[xsde-users] Using Type Mapping?

Boris Kolpackov boris at codesynthesis.com
Thu Sep 11 05:33:50 EDT 2008


Hi Robert,

Robert Hammond <RobertH at microsol.ie> writes:

> Hi, I am trying to work my way through the "people" example to understand
> how the Type maps work properly.
> 
> My assumption after reading the manual is that if I wanted to include my
> own type which was not in the schema file, that I could define it in a
> hxx file, include this and the parser would build the skeleton code for
> that type.
> Have I got this right?

Not exactly. For each type defined in XML Schema the XSD/e compiler
generates a parser skeleton. By default these parser skeletons don't
return anything from their post_*() functions.

You use type maps to tell the XSD/e compiler that a parser skeleton
corresponding to a particular schema type should return something.
Returning things from parser skeletons is useful when you need to
pass information from a "child" element/attribute parser to the
"parent" one. This is handy when, for example, you need to build
a custom in-memory representation of the data stored in XML.

Let's consider the gender type from the people example in the manual.
It is defined in XML Schema like so:

<xsd:simpleType name="gender">
  <xsd:restriction base="xsd:string">
    <xsd:enumeration value="male"/>
    <xsd:enumeration value="female"/>
  </xsd:restriction>
</xsd:simpleType>

If we compile this schema fragment without specifying any type
maps then we get the following parser skeleton:

class gender_pskel: public xml_schema::string_pskel
{
public:
  gender_pskel (xml_schema::string_pskel* base_impl);

  virtual void
  pre ();

  virtual void
  post_gender ();
};

As you can see, the post_gender() function returns void. This may be
perfectly sufficient if, for example, all you need to do is print the
gender value:

class gender_pimpl: public gender_pskel
{
public:
  gender_pimpl ()
    : gender_pskel (&base_impl_)
  {
  }

  virtual void
  post_gender ()
  {
    std::string s = post_string ();
    cout << "gender: " << s << endl;
  }

private:
  xml_schema::string_pimpl base_impl_;
};

But what if you cannot process the gender value in gender_pimpl and
instead needed to pass the gender value to the "parent" parser, the
one generated for the person type:

<xs:complexType name="person">
  <xs:sequence>
    <xs:element name="gender" type="gender"/>

    ...

  </xs:sequence>
</xs:complexType>

class person_pskel: public xml_schema::parser_complex_content
{
public:

  virtual void
  gender ();

  ...
};

One not very clean way would be to have a global variable that is set
in gender_pimpl and is examined in person_pimpl. Since passing data
from "child" parsers to "parent" parsers is a fairly common requirement,
XSD/e provides a mechanism for this. It allows you to specify, via
type maps, the return type of the "child" parser's post_*() function
(post_gender() in our case) and argument type of the "parent" parser's
callback (gender() in our case). The generated code is also responsible
for calling gender_pimpl::post_gender() and passing its return value
to person_pimpl::gender().

In our case we can create a C++ enum corresponding to the gender type
in XML Schema. We can place it, say, in gender.hxx:

enum gender
{
  male,
  female
};

We can then create a type map for our schema, people.map:

include "gender.hxx"
gender ::gender ::gender

In the second line the first identifier is of the schema type. The second
is the return type for gender_pimpl::post_gender() and the last one is the
argument type for the person_pimpl::gender() callback.

Once we compile our schema with this type map, the gender_pskel and
person_pskel skeletons change as follows:

#include "gender.hxx"

class gender_pskel: public xml_schema::string_pskel
{
public:
  gender_pskel (xml_schema::string_pskel* base_impl);

  virtual void
  pre ();

  virtual ::gender
  post_gender ();
};

class person_pskel: public xml_schema::parser_complex_content
{
public:

  virtual void
  gender (::gender);

  ...
};

And our implementation could look like this:

class gender_pimpl: public gender_pskel
{
public:
  gender_pimpl ()
    : gender_pskel (&base_impl_)
  {
  }

  virtual ::gender
  post_gender ()
  {
    std::string s = post_string ();
    return s == "male" : male ? female;
  }

private:
  xml_schema::string_pimpl base_impl_;
};

class person_pimpl: public person_pskel
{
public:

  virtual void
  gender (::gender g)
  {
    // g is the gender value returned by gender_pimpl.
  }
};

Boris



More information about the xsde-users mailing list