Conventional mappings (bindings) of XML Schema to programming languages represent an entire XML instance document as a statically-typed in-memory data structure, analogous to DOM. This representation, however, may not always be suitable. Common reasons for this include:

- Data types for the in-memory representation may already be defined. It is therefore desirable to use these data types instead of the ones provided by the mapping.
- The construction of the in-memory representation may not be necessary or possible. For example, the entire XML instance document could be too large to fit in memory or the processing needs to be carried out as soon as parts of the document become available (streaming).

This document presents a quick introduction to a new kind of XML Schema mapping which provides vocabulary-specific, statically-typed parser templates, analogous to SAX. Using these parser templates you can build your own in-memory representations or perform immediate processing of XML instance documents.

The following step-by-step guide is based on the hello example which can be found in the `examples/cxx/parser/hello` directory of the xsd distribution.

1. Write a Schema definition for instance documents

  Suppose you have the following instance document (`hello.xml`):

      <?xml version="1.0"?>
      <hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="hello.xsd">

        <greeting>Hello</greeting>

        <name>sun</name>
        <name>earth</name>
        <name>world</name>

      </hello>

  Then, the Schema definition for the above instance could look like this (`hello.xsd`):

      <?xml version="1.0"?>
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

        <xsd:complexType name="hello_type">
          <xsd:sequence>
            <xsd:element name="greeting" type="xsd:string"/>
            <xsd:element name="name" type="xsd:string" maxOccurs="unbounded"/>
          </xsd:sequence>
        </xsd:complexType>

        <xsd:element name="hello" type="hello_type"/>

      </xsd:schema>

2. Generate parser templates from your Schema

      $ xsd cxx-parser hello.xsd

  Now we have `hello.hxx` and `hello.txx`. A parser template for the `hello` type looks like this:

      template <typename hello_type_t, typename greeting_t, typename name_t>
      struct hello_type
      {
        virtual void
        pre ();

        virtual void
        greeting (const greeting_t&);

        virtual void
        name (const name_t&);

        virtual hello_type_t
        post ();

        // ...
      };

  The member functions shown above are called parser hooks. You override them in your implementation of the parser. Let's go through all of them one by one.

  The `pre()` function is an initialization hook. It is called when a new element of type `hello` is about to be parsed. You would normally use this function to allocate a new instance of the resulting type or clear accumulators that are used to gather information during parsing. The default implementation of this function does nothing.

  The `post()` function is a finalization hook. It is called when parsing of the element is complete and the result (of type `hello_type_t`) should be returned.

  The `greeting()` and `name()` functions are called when the greeting and name elements have been parsed, respectively. Their argument types are for you to decide and are normally paired with the return types of some of the `post()` functions.

  Let's now see how we can implement our parser.

3. Implement application logic

  At this point we have all the tools we need to do something useful with the information stored in the instance document (`driver.cxx`). The first part is the parser implementation:

      #include "hello.hxx"

      struct hello_parser: hello_type<void,
                                      string, // greeting
                                      string> // name
      {
        virtual void
        greeting (const string& greeting)
        {
          greeting_ = greeting;
        }

        virtual void
        name (const string& name)
        {
          cerr << greeting_ << ", " << name << "!" << endl;
        }

      private:
        string greeting_;
      };

  Here we left both `pre()` and `post()` with the default implementations; we don't have anything to initialize or return (note the `void` type as the first template argument). The rest is pretty straightforward: we store the greeting in a member variable and later, when parsing names, use it to say hello.

  The final piece shows how to put this implementation to work:

      int
      main (int argc, char* argv[])
      {
        // Construct a parser.
        //
        xml_schema::string string_p;
        hello_parser hello_p;

        hello_p.greeting_parser (string_p);
        hello_p.name_parser (string_p);

        // Parse the XML instance document. The second argument to the
        // document's constructor is the document's root element name.
        //
        xml_schema::document<void> doc_p (hello_p, "hello");

        doc_p.parse (argv[1]);
      }

  The first part of this code snippet instantiates individual parsers and assembles them into a complete parser that is capable of handling conforming XML instance documents. `xml_schema::string` is an implementation (provided by the xsd runtime) of a parser for built-in XML Schema type `string`. We use it to parse the name and greeting elements.

  Then we instantiate a document parser (`doc_p`). The first argument to its constructor is the parser for the root element (`hello_p` in our case). The second argument is the root element name. The template parameter of the `xml_schema::document` class template is the return type of the root element parser (`void` in our case).

  The final piece is the call to the `parse()` function which will parse the instance document.

4. Compile and run

      $ g++ -o driver driver.cxx -lxerces-c
      $ ./driver hello.xml
      Hello, sun!
      Hello, moon!
      Hello, world!

5. Learn more

  The library example, which can be found in the `examples/cxx/parser/library` directory of the xsd distribution, shows how to

  - handle more complicated data structures
  - create custom in-memory representations
  - map XML Schema namespace names to C++ names

  The mix-in example, which can be found in the `examples/cxx/parser/mix-in` directory of the xsd distribution, shows how to re-use implementations of base parsers in derived parsers using the mix-in C++ idiom.

  The mixed example, which can be found in the `examples/cxx/parser/mixed` directory of the xsd distribution, shows how to handle "type-less content" such as mixed content models, `xsd:anyType`, `xsd:anySimpleType`, `xsd:any`, and `xsd:anyAttribute`.