aboutsummaryrefslogtreecommitdiff
path: root/documentation/cxx/hybrid/guide/index.xhtml
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/cxx/hybrid/guide/index.xhtml')
-rw-r--r--documentation/cxx/hybrid/guide/index.xhtml5099
1 files changed, 5099 insertions, 0 deletions
diff --git a/documentation/cxx/hybrid/guide/index.xhtml b/documentation/cxx/hybrid/guide/index.xhtml
new file mode 100644
index 0000000..b555009
--- /dev/null
+++ b/documentation/cxx/hybrid/guide/index.xhtml
@@ -0,0 +1,5099 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+
+<head>
+ <title>Embedded C++/Hybrid Mapping Getting Started Guide</title>
+
+ <meta name="copyright" content="&copy; 2005-2009 Code Synthesis Tools CC"/>
+ <meta name="keywords" content="xsd,xml,schema,c++,mapping,data,binding,parse,serialize,create,modify,write,validation,embedded,mobile"/>
+ <meta name="description" content="Embedded C++/Hybrid Mapping Getting Started Guide"/>
+
+ <link rel="stylesheet" type="text/css" href="../../../default.css" />
+
+<style type="text/css">
+ pre {
+ padding : 0 0 0 0em;
+ margin : 0em 0em 0em 0;
+
+ font-size : 102%
+ }
+
+ body {
+ min-width: 48em;
+ }
+
+ h1 {
+ font-weight: bold;
+ font-size: 200%;
+ line-height: 1.2em;
+ }
+
+ h2 {
+ font-weight : bold;
+ font-size : 150%;
+
+ padding-top : 0.8em;
+ }
+
+ h3 {
+ font-size : 140%;
+ padding-top : 0.8em;
+ }
+
+ /* Adjust indentation for three levels. */
+ #container {
+ max-width: 48em;
+ }
+
+ #content {
+ padding: 0 0.1em 0 4em;
+ /*background-color: red;*/
+ }
+
+ #content h1 {
+ margin-left: -2.06em;
+ }
+
+ #content h2 {
+ margin-left: -1.33em;
+ }
+
+ /* Title page */
+
+ #titlepage {
+ padding: 2em 0 1em 0;
+ border-bottom: 1px solid black;
+ }
+
+ #titlepage .title {
+ font-weight: bold;
+ font-size: 200%;
+ text-align: center;
+ }
+
+ #titlepage #first-title {
+ padding: 1em 0 0.4em 0;
+ }
+
+ #titlepage #second-title {
+ padding: 0.4em 0 2em 0;
+ }
+
+ /* Lists */
+ ul.list li, ol.list li {
+ padding-top : 0.3em;
+ padding-bottom : 0.3em;
+ }
+
+ div.img {
+ text-align: center;
+ padding: 2em 0 2em 0;
+ }
+
+ /* */
+ dl dt {
+ padding : 0.8em 0 0 0;
+ }
+
+ /* TOC */
+ table.toc {
+ border-style : none;
+ border-collapse : separate;
+ border-spacing : 0;
+
+ margin : 0.2em 0 0.2em 0;
+ padding : 0 0 0 0;
+ }
+
+ table.toc tr {
+ padding : 0 0 0 0;
+ margin : 0 0 0 0;
+ }
+
+ table.toc * td, table.toc * th {
+ border-style : none;
+ margin : 0 0 0 0;
+ vertical-align : top;
+ }
+
+ table.toc * th {
+ font-weight : normal;
+ padding : 0em 0.1em 0em 0;
+ text-align : left;
+ white-space : nowrap;
+ }
+
+ table.toc * table.toc th {
+ padding-left : 1em;
+ }
+
+ table.toc * td {
+ padding : 0em 0 0em 0.7em;
+ text-align : left;
+ }
+
+ /* Built-in table */
+ #builtin {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+ }
+
+ #builtin th, #builtin td {
+ border: 1px solid;
+ padding : 0.9em 0.9em 0.7em 0.9em;
+ }
+
+ #builtin th {
+ background : #cde8f6;
+ }
+
+ #builtin td {
+ text-align: left;
+ }
+
+ /* XML Schema features table. */
+ #features {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+ }
+
+ #features th, #features td {
+ border: 1px solid;
+ padding : 0.6em 0.6em 0.6em 0.6em;
+ }
+
+ #features th {
+ background : #cde8f6;
+ }
+
+ #features td {
+ text-align: left;
+ }
+</style>
+
+
+</head>
+
+<body>
+<div id="container">
+ <div id="content">
+
+ <div class="noprint">
+
+ <div id="titlepage">
+ <div class="title" id="first-title">Embedded C++/Hybrid Mapping</div>
+ <div class="title" id="second-title">Getting Started Guide</div>
+
+ <p>Copyright &copy; 2005-2009 CODE SYNTHESIS TOOLS CC</p>
+
+ <p>Permission is granted to copy, distribute and/or modify this
+ document under the terms of the
+ <a href="http://www.codesynthesis.com/licenses/fdl-1.2.txt">GNU Free
+ Documentation License, version 1.2</a>; with no Invariant Sections,
+ no Front-Cover Texts and no Back-Cover Texts.
+ </p>
+
+ <p>This document is available in the following formats:
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/index.xhtml">XHTML</a>,
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/cxx-hybrid-e-guide.pdf">PDF</a>, and
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/cxx-hybrid-e-guide.ps">PostScript</a>.</p>
+
+ </div>
+
+ <h1>Table of Contents</h1>
+
+ <table class="toc">
+ <tr>
+ <th></th><td><a href="#0">Preface</a>
+ <table class="toc">
+ <tr><th></th><td><a href="#0.1">About This Document</a></td></tr>
+ <tr><th></th><td><a href="#0.2">More Information</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>1</th><td><a href="#1">Introduction</a>
+ <table class="toc">
+ <tr><th>1.1</th><td><a href="#1.1">Mapping Overview</a></td></tr>
+ <tr><th>1.2</th><td><a href="#1.2">Benefits</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>2</th><td><a href="#2">Hello World Example</a>
+ <table class="toc">
+ <tr><th>2.1</th><td><a href="#2.1">Writing XML Document and Schema</a></td></tr>
+ <tr><th>2.2</th><td><a href="#2.2">Translating Schema to C++</a></td></tr>
+ <tr><th>2.3</th><td><a href="#2.3">Implementing Application Logic</a></td></tr>
+ <tr><th>2.4</th><td><a href="#2.4">Compiling and Running</a></td></tr>
+ <tr><th>2.5</th><td><a href="#2.5">Adding Serialization</a></td></tr>
+ <tr><th>2.6</th><td><a href="#2.6">A Minimal Version</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>3</th><td><a href="#3">Mapping Configuration</a>
+ <table class="toc">
+ <tr><th>3.1</th><td><a href="#3.1">Standard Template Library</a></td></tr>
+ <tr><th>3.2</th><td><a href="#3.2">Input/Output Stream Library</a></td></tr>
+ <tr><th>3.3</th><td><a href="#3.3">C++ Exceptions</a></td></tr>
+ <tr><th>3.4</th><td><a href="#3.4">XML Schema Validation</a></td></tr>
+ <tr><th>3.5</th><td><a href="#3.5">64-bit Integer Type</a></td></tr>
+ <tr><th>3.6</th><td><a href="#3.6">Parser and Serializer Reuse</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>4</th><td><a href="#4">Working with Object Models</a>
+ <table class="toc">
+ <tr><th>4.1</th><td><a href="#4.1">Namespaces</a></td></tr>
+ <tr><th>4.2</th><td><a href="#4.2">Memory Management</a></td></tr>
+ <tr><th>4.3</th><td><a href="#4.3">Attributes and Elements</a></td></tr>
+ <tr><th>4.4</th><td><a href="#4.4">Compositors</a></td></tr>
+ <tr><th>4.5</th><td><a href="#4.5">Accessing the Object Model</a></td></tr>
+ <tr><th>4.6</th><td><a href="#4.6">Modifying the Object Model</a></td></tr>
+ <tr><th>4.7</th><td><a href="#4.7">Creating the Object Model from Scratch</a></td></tr>
+ <tr><th>4.8</th><td><a href="#4.8">Customizing the Object Model</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>5</th><td><a href="#5">Mapping for Built-In XML Schema Types</a>
+ <table class="toc">
+ <tr><th>5.1</th><td><a href="#5.1">Mapping for <code>QName</code></a></td></tr>
+ <tr><th>5.2</th><td><a href="#5.2">Mapping for <code>NMTOKENS</code> and <code>IDREFS</code>s</a></td></tr>
+ <tr><th>5.3</th><td><a href="#5.3">Mapping for <code>base54Binary</code> and <code>hexBinary</code>s</a></td></tr>
+ <tr><th>5.4</th><td><a href="#5.4">Time Zone Representation</a></td></tr>
+ <tr><th>5.5</th><td><a href="#5.5">Mapping for <code>date</code></a></td></tr>
+ <tr><th>5.6</th><td><a href="#5.6">Mapping for <code>dateTime</code></a></td></tr>
+ <tr><th>5.7</th><td><a href="#5.7">Mapping for <code>duration</code></a></td></tr>
+ <tr><th>5.8</th><td><a href="#5.8">Mapping for <code>gDay</code></a></td></tr>
+ <tr><th>5.9</th><td><a href="#5.9">Mapping for <code>gMonth</code></a></td></tr>
+ <tr><th>5.10</th><td><a href="#5.10">Mapping for <code>gMonthDay</code></a></td></tr>
+ <tr><th>5.11</th><td><a href="#5.11">Mapping for <code>gYear</code></a></td></tr>
+ <tr><th>5.12</th><td><a href="#5.12">Mapping for <code>gYearMonth</code></a></td></tr>
+ <tr><th>5.13</th><td><a href="#5.13">Mapping for <code>time</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>6</th><td><a href="#6">Parsing and Serialization</a>
+ <table class="toc">
+ <tr><th>6.1</th><td><a href="#6.1">Customizing Parsers and Serializers</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ </table>
+ </div>
+
+ <h1><a name="0">Preface</a></h1>
+
+ <h2><a name="0.1">About This Document</a></h2>
+
+ <p>The goal of this document is to provide you with an
+ understanding of the C++/Hybrid programming model and allow you
+ to efficiently evaluate XSD/e against your project's technical
+ requirements. As such, this document is intended for embedded
+ C++ developers and software architects who are looking for an
+ embedded XML processing solution. Prior experience with XML
+ and C++ is required to understand this document. Basic
+ understanding of XML Schema is advantageous but not expected
+ or required.
+ </p>
+
+
+ <h2><a name="0.2">More Information</a></h2>
+
+ <p>Beyond this guide, you may also find the following sources of
+ information useful:</p>
+
+ <ul class="list">
+ <li><a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e
+ Compiler Command Line Manual</a></li>
+
+ <li><a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml">Embedded
+ C++/Parser Mapping Getting Started Guide</a>. The C++/Hybrid
+ mapping uses C++/Parser for XML parsing.</li>
+
+ <li><a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml">Embedded
+ C++/Serializer Mapping Getting Started Guide</a>. The C++/Hybrid
+ mapping uses C++/Serializer for XML serialization.</li>
+
+ <li>The <code>INSTALL</code> file in the XSD/e distribution provides
+ build instructions for various platforms.</li>
+
+ <li>The <code>examples/cxx/hybrid/</code> directory in the XSD/e
+ distribution contains a collection of examples and a README
+ file with an overview of each example.</li>
+
+ <li>The <a href="http://www.codesynthesis.com/mailman/listinfo/xsde-users">xsde-users</a>
+ mailing list is the place to ask technical questions about XSD/e and the
+ Embedded C++/Hybrid mapping. Furthermore, the
+ <a href="http://www.codesynthesis.com/pipermail/xsde-users/">archives</a>
+ may already have answers to some of your questions.</li>
+
+ </ul>
+
+ <!-- Introduction -->
+
+ <h1><a name="1">1 Introduction</a></h1>
+
+ <p>Welcome to CodeSynthesis XSD/e and the Embedded C++/Hybrid mapping.
+ XSD/e is a validating XML parser/serializer and data binding generator
+ for mobile and embedded systems. Embedded C++/Hybrid is a W3C XML
+ Schema to C++ mapping that represents the data stored in XML as a
+ light-weight, statically-typed, in-memory object model.
+ </p>
+
+ <h2><a name="1.1">1.1 Mapping Overview</a></h2>
+
+ <p>Based on a formal description of an XML vocabulary (schema), the
+ C++/Hybrid mapping produces a tree-like data structure suitable
+ for in-memory processing. The core of the mapping consists of C++
+ classes that constitute the object model and are derived from
+ types defined in XML Schema. The C++/Hybrid mapping uses the
+ APIs provided by the
+ <a href="http://www.codesynthesis.com/products/xsde/c++/parser/">Embedded
+ C++/Parser</a> and
+ <a href="http://www.codesynthesis.com/products/xsde/c++/serializer/">Embedded
+ C++/Serializer</a>
+ mappings to perform validation and parsing of XML to the object
+ model and validation and serialization of the object model to
+ XML. The following diagram illustrates the high-level architecture
+ of the C++/Hybrid mapping:</p>
+
+ <!-- align=center is needed for html2ps -->
+ <div class="img" align="center"><img src="figure-1.png"/></div>
+
+ <p>The use of well-defined APIs presented by the C++/Parser and
+ C++/Serializer mappings for XML parsing and serialization
+ allows a number of advanced techniques, for example, customization
+ of parsing and serialization code, filtering of XML during
+ parsing or object model during serialization, as well as the hybrid,
+ partially event-driven, partially in-memory processing
+ where the XML document is delivered to the application as
+ parts of the object model. The last feature combines the
+ ease and convenience of the in-memory processing model
+ with the ability to minimize the use of RAM and process documents
+ that would otherwise not fit into memory.
+ </p>
+
+ <p>The Embedded C++/Hybrid mapping was specifically designed and
+ optimized for mobile and embedded systems where hardware
+ constraints require high efficiency and economical use of
+ resources. As a result, the generated parsing and serialization
+ code is 2-10 times faster than general-purpose XML processors
+ while at the same time maintaining extremely low static and
+ dynamic memory footprints. For example, an executable that
+ performs validating XML parsing and serialization can be as small
+ as 150KB in size. The size can be further reduced by disabling
+ support for parsing or serialization as well as XML Schema
+ validation.
+ </p>
+
+ <p>The generated code and the runtime library are also highly-portable
+ and, in their minimal configuration, can be used without STL, RTTI,
+ iostream, C++ exceptions, and with the minimal use of C++ templates.</p>
+
+ <p>A typical application that uses the C++/Hybrid mapping for XML
+ processing performs the following three steps: it first
+ reads (parses) an XML document to an in-memory object model, it
+ then performs some useful computations on that object model which
+ may involve modification of the model, and finally it may write
+ (serialize) the modified object model back to XML. The next chapter
+ presents a simple application that performs these three steps. The
+ following chapters describe the Embedded C++/Hybrid mapping in more
+ detail.</p>
+
+ <h2><a name="1.2">1.2 Benefits</a></h2>
+
+ <p>Traditional XML access APIs such as Document Object Model (DOM)
+ or Simple API for XML (SAX) as well as general-purpose XML Schema
+ validators have a number of drawbacks that make them less suitable
+ for creating mobile and embedded XML processing applications. These
+ drawbacks include:
+ </p>
+
+ <ul class="list">
+ <li>Generic representation of XML in terms of elements, attributes,
+ and text forces an application developer to write a substantial
+ amount of bridging code that identifies and transforms pieces
+ of information encoded in XML to a representation more suitable
+ for consumption by the application logic.</li>
+
+ <li>String-based flow control defers error detection to runtime.
+ It also reduces code readability and maintainability.</li>
+
+ <li>Lack of type safety and inefficient use of resources due to
+ the data being represented as text.</li>
+
+ <li>Extra validation code that is not used by the application.</li>
+
+ <li>Resulting applications are hard to debug, change, and
+ maintain.</li>
+ </ul>
+
+ <p>In contrast, a light-weight, statically-typed, vocabulary-specific
+ object model produced by the Embedded C++/Hybrid mapping allows
+ you to operate in your domain terms instead of the generic elements,
+ attributes, and text. Native data types are used to store the XML
+ data (for example, integers are stored as integers, not as text).
+ Validation code is included only for XML Schema constructs that
+ are used in the application. This results in efficient use of
+ resources and compact object code.</p>
+
+ <p>Furthermore, static typing helps catch errors at
+ compile-time rather than at run-time. Automatic code generation
+ frees you for more interesting tasks (such as doing something
+ useful with the information stored in the XML documents) and
+ minimizes the effort needed to adapt your applications to changes
+ in the document structure. To summarize, the C++/Hybrid object
+ model has the following key advantages over generic XML access
+ APIs:</p>
+
+ <ul class="list">
+ <li><b>Ease of use.</b> The generated code hides all the complexity
+ associated with parsing and serializing XML. This includes navigating
+ the structure and converting between the text representation and
+ data types suitable for manipulation by the application logic.</li>
+
+ <li><b>Natural representation.</b> The object representation allows
+ you to access the XML data using your domain vocabulary instead
+ of generic elements, attributes, and text.</li>
+
+ <li><b>Concise code.</b> With the object representation the
+ application implementation is simpler and thus easier
+ to read and understand.</li>
+
+ <li><b>Safety.</b> The generated object model is statically
+ typed and uses functions instead of strings to access the
+ information. This helps catch programming errors at compile-time
+ rather than at runtime.</li>
+
+ <li><b>Maintainability.</b> Automatic code generation minimizes the
+ effort needed to adapt the application to changes in the
+ document structure. With static typing, the C++ compiler
+ can pin-point the places in the client code that need to be
+ changed.</li>
+
+ <li><b>Efficiency.</b> If the application makes repetitive use
+ of the data extracted from XML, then the C++/Hybrid object model
+ is more efficient because the navigation is performed using
+ function calls rather than string comparisons and the XML
+ data is extracted only once. The runtime memory
+ usage is also reduced due to more efficient data storage
+ (for instance, storing numeric data as integers instead of
+ strings) as well as the static knowledge of cardinality
+ constraints.
+
+ <p>Furthermore, the generated XML parsing and serialization code
+ combines validation and data-to-text conversion in a single step.
+ This makes the generated code much more efficient than traditional
+ architectures with separate stages for validation and data
+ conversion.</p>
+ </li>
+ </ul>
+
+ <!-- Hello World Example -->
+
+
+ <h1><a name="2">2 Hello World Example</a></h1>
+
+ <p>In this chapter we will examine how to parse, access, modify, and
+ serialize a very simple XML document using the generated
+ C++/Hybrid object model as well as the XML parser and serializer. The
+ code presented in this chapter is based on the <code>hello</code>
+ example which can be found in the <code>examples/cxx/hybrid/</code>
+ directory of the XSD/e distribution.</p>
+
+ <h2><a name="2.1">2.1 Writing XML Document and Schema</a></h2>
+
+ <p>First, we need to get an idea about the structure
+ of the XML documents we are going to process. Our
+ <code>hello.xml</code>, for example, could look like this:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0"?>
+&lt;hello>
+
+ &lt;greeting>Hello&lt;/greeting>
+
+ &lt;name>sun&lt;/name>
+ &lt;name>earth&lt;/name>
+ &lt;name>world&lt;/name>
+
+&lt;/hello>
+ </pre>
+
+ <p>Then we can write a description of the above XML in the
+ XML Schema language and save it into <code>hello.xsd</code>:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0"?>
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="hello">
+ &lt;xs:sequence>
+ &lt;xs:element name="greeting" type="xs:string"/>
+ &lt;xs:element name="name" type="xs:string" maxOccurs="unbounded"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="hello" type="hello"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>Even if you are not familiar with XML Schema, it
+ should be easy to connect declarations in <code>hello.xsd</code>
+ to elements in <code>hello.xml</code>. The <code>hello</code> type
+ is defined as a sequence of the nested <code>greeting</code> and
+ <code>name</code> elements. Note that the term sequence in XML
+ Schema means that elements should appear in a particular order
+ as opposed to appearing multiple times. The <code>name</code>
+ element has its <code>maxOccurs</code> property set to
+ <code>unbounded</code> which means it can appear multiple times
+ in an XML document. Finally, the globally-defined <code>hello</code>
+ element prescribes the root element for our vocabulary. For an
+ easily-approachable introduction to XML Schema refer to
+ <a href="http://www.w3.org/TR/xmlschema-0/">XML Schema Part 0:
+ Primer</a>.</p>
+
+ <p>The above schema is a specification of our XML vocabulary; it tells
+ everybody what valid documents of our XML-based language should look
+ like. The next step is to compile the schema to generate the object
+ model and the parser.</p>
+
+
+ <h2><a name="2.2">2.2 Translating Schema to C++</a></h2>
+
+ <p>Now we are ready to translate our <code>hello.xsd</code> to C++.
+ To do this we invoke the XSD/e compiler from a terminal (UNIX) or
+ a command prompt (Windows):
+ </p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-aggregate hello.xsd
+ </pre>
+
+ <p>This invocation of the XSD/e compiler produces three pairs of C++ files:
+ <code>hello.hxx</code> and <code>hello.cxx</code>,
+ <code>hello-pskel.hxx</code> and <code>hello-pskel.cxx</code>, as well as
+ <code>hello-pimpl.hxx</code> and <code>hello-pimpl.cxx</code>. The
+ first pair contains the object model classes. The second pair contains
+ parser skeletons. Parser skeletons are generated by the C++/Parser
+ mapping which is automatically invoked by C++/Hybrid.
+ For now we can ignore parser skeletons except that we need to compile
+ them and link the result to our application. The last pair of files
+ contains parser implementations. They implement the parser skeletons
+ to create and populate the object model types from XML data. The generation
+ of parser skeletons and parser implementations is requested with the
+ <code>--generate-parser</code> XSD/e compiler option.</p>
+
+ <p>You may be wondering what is the <code>--generate-aggregate</code>
+ option for. This option instructs the XSD/e compiler to generate
+ parser and, as we will see later, serializer aggregates. The
+ generated parser implementation files mentioned above contain
+ a separate parser implementation class for each type defined
+ in XML Schema. These parser implementations need to be
+ instantiated and connected before we can use them to parse an XML document.
+ When you specify the <code>--generate-aggregate</code> option,
+ the XSD/e compiler generates a class (in the parser implementation
+ files), called parser aggregate, for each global element defined
+ in the schema (you can also generate a parser aggregate for a type
+ as well as control for which global elements parser aggregates
+ are generated, see the
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e
+ Compiler Command Line Manual</a> for more information). A parser
+ aggregate instantiates and connects all the necessary parser
+ implementations needed to parse an XML document with a given root
+ element. We will see how to use the parser aggregate for the
+ <code>hello</code> root element in the next section.</p>
+
+ <p>The following code fragment is taken from <code>hello.hxx</code>; it
+ shows what the C++ object model for our "Hello World" XML vocabulary
+ looks like:
+ </p>
+
+ <pre class="c++">
+class hello
+{
+public:
+ hello ();
+
+ // greeting
+ //
+ const std::string&amp;
+ greeting () const;
+
+ std::string&amp;
+ greeting ();
+
+ void
+ greeting (const std::string&amp;);
+
+ // name
+ //
+ typedef xsde::string_sequence name_sequence;
+ typedef name_sequence::iterator name_iterator;
+ typedef name_sequence::const_iterator name_const_iterator;
+
+ const name_sequence&amp;
+ name () const;
+
+ name_sequence&amp;
+ name ();
+
+private:
+ ...
+};
+ </pre>
+
+ <p>The <code>hello</code> C++ class corresponds to the
+ <code>hello</code> XML Schema type. For each element
+ in this type a set of accessor and modifier functions
+ are generated inside the <code>hello</code> class. Note
+ that the member functions for the <code>greeting</code> and
+ <code>name</code> elements are different because of the
+ different cardinalities these two elements have
+ (<code>greeting</code> is a required single element and
+ <code>name</code> is a sequence of elements).</p>
+
+ <p>It is also evident that the built-in XML Schema type
+ <code>string</code> is mapped to <code>std::string</code>.
+ The internal <code>string_sequence</code> class that
+ is used in the <code>name_sequence</code> type definition
+ has an interface similar to <code>std::vector</code>. The
+ mapping between the built-in XML Schema types and C++ types
+ is described in more detail in <a href="#5">Chapter 5,
+ "Mapping for Built-in XML Schema Types"</a>.</p>
+
+
+ <h2><a name="2.3">2.3 Implementing Application Logic</a></h2>
+
+ <p>At this point we have all the parts we need to do something useful
+ with the information stored in our XML document:
+ </p>
+
+ <pre class="c++">
+#include &lt;iostream>
+
+#include "hello.hxx"
+#include "hello-pimpl.hxx"
+
+using namespace std;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ // Parse.
+ //
+ hello_paggr hello_p;
+ xml_schema::document_pimpl doc_p (hello_p.root_parser (),
+ hello_p.root_name ());
+ hello_p.pre ();
+ doc_p.parse (argv[1]);
+ hello* h = hello_p.post ();
+
+ // Print what we've got.
+ //
+ for (hello::name_const_iterator i = h->name ().begin ();
+ i != h->name ().end ();
+ ++i)
+ {
+ cout &lt;&lt; h->greeting () &lt;&lt; ", " &lt;&lt; *i &lt;&lt; "!" &lt;&lt; endl;
+ }
+
+ delete h;
+ }
+ catch (const xml_schema::parser_exception&amp; e)
+ {
+ cerr &lt;&lt; argv[1] &lt;&lt; ":" &lt;&lt; e.line () &lt;&lt; ":" &lt;&lt; e.column ()
+ &lt;&lt; ": " &lt;&lt; e.text () &lt;&lt; endl;
+ return 1;
+ }
+}
+ </pre>
+
+ <p>The first part of our application creates a document parser
+ and parses the XML file specified in the command line to the
+ object model. The <code>hello_paggr</code> class is the parser
+ aggregate class we discussed earlier. Parsing is covered in more
+ detail in <a href="#6">Chapter 6, "Parsing and Serialization"</a>.
+ The second part uses the returned object model to iterate over
+ names and print a greeting line for each of them. We also catch
+ and print the <code>xml_schema::parser_exception</code> exception
+ in case something goes wrong.
+ </p>
+
+ <h2><a name="2.4">2.4 Compiling and Running</a></h2>
+
+ <p>After saving our application from the previous section in
+ <code>driver.cxx</code>, we are ready to compile our first
+ program and run it on the test XML document. On UNIX
+ this can be done with the following commands:
+ </p>
+
+ <pre class="terminal">
+$ c++ -I.../libxsde -c driver.cxx hello-pskel.cxx hello-pimpl.cxx
+$ c++ -o driver driver.o hello-pskel.o hello-pimpl.o \
+ .../libxsde/xsde/libxsde.a
+$ ./driver hello.xml
+Hello, sun!
+Hello, moon!
+Hello, world!
+ </pre>
+
+ <p>Here <code>.../libxsde</code> represents the path to the
+ <code>libxsde</code> directory in the XSD/e distribution.</p>
+
+ <p>We can also test the error handling. To test XML well-formedness
+ checking, we can try to parse <code>hello.hxx</code>:</p>
+
+ <pre class="terminal">
+$ ./driver hello.hxx
+hello.hxx:1:0: not well-formed (invalid token)
+ </pre>
+
+ <p>We can also try to parse a valid XML but not from our
+ vocabulary, for example <code>hello.xsd</code>:</p>
+
+ <pre class="terminal">
+$ ./driver hello.xsd
+hello.xsd:2:57: unexpected element encountered
+ </pre>
+
+ <h2><a name="2.5">2.5 Adding Serialization</a></h2>
+
+ <p>While parsing and accessing the XML data may be everything
+ you need, there are applications that require creating new
+ or modifying existing XML documents. To request the generation
+ of serialization support we will need to add the
+ <code>--generate-serializer</code> option to our XSD/e
+ compiler invocation:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+ --generate-aggregate hello.xsd
+ </pre>
+
+ <p>This will result in two additional pairs of C++ files:
+ <code>hello-sskel.hxx</code> and <code>hello-sskel.cxx</code>, as well as
+ <code>hello-simpl.hxx</code> and <code>hello-simpl.cxx</code>.
+ Similar to the parser files, the first pair contains serializer
+ skeletons (generated by the C++/Serializer mapping) and the second
+ pair contains serializer implementations as well as the serializer
+ aggregate for the <code>hello</code> root element.</p>
+
+ <p>Let us first examine an application that modifies an existing
+ object model and serializes it back to XML:</p>
+
+ <pre class="c++">
+#include &lt;iostream>
+
+#include "hello.hxx"
+#include "hello-pimpl.hxx"
+#include "hello-simpl.hxx"
+
+using namespace std;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ // Parse.
+ //
+ hello_paggr hello_p;
+ xml_schema::document_pimpl doc_p (hello_p.root_parser (),
+ hello_p.root_name ());
+ hello_p.pre ();
+ doc_p.parse (argv[1]);
+ hello* h = hello_p.post ();
+
+ // Change the greeting phrase.
+ //
+ h->greeting ("Hi");
+
+ // Add another entry to the name sequence.
+ //
+ h->name ().push_back ("mars");
+
+ // Serialize the modified object model to XML.
+ //
+ hello_saggr hello_s;
+ xml_schema::document_simpl doc_s (hello_s.root_serializer (),
+ hello_s.root_name ());
+ hello_s.pre (*h);
+ doc_s.serialize (cout);
+ hello_s.post ();
+
+ delete h;
+ }
+ catch (const xml_schema::parser_exception&amp; e)
+ {
+ cerr &lt;&lt; argv[1] &lt;&lt; ":" &lt;&lt; e.line () &lt;&lt; ":" &lt;&lt; e.column ()
+ &lt;&lt; ": " &lt;&lt; e.text () &lt;&lt; endl;
+ return 1;
+ }
+ catch (const xml_schema::serializer_exception&amp; e)
+ {
+ cerr &lt;&lt; "error: " &lt;&lt; e.text () &lt;&lt; endl;
+ return 1;
+ }
+}
+ </pre>
+
+ <p>First, our application parses an XML document and obtains its
+ object model as in the previous example. Then it changes the
+ greeting string and adds another entry to the list of names.
+ Finally, it creates a document serializer and serializes the
+ object model back to XML. The resulting XML is written to
+ the standard output (<code>cout</code>) for us to inspect.
+ We could have also written the result to a file or memory
+ buffer by creating an instance of <code>std::ofstream</code>
+ or <code>std::ostringstream</code> and passing it to
+ <code>serialize()</code> instead of <code>cout</code>.
+ The <code>hello_saggr</code> class is the serializer aggregate
+ class we discussed earlier. Serialization is covered in more
+ detail in <a href="#6">Chapter 6, "Parsing and Serialization"</a>.</p>
+
+ <p>If we now compile and run this application (don't forget to
+ compile and link <code>hello-sskel.cxx</code> and
+ <code>hello-simpl.cxx</code>), we will see the
+ output as shown in the following listing:</p>
+
+ <pre class="xml">
+&lt;hello>
+ &lt;greeting>Hi&lt;/greeting>
+ &lt;name>sun&lt;/name>
+ &lt;name>earth&lt;/name>
+ &lt;name>world&lt;/name>
+ &lt;name>mars&lt;/name>
+&lt;/hello>
+ </pre>
+
+ <p>
+ We can also test XML Schema validation. We can "accidently"
+ remove all the names from the object model by adding the following
+ after: <code>push_back ("mars")</code>:</p>
+
+ <pre class="c++">
+h->name ().clear ();
+ </pre>
+
+ <p>This will violate our vocabulary specification which requires
+ at least one <code>name</code> element to be present. If we
+ make the above change and recompile our application, we will
+ get the following output:</p>
+
+ <pre class="terminal">
+$ ./driver hello.xml
+error: expected element not encountered
+ </pre>
+
+ <p>It is also possible to create and serialize an object model from
+ scratch as shown in the following example. For this case we
+ can remove the <code>--generate-parser</code> option since
+ we don't need support for XML parsing.</p>
+
+ <pre class="c++">
+#include &lt;sstream>
+#include &lt;iostream>
+
+#include "hello.hxx"
+#include "hello-simpl.hxx"
+
+using namespace std;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ hello h;
+ h.greeting ("Hi");
+
+ hello::name_sequence&amp; ns = h.name ();
+ ns.push_back ("Jane");
+ ns.push_back ("John");
+
+ // Serialize the object model to XML.
+ //
+ hello_saggr hello_s;
+ xml_schema::document_simpl doc_s (hello_s.root_serializer (),
+ hello_s.root_name ());
+ ostringstream ostr;
+
+ hello_s.pre (*h);
+ doc_s.serialize (ostr);
+ hello_s.post ();
+
+ delete h;
+
+ cout &lt;&lt; ostr.c_str () &lt;&lt; endl;
+ }
+ catch (const xml_schema::serializer_exception&amp; e)
+ {
+ cerr &lt;&lt; "error: " &lt;&lt; e.text () &lt;&lt; endl;
+ return 1;
+ }
+}
+ </pre>
+
+ <p>In this example we used the generated default constructor to
+ create an empty instance of type <code>hello</code>. We then
+ set greeting and, to reduce typing, we obtained a reference to
+ the name sequence which we used to add a few names. The
+ serialization part is identical to the previous example except
+ this time we first save the XML representation into a string.
+ If we compile and run this program, it produces the following
+ output:</p>
+
+ <pre class="xml">
+&lt;hello>
+ &lt;greeting>Hi&lt;/greeting>
+ &lt;name>Jane&lt;/name>
+ &lt;name>John&lt;/name>
+&lt;/hello>
+ </pre>
+
+ <h2><a name="2.6">2.6 A Minimal Version</a></h2>
+
+ <p>The previous sections showed a number of examples that relied
+ on STL for strings, iostream of input/output and C++ exceptions
+ for error handling.
+ As was mentioned in the introduction and will be discussed
+ in further detail in the next chapter, the C++/Hybrid mapping
+ can be configured only to rely on the minimal subset of C++.
+ In this section we will implement an example that parses,
+ prints, modifies and serializes the object model without
+ relying on STL, iostream, or C++ exceptions.</p>
+
+ <p>The first step is to instruct the XSD/e compiler not to use
+ any of the above features in the generated code. You may also
+ need to re-configure and rebuild the XSD/e runtime library
+ (<code>libxsde.a</code>) to disable STL, iostream, and
+ exceptions.</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --no-stl --no-iostream --no-exceptions \
+ --generate-parser --generate-serializer --generate-aggregate \
+ hello.xsd
+ </pre>
+
+ <p>If you now study the generated <code>hello.hxx</code> file,
+ you will notice that the use of <code>std::string</code> type
+ is replaced with <code>char*</code>. When STL is disabled,
+ built-in XML Schema type <code>string</code> is mapped to a
+ C string. The following listing presents the content of
+ <code>driver.cxx</code> in full:</p>
+
+ <pre class="c++">
+#include &lt;stdio.h>
+
+#include "people.hxx"
+
+#include "people-pimpl.hxx"
+#include "people-simpl.hxx"
+
+using namespace std;
+
+struct writer: xml_schema::writer
+{
+ virtual bool
+ write (const char* s, size_t n)
+ {
+ return fwrite (s, n, 1, stdout) == 1;
+ }
+
+ virtual bool
+ flush ()
+ {
+ return fflush (stdout) == 0;
+ }
+};
+
+int
+main (int argc, char* argv[])
+{
+ // Open the file or use STDIN.
+ //
+ FILE* f = fopen (argv[1], "rb");
+
+ if (f == 0)
+ {
+ fprintf (stderr, "%s: unable to open\n", argc);
+ return 1;
+ }
+
+ // Parse.
+ //
+ using xml_schema::parser_error;
+
+ parser_error pe;
+ bool io_error = false;
+ hello* h = 0;
+
+ do
+ {
+ hello_paggr hello_p;
+ xml_schema::document_pimpl doc_p (hello_p.root_parser (),
+ hello_p.root_name ());
+ if (pe = doc_p._error ())
+ break;
+
+ hello_p.pre ();
+
+ if (pe = hello_p._error ())
+ break;
+
+ char buf[4096];
+
+ do
+ {
+ size_t s = fread (buf, 1, sizeof (buf), f);
+
+ if (s != sizeof (buf) &amp;&amp; ferror (f))
+ {
+ io_error = true;
+ break;
+ }
+
+ doc_p.parse (buf, s, feof (f) != 0);
+ pe = doc_p._error ();
+
+ } while (!pe &amp;&amp; !feof (f));
+
+ if (io_error || pe)
+ break;
+
+ h = hello_p.post ();
+ pe = hello_p._error ();
+
+ } while (false);
+
+ fclose (f);
+
+ // Handle parsing errors.
+ //
+ if (io_error)
+ {
+ fprintf (stderr, "%s: read failure\n", argc);
+ return 1;
+ }
+
+ if (pe)
+ {
+ switch (pe.type ())
+ {
+ case parser_error::sys:
+ {
+ fprintf (stderr, "%s: %s\n", argc, pe.sys_text ());
+ break;
+ }
+ case parser_error::xml:
+ {
+ fprintf (stderr, "%s:%lu:%lu: %s\n",
+ argc, pe.line (), pe.column (), pe.xml_text ());
+ break;
+ }
+ case parser_error::schema:
+ {
+ fprintf (stderr, "%s:%lu:%lu: %s\n",
+ argc, pe.line (), pe.column (), pe.schema_text ());
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 1;
+ }
+
+ // Print what we've got.
+ //
+ for (hello::name_const_iterator i = h->name ().begin ();
+ i != h->name ().end ();
+ ++i)
+ {
+ printf ("%s, %s!\n", h->greeting (), *i);
+ }
+
+ using xml_schema::strdupx;
+
+ // Change the greeting phrase.
+ //
+ h->greeting (strdupx ("Hi"));
+
+ // Add another entry to the name sequence.
+ //
+ h->name ().push_back (strdupx ("mars"));
+
+ // Serialize.
+ //
+ using xml_schema::serializer_error;
+
+ serializer_error se;
+ writer w;
+
+ do
+ {
+ hello_saggr hello_s;
+ xml_schema::document_simpl doc_s (hello_s.root_serializer (),
+ hello_s.root_name ());
+ if (se = doc_s._error ())
+ break;
+
+ hello_s.pre (*h);
+
+ if (se = hello_s._error ())
+ break;
+
+ doc_s.serialize (w);
+
+ if (se = doc_s._error ())
+ break;
+
+ hello_s.post ();
+
+ se = hello_s._error ();
+
+ } while (false);
+
+ delete h;
+
+ // Handle serializer errors.
+ //
+ if (se)
+ {
+ switch (se.type ())
+ {
+ case serializer_error::sys:
+ {
+ fprintf (stderr, "error: %s\n", se.sys_text ());
+ break;
+ }
+ case serializer_error::xml:
+ {
+ fprintf (stderr, "error: %s\n", se.xml_text ());
+ break;
+ }
+ case serializer_error::schema:
+ {
+ fprintf (stderr, "error: %s\n", se.schema_text ());
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 1;
+ }
+}
+ </pre>
+
+ <p>The parsing and serialization parts of the above example got
+ quite a bit more complex due to the lack of exceptions and iostream
+ support. For more information on what's going on there, refer to
+ <a href="#6">Chapter 6, "Parsing and Serialization"</a>. On the other
+ hand, the access and modification of the object model stayed
+ relatively unchanged. The only noticeable change is the use
+ of the <code>xml_schema::strdupx</code> function to create
+ C strings from string literals. We have to use this function
+ because the object model assumes ownership of the strings
+ passed. We also cannot use the standard C <code>strdup</code>
+ because the object model expects the strings to be allocated
+ with C++ operator <code>new[]</code> while C <code>strdup</code>
+ uses <code>malloc</code> (on most implementations operator
+ <code>new</code> is implemented in terms of <code>malloc</code>
+ so you can probably use <code>strdup</code> if you really
+ want to).</p>
+
+
+ <!-- Mapping Configuration -->
+
+
+ <h1><a name="3">3 Mapping Configuration</a></h1>
+
+ <p>The Embedded C++/Hybrid mapping has a number of configuration
+ parameters that determine the overall properties and behavior
+ of the generated code, such as the use of Standard Template
+ Library (STL), Input/Output Stream Library (iostream), C++
+ exceptions, XML Schema validation, 64-bit integer types, as well as
+ parser and serializer implementation reuse styles. In the previous
+ chapter we have already got an overview of the changes to the
+ generated code that happen when we disable STL, iostream, and C++
+ exceptions. In this chapter we will discuss these and other
+ configuration parameters in more detail.</p>
+
+ <p>In order to enable or disable a particular feature, the corresponding
+ configuration parameter should be set accordingly in the XSD/e runtime
+ library as well as specified during schema compilation with the XSD/e
+ command line options as described in the
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e
+ Compiler Command Line Manual</a>.
+ </p>
+
+ <p>While the XML documents can use various encodings, the Embedded
+ C++/Hybrid mapping always delivers character data to the application
+ in the UTF-8 encoding. The underlying XML parser used by the mapping
+ includes built-in support for XML documents encoded in UTF-8, UTF-16,
+ ISO-8859-1, and US-ASCII. Other encodings can be supported by providing
+ application-specific decoder functions. C++/Hybrid also expects character
+ data supplied by the application to be in the UTF-8 encoding. The
+ underlying XML serializer used by the mapping produces the resulting
+ XML in the UTF-8 encoding as well.</p>
+
+ <h2><a name="3.1">3.1 Standard Template Library</a></h2>
+
+ <p>To disable the use of STL you will need to configure the XSD/e
+ runtime without support for STL as well as pass the
+ <code>--no-stl</code> option to the XSD/e compiler when
+ translating your schemas.</p>
+
+ <p>When STL is disabled, all string-based XML Schema types
+ (see <a href="#5">Chapter 5, "Mapping for Built-In XML Schema
+ Types"</a>) are mapped to C-style <code>char*</code> instead of
+ <code>std::string</code>. In this configuration when you set an
+ element or attribute value of a string-based type, the object
+ model assumes ownership of the string and expects that it was
+ allocated with operator <code>new[]</code>. To simplify
+ creation of such strings from string literals, the generated
+ code provides the <code>strdupx</code> and <code>strndupx</code>
+ functions in the <code>xml_schema</code> namespace. These functions
+ are similar to C <code>strdup</code> and <code>strndup</code> except
+ that they use operator <code>new[]</code> instead of <code>malloc</code>
+ to allocate the string:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ char*
+ strdupx (const char*);
+
+ char*
+ strndupx (const char*, size_t);
+}
+ </pre>
+
+ <h2><a name="3.2">3.2 Input/Output Stream Library</a></h2>
+
+ <p>To disable the use of iostream you will need to configure the
+ XSD/e runtime library without support for iostream as well as
+ pass the <code>--no-iostream</code> option to the XSD/e compiler
+ when translating your schemas. When iostream is disabled, a
+ number of overloaded <code>parse()</code> and <code>serialize()</code>
+ functions in the document parser (<code>xml_schema::document_pimpl</code>)
+ and document serializer (<code>xml_schema::document_simpl</code>) become
+ unavailable. See
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#7">Chapter 7,
+ "Document Parser and Error Handling"</a> in the Embedded
+ C++/Parser Mapping Getting Started Guide and
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#8">Chapter 8,
+ "Document Serializer and Error Handling"</a> in the Embedded
+ C++/Serializer Mapping Getting Started Guide for details.
+ </p>
+
+ <h2><a name="3.3">3.3 C++ Exceptions</a></h2>
+
+ <p>To disable the use of C++ exceptions, you will need to configure
+ the XSD/e runtime without support for exceptions as well as pass
+ the <code>--no-exceptions</code> option to the XSD/e compiler
+ when translating your schemas. When C++ exceptions are disabled,
+ the error conditions that may arise while parsing, serializing,
+ and modifying the object model are indicated with error codes
+ instead of exceptions. For more information on error handling
+ during parsing, see
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#7">Chapter 7,
+ "Document Parser and Error Handling"</a> in the Embedded C++/Parser
+ Mapping Getting Started Guide. For more information on error handling
+ during serialization, see
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#8">Chapter 8,
+ "Document Serializer and Error Handling"</a> in the Embedded
+ C++/Serializer Mapping Getting Started Guide. For more information on
+ error handling in the object model, see <a href="#4">Chapter 4, "Working
+ with Object Models"</a> below.
+ </p>
+
+ <h2><a name="3.4">3.4 XML Schema Validation</a></h2>
+
+ <p>By default, XML Schema validation is enabled during both parsing
+ and serialization. To disable validation during parsing, you will
+ need to configure the XSD/e runtime to disable support for validation
+ in the C++/Parser mapping as well as pass the <code>--suppress-parser-val</code>
+ option to the XSD/e compiler when translating your schemas. To disable
+ validation during serialization, you will need to configure the XSD/e
+ runtime to disable support for validation in the C++/Serializer mapping
+ as well as pass the <code>--suppress-serializer-val</code>
+ option to the XSD/e compiler when translating your schemas. If you
+ are disabling validation during both parsing and serialization, you
+ can use the <code>--suppress-validation</code> option instead of the
+ two options mentioned above.</p>
+
+ <p>Disabling XML Schema validation allows to further increase the
+ parsing and serialization performance as well as reduce footprint in
+ cases where the data being parsed and/or serialized is known
+ to be valid.</p>
+
+ <h2><a name="3.5">3.5 64-bit Integer Type</a></h2>
+
+ <p>By default the 64-bit <code>long</code> and <code>unsignedLong</code>
+ built-in XML Schema types are mapped to the 64-bit <code>long long</code>
+ and <code>unsigned long long</code> fundamental C++ types. To
+ disable the use of these types in the mapping you will need to
+ configure the XSD/e runtime accordingly as well as pass
+ the <code>--no-long-long</code> option to the XSD/e compiler
+ when translating your schemas. When the use of 64-bit integral
+ C++ types is disabled the <code>long</code> and
+ <code>unsignedLong</code> XML Schema built-in types are mapped
+ to <code>long</code> and <code>unsigned long</code> fundamental
+ C++ types.</p>
+
+ <h2><a name="3.6">3.6 Parser and Serializer Reuse</a></h2>
+
+ <p>When one type in XML Schema inherits from another, it is
+ often desirable to be able to reuse the parser and serializer
+ implementations corresponding to the base type in the parser
+ and serializer implementations corresponding to the derived type.
+ XSD/e provides support for two reuse styles: the so-called <em>mixin</em>
+ (generated when the <code>--reuse-style-mixin</code> option
+ is specified) and <em>tiein</em> (generated by default) styles.
+ The XSD/e runtime should be configured in accordance with the
+ reuse style used in the generated code. See <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#5.6">Section 5.6,
+ "Parser Reuse"</a> in the Embedded C++/Parser Mapping Getting Started
+ Guide and
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#6.6">Section 6.6,
+ "Serializer Reuse"</a> in the Embedded C++/Serializer Mapping Getting
+ Started Guide for details.</p>
+
+
+ <!-- Chapater 4 -->
+
+
+ <h1><a name="4">4 Working with Object Models</a></h1>
+
+ <p>As we have seen in the previous chapters, the XSD/e compiler generates
+ a C++ class for each type defined in XML Schema. Together these classes
+ constitute an object model for an XML vocabulary. In this chapter we
+ will take a closer look at different parts that comprise an
+ object model class as well as how to create, access, and modify
+ object models.</p>
+
+ <p>In this chapter we will use the following schema that describes a
+ collection of person records. We save it in <code>people.xsd</code>:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0"?>
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:simpleType name="gender">
+ &lt;xs:restriction base="xs:string">
+ &lt;xs:enumeration value="male"/>
+ &lt;xs:enumeration value="female"/>
+ &lt;/xs:restriction>
+ &lt;/xs:simpleType>
+
+ &lt;xs:complexType name="person">
+ &lt;xs:sequence>
+ &lt;xs:element name="first-name" type="xs:string"/>
+ &lt;xs:element name="middle-name" type="xs:string" minOccurs="0"/>
+ &lt;xs:element name="last-name" type="xs:string"/>
+ &lt;xs:element name="gender" type="gender"/>
+ &lt;xs:element name="age" type="xs:unsignedShort"/>
+ &lt;/xs:sequence>
+ &lt;xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+ &lt;/xs:complexType>
+
+ &lt;xs:complexType name="people">
+ &lt;xs:sequence>
+ &lt;xs:element name="person" type="person" maxOccurs="unbounded"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="people" type="people"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>A sample XML instance to go along with this schema is saved
+ in <code>people.xml</code>:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0"?>
+&lt;people>
+
+ &lt;person id="1">
+ &lt;first-name>John&lt;/first-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>male&lt;/gender>
+ &lt;age>32&lt;/age>
+ &lt;/person>
+
+ &lt;person id="2">
+ &lt;first-name>Jane&lt;/first-name>
+ &lt;middle-name>Mary&lt;/middle-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>female&lt;/gender>
+ &lt;age>28&lt;/age>
+ &lt;/person>
+
+&lt;/people>
+ </pre>
+
+ <p>Compiling <code>people.xsd</code> with the XSD/e compiler results
+ in three generated object model classes: <code>gender</code>,
+ <code>person</code> and <code>people</code>. Here is how they
+ look with STL enabled:</p>
+
+ <pre class="c++">
+// gender (fixed-length)
+//
+class gender: public std::string
+{
+public:
+ gender ();
+ gender (const gender&amp;);
+ gender&amp; operator= (const gender&amp;);
+};
+
+// person (fixed-length)
+//
+class person
+{
+public:
+ person ();
+ person (const person&amp;);
+ person&amp; operator= (const person&amp;);
+
+ // id
+ //
+ unsigned int
+ id () const;
+
+ unsigned int&amp;
+ id ();
+
+ void
+ id (unsigned int);
+
+ // first-name
+ //
+ const std::string&amp;
+ first_name () const;
+
+ std::string&amp;
+ first_name ();
+
+ void
+ first_name (const std::string&amp;);
+
+ // middle-name
+ //
+ bool
+ middle_name_present () const;
+
+ void
+ middle_name_present (bool);
+
+ const std::string&amp;
+ middle_name () const;
+
+ std::string&amp;
+ middle_name ();
+
+ void
+ middle_name (const std::string&amp;);
+
+ // last-name
+ //
+ const std::string&amp;
+ last_name () const;
+
+ std::string&amp;
+ last_name ();
+
+ void
+ last_name (const std::string&amp;);
+
+ // gender
+ //
+ const ::gender&amp;
+ gender () const;
+
+ ::gender&amp;
+ gender ();
+
+ void
+ gender (const ::gender&amp;);
+
+ // age
+ //
+ unsigned short
+ age () const;
+
+ unsigned short&amp;
+ age ();
+
+ void
+ age (unsigned short);
+
+private:
+ ...
+};
+
+// people (variable-length)
+//
+class people
+{
+public:
+ people ();
+
+private:
+ people (const people&amp;);
+ people&amp; operator= (const people&amp;);
+
+public:
+ // person
+ //
+ typedef xsde::fix_sequence&lt;person> person_sequence;
+ typedef person_sequence::iterator person_iterator;
+ typedef person_sequence::const_iterator person_const_iterator;
+
+ const person_sequence&amp;
+ person () const;
+
+ person_sequence&amp;
+ person ();
+
+private:
+ ...
+};
+ </pre>
+
+ <p>We will examine these classes in detail in the subsequent
+ sections.</p>
+
+ <h2><a name="4.1">4.1 Namespaces</a></h2>
+
+ <p>XSD/e maps XML namespaces specified in the <code>targetNamespace</code>
+ attribute in XML Schema to one or more nested C++ namespaces. By
+ default, a namespace URI is mapped to a sequence of C++ namespace
+ names by removing the protocol and host parts and splitting the
+ rest into a sequence of names with <code>'/'</code> as the name
+ separator. For example, the <code>http://www.codesynthesis.com/cs/my</code>
+ XML namespace is mapped to the <code>cs::my</code> C++ namespace.</p>
+
+ <p>The default mapping of namespace URIs to C++ namespaces
+ can be altered using the <code>--namespace-map</code> and
+ <code>--namespace-regex</code> compiler options. For example,
+ to map the <code>http://www.codesynthesis.com/my</code> XML
+ namespace to the <code>cs::my</code> C++ namespace, we can use
+ the following option:</p>
+
+ <pre class="terminal">
+--namespace-map http://www.codesynthesis.com/my=cs::my
+ </pre>
+
+ <p>A vocabulary without a namespace is mapped to the global scope. This
+ also can be altered with the above options by using an empty name
+ for the XML namespace. For example, we could place the generated
+ object model classes for the <code>people.xsd</code> schema
+ into the <code>records</code> C++ namespace by adding the following
+ option:</p>
+
+ <pre class="terminal">
+--namespace-map =records
+ </pre>
+
+
+ <h2><a name="4.2">4.2 Memory Management</a></h2>
+
+ <p>To ensure that objects are allocated and passed efficiently,
+ the C++/Hybrid mapping divides all object model types into
+ fixed-length and variable-length. A type is variable-length
+ if any of the following is true:</p>
+
+ <ol class="list">
+ <li>it is an XML Schema <code>list</code> type</li>
+
+ <li>it is an XML Schema <code>union</code> type and STL is disabled</li>
+
+ <li>it derives from a variable-length type</li>
+
+ <li>it contains an element or attribute of a variable-length type</li>
+
+ <li>it contains an element or compositor (<code>sequence</code>
+ or <code>choice</code>) with <code>maxOccurs</code>
+ greater than one</li>
+
+ <li>it is recursive (that is, one of its elements contains
+ a reference, directly or indirectly, to the type itself)</li>
+ </ol>
+
+ <p>The following build-in XML Schema types are variable-length:
+ <code>base64Binary</code>, <code>hexBinary</code>, <code>NMTOKENS</code>,
+ and <code>IDREFS</code>. Furthermore, if STL is disabled, all
+ string-based build-in XML Schema types are variable-length,
+ namely: <code>string</code>, <code>normalizedString</code>,
+ <code>token</code>, <code>Name</code>, <code>NMTOKEN</code>,
+ <code>NCName</code>, <code>language</code>, <code>QName</code>,
+ <code>ID</code>, <code>IDFER</code>, and <code>anyURI</code>.</p>
+
+ <p>Otherwise, a type is fixed-length. As you might have noticed from
+ the previous code listings, the XSD/e compiler adds a comment before
+ each generated object model class that states whether it is fixed or
+ variable-length. For example, the <code>people</code> type is
+ variable-length because it contains a sequence of <code>person</code>
+ elements (<code>maxOccurs="unbounded"</code>). If we recompile
+ the <code>people.xsd</code> schema with the <code>--no-stl</code>
+ option, the first two types will also become variable-length
+ since <code>gender</code> inherits from and <code>person</code>
+ contains elements of the <code>string</code> built-in type. And
+ when STL is disabled, <code>string</code> is variable-length.</p>
+
+ <p>The object model uses different methods for storing and passing
+ around fixed-length and variable-length types. Instances of
+ fixed-length types are stored and passed by value since it is
+ cheaper to copy than to allocate them dynamically (in the
+ STL case, the <code>std::string</code> is expected to support the
+ referenced-counted copy-on-write optimization, which makes
+ copying cheap).</p>
+
+ <p>Variable-length types are always allocated dynamically and
+ are stored and passed as pointers. Because copying an instance
+ of a variable-length type can be expensive, such types make
+ their copy constructor and copy assignment operators unavailable.</p>
+
+ <p>When you set a value of an element or attribute of a
+ variable-length type, the object model assumes ownership of
+ the pointed to object. It expects you to allocate the object with
+ operator <code>new</code> and will eventually delete it
+ with operator <code>delete</code>. As an example, let us extend
+ our <code>people.xsd</code> schema with the following type:</p>
+
+ <pre class="xml">
+&lt;xs:complexType name="staff">
+ &lt;xs:sequence>
+ &lt;xs:element name="permanent" type="people"/>
+ &lt;xs:element name="contract" type="people"/>
+ &lt;/xs:sequence>
+&lt;/xs:complexType>
+ </pre>
+
+ <p>If we compile it with XSD/e, we will get the following C++
+ class:</p>
+
+ <pre class="c++">
+// staff (variable-length)
+//
+class staff
+{
+public:
+ staff ();
+
+private:
+ staff (const staff&amp;);
+ staff&amp; operator= (const staff&amp;);
+
+public:
+ // permanent
+ //
+ const people&amp;
+ permanent () const;
+
+ people&amp;
+ permanent ();
+
+ void
+ permanent (people*);
+
+ // contract
+ //
+ const people&amp;
+ contract () const;
+
+ people&amp;
+ contract ();
+
+ void
+ contract (people*);
+
+private:
+ ...
+};
+ </pre>
+
+ <p>Notice that unlike, say, the <code>first_name()</code> modifier
+ function in the <code>person</code> class, the <code>permanent()</code>
+ and <code>contract()</code> modifiers expect a pointer to the
+ <code>people</code> object. The following listing shows how
+ we can create and populate an instance of the <code>staff</code>
+ class. The use of smart pointers to hold the results of dynamic
+ allocations is omitted for brevity:</p>
+
+ <pre class="c++">
+people* per = new people;
+people* con = new people;
+
+// Populate per and con.
+
+staff s;
+s->permanent (per) // Assumes ownership or per.
+s->contract (con) // Assumes ownership or con.
+ </pre>
+
+ <h2><a name="4.3">4.3 Attributes and Elements</a></h2>
+
+ <p>As we have seen before, XSD/e generates a different
+ set of member functions for elements with different cardinalities.
+ The C++/Hybrid mapping divides all the possible element and attribute
+ cardinalities into three cardinality classes:
+ <em>one</em>, <em>optional</em>, and <em>sequence</em>.</p>
+
+ <p>The <em>one</em> cardinality class covers all elements that should
+ occur exactly once as well as the required attributes. In our
+ example, the <code>first-name</code>, <code>last-name</code>,
+ <code>gender</code>, and <code>age</code> elements as well as
+ the <code>id</code> attribute belong to this cardinality class.
+ The following code fragment shows again the accessor and modifier
+ functions that are generated for the <code>first-name</code> element
+ in the <code>person</code> class:</p>
+
+ <pre class="c++">
+class person
+{
+ // first-name
+ //
+ const std::string&amp;
+ first_name () const;
+
+ std::string&amp;
+ first_name ();
+
+ void
+ first_name (const std::string&amp;);
+};
+ </pre>
+
+ <p>The first two accessor functions return read-only (constant) and
+ read-write references to the element's value, respectively. The
+ modifier function sets the new value for the element. Note that
+ the signature of the modifier function varies depending on
+ whether the element or attribute is of a fixed or variable-length
+ type, as was discussed in the previous section.</p>
+
+ <p>The <em>optional</em> cardinality class covers all elements that
+ can occur zero or one time as well as optional attributes. In our
+ example, the <code>middle-name</code> element belongs to this
+ cardinality class. The following code fragment shows again the
+ accessor and modifier functions that are generated for this element
+ in the <code>person</code> class:</p>
+
+ <pre class="c++">
+class person
+{
+ // middle-name
+ //
+ bool
+ middle_name_present () const;
+
+ void
+ middle_name_present (bool);
+
+ const std::string&amp;
+ middle_name () const;
+
+ std::string&amp;
+ middle_name ();
+
+ void
+ middle_name (const std::string&amp;);
+};
+ </pre>
+
+ <p>Compared to the <em>one</em> cardinality class, <em>optional</em> adds
+ two extra functions for querying and modifying the element's presence
+ status. The following example shows how we can use these functions:</p>
+
+ <pre class="c++">
+person&amp; p = ...
+
+if (p.middle_name_present ())
+{
+ cout &lt;&lt; p.middle_name () &lt;&lt; endl;
+ p.middle_name_present (false); // Reset to the "not present" state.
+}
+ </pre>
+
+ <p>Finally, the <em>sequence</em> cardinality class covers all elements
+ that can occur more than once. In our example, the
+ <code>person</code> element in the <code>people</code> type
+ belongs to this cardinality class. The following code fragment shows
+ again the type definitions as well as the accessor and modifier
+ functions that are generated for this element in the <code>people</code>
+ class:</p>
+
+ <pre class="c++">
+class people
+{
+ // person
+ //
+ typedef xsde::fix_sequence&lt;person> person_sequence;
+ typedef person_sequence::iterator person_iterator;
+ typedef person_sequence::const_iterator person_const_iterator;
+
+ const person_sequence&amp;
+ person () const;
+
+ person_sequence&amp;
+ person ();
+};
+ </pre>
+
+ <p>The <code>person_sequence</code> type is a sequence container for the
+ element's values. It has an interface similar to <code>std::vector</code>
+ and we will discuss it in more detail shortly. The <code>person_iterator</code>
+ and <code>person_const_iterator</code> types are read-write and read-only
+ (constant) iterators for the <code>person_sequence</code>
+ container.</p>
+
+ <p>Unlike other two cardinality classes, the <em>sequence</em> class
+ only provides accessor functions that return read-only (constant)
+ and read-write references to the sequence container. The
+ modification of the element values is performed my manipulating
+ the returned sequence container and elements that it contains.</p>
+
+ <p>In the remainder of this section we will examine the interfaces
+ of the sequence containers which differ slightly depending on
+ whether the element type is fixed or variable-length and whether
+ C++ exceptions are enabled. Also, when STL is disabled, string
+ sequences have a special interface which is also discussed
+ below.</p>
+
+ <p>When exceptions are enabled, the fixed-length type sequences
+ are implemented in terms of the following class template:</p>
+
+ <pre class="c++">
+template &lt;typename T>
+class fix_sequence
+{
+public:
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T&amp; reference;
+ typedef const T&amp; const_reference;
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+public:
+ fix_sequence ();
+
+ void
+ swap (fix_sequence&amp;);
+
+private:
+ fix_sequence (const fix_sequence&amp;);
+
+ fix_sequence&amp;
+ operator= (fix_sequence&amp;);
+
+public:
+ iterator
+ begin ();
+
+ const_iterator
+ begin () const;
+
+ iterator
+ end ();
+
+ const_iterator
+ end () const;
+
+ T&amp;
+ front ();
+
+ const T&amp;
+ front () const;
+
+ T&amp;
+ back ();
+
+ const T&amp;
+ back () const;
+
+ T&amp;
+ operator[] (size_t);
+
+ const T&amp;
+ operator[] (size_t) const;
+
+public:
+ bool
+ empty () const;
+
+ size_t
+ size () const;
+
+ size_t
+ capacity () const;
+
+ size_t
+ max_size () const;
+
+public:
+ void
+ clear ();
+
+ void
+ pop_back ();
+
+ iterator
+ erase (iterator);
+
+ void
+ push_back (const T&amp;);
+
+ iterator
+ insert (iterator, const T&amp;);
+
+ void
+ reserve (size_t);
+};
+ </pre>
+
+ <p>When C++ exceptions are disabled, the signatures of the
+ <code>push_back()</code>, <code>insert()</code>, and
+ <code>reserve()</code> functions change as follows:</p>
+
+ <pre class="c++">
+template &lt;typename T>
+class fix_sequence
+{
+public:
+ enum error
+ {
+ error_none,
+ error_no_memory
+ };
+
+ ...
+
+public:
+ error
+ push_back (const T&amp;);
+
+ error
+ insert (iterator, const T&amp;);
+
+ error
+ insert (iterator, const T&amp;, iterator&amp; result);
+
+ error
+ reserve (size_t);
+};
+ </pre>
+
+ <p>That is, the functions that may require memory allocation
+ now return an error code that you will need to check in
+ order to detect the out of memory condition.</p>
+
+ <p>When exceptions are enabled, the variable-length type sequences
+ are implemented in terms of the following class template:</p>
+
+ <pre class="c++">
+template &lt;typename T>
+class var_sequence
+{
+public:
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T&amp; reference;
+ typedef const T&amp; const_reference;
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ typedef &lt;implementation details> iterator;
+ typedef &lt;implementation details> const_iterator;
+
+public:
+ var_sequence ();
+
+ void
+ swap (var_sequence&amp;);
+
+private:
+ var_sequence (const var_sequence&amp;);
+
+ var_sequence&amp;
+ operator= (var_sequence&amp;);
+
+public:
+ iterator
+ begin ();
+
+ const_iterator
+ begin () const;
+
+ iterator
+ end ();
+
+ const_iterator
+ end () const;
+
+ T&amp;
+ front ();
+
+ const T&amp;
+ front () const;
+
+ T&amp;
+ back ();
+
+ const T&amp;
+ back () const;
+
+ T&amp;
+ operator[] (size_t);
+
+ const T&amp;
+ operator[] (size_t) const;
+
+public:
+ bool
+ empty () const;
+
+ size_t
+ size () const;
+
+ size_t
+ capacity () const;
+
+ size_t
+ max_size () const;
+
+public:
+ void
+ clear ();
+
+ void
+ pop_back ();
+
+ iterator
+ erase (iterator);
+
+ void
+ push_back (T*);
+
+ iterator
+ insert (iterator, T*);
+
+ error
+ reserve (size_t);
+};
+ </pre>
+
+ <p>Most of this interface is identical to the fixed-length type
+ version except for the <code>push_back()</code> and
+ <code>insert()</code> functions. Similar to the modifier
+ functions for elements and attributes of variable-length
+ types, these two functions expect a pointer to the
+ dynamically-allocated instance of the type and assume
+ ownership of the passed object. To simplify error handling,
+ these two functions delete the passed object if the reallocation
+ of the underlying sequence buffer fails.</p>
+
+ <p>When C++ exceptions are disabled, the <code>push_back()</code>,
+ <code>insert()</code>, and <code>reserve()</code> functions
+ return an error code to signal the out of memory condition:</p>
+
+ <pre class="c++">
+template &lt;typename T>
+class var_sequence
+{
+public:
+ enum error
+ {
+ error_none,
+ error_no_memory
+ };
+
+ ...
+
+public:
+ error
+ push_back (T*);
+
+ error
+ insert (iterator, T*);
+
+ error
+ insert (iterator, T*, iterator&amp; result);
+
+ error
+ reserve (size_t);
+};
+ </pre>
+
+
+ <p>When STL is enabled, the string sequence have the same
+ interface as <code>fix_sequence&lt;std::string></code>. When
+ STL is disabled and strings are mapped to <code>char*</code>,
+ the string sequence has a special interface. When C++ exceptions are
+ enabled, it has the following definition:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class string_sequence
+ {
+ public:
+ typedef char* value_type;
+ typedef char** pointer;
+ typedef const char** const_pointer;
+ typedef char* reference;
+ typedef const char* const_reference;
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ typedef char** iterator;
+ typedef const char* const* const_iterator;
+
+ string_sequence ();
+
+ void
+ swap (string_sequence&amp;);
+
+ private:
+ string_sequence (string_sequence&amp;);
+
+ string_sequence&amp;
+ operator= (string_sequence&amp;);
+
+ public:
+ iterator
+ begin ();
+
+ const_iterator
+ begin () const;
+
+ iterator
+ end ();
+
+ const_iterator
+ end () const;
+
+ char*
+ front ();
+
+ const char*
+ front () const;
+
+ char*
+ back ();
+
+ const char*
+ back () const;
+
+ char*
+ operator[] (size_t);
+
+ const char*
+ operator[] (size_t) const;
+
+ public:
+ bool
+ empty () const;
+
+ size_t
+ size () const;
+
+ size_t
+ capacity () const;
+
+ size_t
+ max_size () const;
+
+ public:
+ void
+ clear ();
+
+ void
+ pop_back ();
+
+ iterator
+ erase (iterator);
+
+ void
+ push_back (char*);
+
+ void
+ push_back_copy (const char*);
+
+ iterator
+ insert (iterator, char*);
+
+ void
+ reserve (size_t);
+
+ // Detach a string from the sequence at a given position.
+ // The string pointer at this position in the sequence is
+ // set to 0.
+ //
+ char*
+ detach (iterator);
+ };
+}
+ </pre>
+
+ <p>The <code>push_back()</code> and <code>insert()</code> functions
+ assume ownership of the passed string which should be allocated
+ with operator <code>new[]</code> and will be deallocated
+ with operator <code>delete[]</code> by the <code>string_sequence</code>
+ object. Similar to <code>var_sequence</code>, these two functions
+ free the passed string if the reallocation of the underlying
+ sequence buffer fails. The <code>push_back_copy()</code>
+ function makes a copy of the passed string.
+ If you detach the underlying element string, then it should
+ eventually be deallocated with operator <code>delete[]</code>.</p>
+
+ <p>When C++ exceptions are disabled, the signatures of the
+ <code>push_back()</code>, <code>push_back_copy()</code>,
+ <code>insert()</code>, and <code>reserve()</code> functions
+ in the <code>string_sequence</code> class change as follows:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class string_sequence
+ {
+ public:
+ enum error
+ {
+ error_none,
+ error_no_memory
+ };
+
+ ...
+
+ public:
+ error
+ push_back (char*);
+
+ error
+ push_back_copy (const char*);
+
+ error
+ insert (iterator, char*);
+
+ error
+ insert (iterator, char*, iterator&amp; result);
+
+ error
+ reserve (size_t);
+ };
+}
+ </pre>
+
+ <h2><a name="4.4">4.4 Compositors</a></h2>
+
+ <p>The XML Schema language provides three compositor constructs that
+ are used to group elements: <code>all</code>, <code>sequence</code>,
+ and <code>choice</code>. If a compositor has an <em>optional</em>
+ or <em>sequence</em> cardinality class (see <a href="#4.3">Section
+ 4.3, "Attributes and Elements"</a>) or if a compositor is
+ inside <code>choice</code>, then the C++/Hybrid mapping generates
+ a nested class for such a compositor as well as a set of accessor
+ and modifier functions similar to the ones defined for elements
+ and attributes. Otherwise, the member functions, corresponding
+ to elements defined in a compositor, are generated directly in
+ the containing class.</p>
+
+ <p>Compositor classes are either fixed or variable-length and
+ obey the same storage and passing rules as object model
+ classes corresponding to XML Schema types (see <a href="#4.2">Section
+ 4.2, "Memory Management"</a>). Consider the following schema
+ fragment as an example:</p>
+
+ <pre class="xml">
+&lt;complexType name="type">
+ &lt;sequence>
+ &lt;sequence minOccurs="0">
+ &lt;element name="a" type="int"/>
+ &lt;element name="b" type="string" maxOccurs="unbounded"/>
+ &lt;/sequence>
+ &lt;sequence maxOccurs="unbounded">
+ &lt;element name="c" type="int"/>
+ &lt;element name="d" type="string"/>
+ &lt;/sequence>
+ &lt;/sequence>
+&lt;/complexType>
+ </pre>
+
+ <p>The corresponding object model class is shown below:</p>
+
+ <pre class="c++">
+// type (variable-length)
+//
+class type
+{
+public:
+ type ();
+
+private:
+ type (const type&amp;);
+ type&amp; operator= (const type&amp;);
+
+public:
+ // sequence (variable-length)
+ //
+ class sequence_type
+ {
+ public:
+ sequence_type ();
+
+ private:
+ sequence_type (const sequence_type&amp;);
+ sequence_type&amp; operator= (const sequence_type&amp;);
+
+ public:
+ // a
+ //
+ int
+ a () const;
+
+ int&amp;
+ a ();
+
+ void
+ a (int);
+
+ // b
+ //
+ typedef xsde::string_sequence b_sequence;
+ typedef b_sequence::iterator b_iterator;
+ typedef b_sequence::const_iterator b_const_iterator;
+
+ const b_sequence&amp;
+ b () const;
+
+ b_sequence&amp;
+ b ();
+
+ private:
+ ...
+ };
+
+ bool
+ sequence_present () const;
+
+ void
+ sequence_present (bool);
+
+ const sequence_type&amp;
+ sequence () const;
+
+ sequence_type&amp;
+ sequence ();
+
+ void
+ sequence (sequence_type*);
+
+ // sequence1 (fixed-length)
+ //
+ class sequence1_type
+ {
+ public:
+ sequence1_type ();
+ sequence1_type (const sequence1_type&amp;);
+ sequence1_type&amp; operator= (const sequence1_type&amp;);
+
+ // c
+ //
+ int
+ c () const;
+
+ int&amp;
+ c ();
+
+ void
+ c (int);
+
+ // d
+ //
+ const std::string&amp;
+ d () const;
+
+ std::string&amp;
+ d ();
+
+ void
+ d (const std::string&amp;);
+
+ private:
+ ...
+ };
+
+ typedef xsde::fix_sequence&lt;sequence1_type> sequence1_sequence;
+ typedef sequence1_sequence::iterator sequence1_iterator;
+ typedef sequence1_sequence::const_iterator sequence1_const_iterator;
+
+ const sequence1_sequence&amp;
+ sequence1 () const;
+
+ sequence1_sequence&amp;
+ sequence1 ();
+
+private:
+ ...
+};
+ </pre>
+
+ <p>The content of the outer <code>sequence</code> compositor is
+ generated in-line since this compositor belongs to the <em>one</em>
+ cardinality class. The first nested <code>sequence</code> compositor
+ is optional (<code>minOccurs="0"</code>), which results in a corresponding
+ nested class. Notice that the <code>sequence_type</code> is
+ variable-length and the accessor and modifier functions corresponding
+ to this <code>sequence</code> compositor are the same as for an
+ optional element or attribute. Similarly, the second nested
+ compositor is of the <em>sequence</em> cardinality class
+ (<code>maxOccurs="unbounded"</code>), which also results in a
+ nested class and a set of accessor functions.</p>
+
+ <p>Generated code corresponding to an <code>all</code> and
+ <code>sequence</code> compositor, whether in-line or as a
+ nested class, simply define accessor and modifier functions
+ for the elements that this compositor contains. For the
+ <code>choice</code> compositor, on the other hand,
+ additional types and functions are generated to support
+ querying and selecting the choice arm that is in effect.
+ Consider the following simple example:</p>
+
+ <pre class="xml">
+&lt;complexType name="type">
+ &lt;choice>
+ &lt;element name="a" type="int"/>
+ &lt;element name="b" type="string"/>
+ &lt;element name="c" type="boolean"/>
+ &lt;/choice>
+&lt;/complexType>
+ </pre>
+
+
+ <p>The corresponding object model class is shown next:</p>
+
+ <pre class="c++">
+// type (fixed-length)
+//
+class type
+{
+public:
+ type ();
+ type (const type&amp;);
+ type&amp; operator= (const type&amp;);
+
+ // choice
+ //
+ enum choice_arm_tag
+ {
+ a_tag,
+ b_tag,
+ c_tag
+ };
+
+ choice_arm_tag
+ choice_arm () const;
+
+ void
+ choice_arm (choice_arm_tag);
+
+ // a
+ //
+ int
+ a () const;
+
+ int&amp;
+ a ();
+
+ void
+ a (int);
+
+ // b
+ //
+ const std::string&amp;
+ b () const;
+
+ std::string&amp;
+ b ();
+
+ void
+ b (const std::string&amp;);
+
+ // c
+ //
+ bool
+ c () const;
+
+ bool&amp;
+ c ();
+
+ void
+ c (bool);
+
+private:
+ ...
+};
+ </pre>
+
+ <p>The extra type is the <code>choice_arm_tag</code> enumeration
+ which defines a set of tags corresponding to each choice arm.
+ There are also the <code>choice_arm()</code> accessor and modifier
+ functions that can be used to query and set the current choice arm.
+ The following code fragment shows how we can use this class:</p>
+
+ <pre class="c++">
+type&amp; x = ...
+
+switch (x.choice_arm ())
+{
+case type::a_tag:
+ {
+ cout &lt;&lt; "a: " &lt;&lt; x.a () &lt;&lt; endl;
+ break;
+ }
+case type::b_tag:
+ {
+ cout &lt;&lt; "b: " &lt;&lt; x.b () &lt;&lt; endl;
+ break;
+ }
+case type::c_tag:
+ {
+ cout &lt;&lt; "c: " &lt;&lt; x.c () &lt;&lt; endl;
+ break;
+ }
+}
+
+// Modifiers automatically set the corresponding arm.
+//
+x.a (10);
+
+// For accessors we need to select the arm explicitly.
+//
+x.choice_arm (type::b_tag);
+x.b () = "b";
+ </pre>
+
+ <p>The following slightly more complex example triggers the generation of
+ nested classes for the <code>choice</code> compositor as well as for
+ the <code>sequence</code> compositor inside <code>choice</code>.
+ Notice that the nested class for <code>sequence</code> is generated
+ because it is in <code>choice</code> even though its cardinality
+ class is <em>one</em>.</p>
+
+ <pre class="xml">
+&lt;complexType name="type">
+ &lt;choice maxOccurs="unbounded">
+ &lt;sequence>
+ &lt;element name="a" type="int"/>
+ &lt;element name="b" type="string"/>
+ &lt;/sequence>
+ &lt;element name="c" type="boolean"/>
+ &lt;/choice>
+&lt;/complexType>
+ </pre>
+
+ <p>The corresponding object model class is shown next:</p>
+
+ <pre class="c++">
+// type (variable-length)
+//
+class type
+{
+public:
+ type ();
+
+private:
+ type (const type&amp;);
+ type&amp; operator= (const type&amp;);
+
+public:
+ // choice (fixed-length)
+ //
+ class choice_type
+ {
+ public:
+ choice_type ();
+ choice_type (const choice_type&amp;);
+ choice_type&amp; operator= (const choice_type&amp;);
+
+ enum choice_arm_tag
+ {
+ sequence_tag,
+ c_tag
+ };
+
+ choice_arm_tag
+ choice_arm () const;
+
+ void
+ choice_arm (choice_arm_tag);
+
+ // sequence (fixed-length)
+ //
+ class sequence_type
+ {
+ public:
+ sequence_type ();
+ sequence_type (const sequence_type&amp;);
+ sequence_type&amp; operator= (const sequence_type&amp;);
+
+ // a
+ //
+ int
+ a () const;
+
+ int&amp;
+ a ();
+
+ void
+ a (int);
+
+ // b
+ //
+ const std::string&amp;
+ b () const;
+
+ std::string&amp;
+ b ();
+
+ void
+ b (const std::string&amp;);
+
+ private:
+ ...
+ };
+
+ const sequence_type&amp;
+ sequence () const;
+
+ sequence_type&amp;
+ sequence ();
+
+ void
+ sequence (const sequence_type&amp;);
+
+ // c
+ //
+ bool
+ c () const;
+
+ bool&amp;
+ c ();
+
+ void
+ c (bool);
+
+ private:
+ ...
+ };
+
+ typedef xsde::fix_sequence&lt;choice_type> choice_sequence;
+ typedef choice_sequence::iterator choice_iterator;
+ typedef choice_sequence::const_iterator choice_const_iterator;
+
+ const choice_sequence&amp;
+ choice () const;
+
+ choice_sequence&amp;
+ choice ();
+
+private:
+ ...
+};
+ </pre>
+
+ <h2><a name="4.5">4.5 Accessing the Object Model</a></h2>
+
+ <p>In this section we will examine how to get to the information
+ stored in the object model for the person records vocabulary
+ introduced at the beginning of this chapter. The following
+ application accesses and prints the contents of the
+ <code>people.xml</code> file:</p>
+
+ <pre class="c++">
+#include &lt;memory>
+#include &lt;iostream>
+
+#include "people.hxx"
+#include "people-pimpl.hxx"
+
+using namespace std;
+
+int
+main ()
+{
+ // Parse.
+ //
+ people_paggr people_p;
+ xml_schema::document_pimpl doc_p (people_p.root_parser (),
+ people_p.root_name ());
+ people_p.pre ();
+ doc_p.parse ("people.xml");
+ auto_ptr&lt;people> ppl (people_p.post ());
+
+ // Iterate over individual person records.
+ //
+ people::person_sequence&amp; ps = ppl->person ();
+
+ for (people::person_iterator i = ps.begin (); i != ps.end (); ++i)
+ {
+ person&amp; p = *i;
+
+ // Print names: first-name and last-name are required elements,
+ // middle-name is optional.
+ //
+ cout &lt;&lt; "name: " &lt;&lt; p.first_name () &lt;&lt; " ";
+
+ if (p.middle_name_present ())
+ cout &lt;&lt; p.middle_name () &lt;&lt; " ";
+
+ cout &lt;&lt; p.last_name () &lt;&lt; endl;
+
+ // Print gender, age, and id which are all required.
+ //
+ cout &lt;&lt; "gender: " &lt;&lt; p.gender () &lt;&lt; endl
+ &lt;&lt; "age: " &lt;&lt; p.age () &lt;&lt; endl
+ &lt;&lt; "id: " &lt;&lt; p.id () &lt;&lt; endl
+ &lt;&lt; endl;
+ }
+}
+ </pre>
+
+ <p>This code shows common patterns of accessing elements and attributes
+ with different cardinality classes. For the sequence element
+ (<code>person</code> in the <code>people</code> type) we first obtain a
+ reference to the container and then iterate over individual
+ records. The values of elements and attributes with the
+ <em>one</em> cardinality class (<code>first-name</code>,
+ <code>last-name</code>, <code>gender</code>, <code>age</code>,
+ and <code>id</code>) can be obtained directly by calling the
+ corresponding accessor functions. For the optional
+ <code>middle-name</code> element we first check if the value is present
+ and only then call the corresponding accessor to retrieve it.</p>
+
+ <p>Note that when we want to reduce typing by creating a variable
+ representing a fragment of the object model that we are currently
+ working with (<code>ps</code> and <code>p</code> above), we obtain
+ a reference to that fragment instead of making a copy. This is
+ generally a good rule to follow when creating efficient
+ applications.</p>
+
+ <p>If we run the above application on our sample
+ <code>people.xml</code>, the output looks as follows:</p>
+
+ <pre class="terminal">
+name: John Doe
+gender: male
+age: 32
+id: 1
+
+name: Jane Mary Doe
+gender: female
+age: 28
+id: 2
+ </pre>
+
+
+ <h2><a name="4.6">4.6 Modifying the Object Model</a></h2>
+
+ <p>In this section we will examine how to modify the information
+ stored in the object model for our person records vocabulary.
+ The following application changes the contents of the
+ <code>people.xml</code> file:</p>
+
+ <pre class="c++">
+#include &lt;memory>
+#include &lt;iostream>
+
+#include "people.hxx"
+#include "people-pimpl.hxx"
+#include "people-simpl.hxx"
+
+using namespace std;
+
+int
+main ()
+{
+ // Parse.
+ //
+ people_paggr people_p;
+ xml_schema::document_pimpl doc_p (people_p.root_parser (),
+ people_p.root_name ());
+ people_p.pre ();
+ doc_p.parse ("people.xml");
+ auto_ptr&lt;people> ppl (people_p.post ());
+
+ // Iterate over individual person records and increment
+ // the age.
+ //
+ people::person_sequence&amp; ps = ppl->person ();
+
+ for (people::person_iterator i = ps.begin (); i != ps.end (); ++i)
+ {
+ i->age ()++; // Alternative way: i->age (i->age () + 1)
+ }
+
+ // Add middle-name to the first record and remove it from
+ // the second.
+ //
+ person&amp; john = ps[0];
+ person&amp; jane = ps[1];
+
+ john.middle_name ("Mary");
+ jane.middle_name_present (false);
+
+ // Add another John record.
+ //
+ ps.push_back (john);
+
+ // Serialize the modified object model to XML.
+ //
+ people_saggr people_s;
+ xml_schema::document_simpl doc_s (people_s.root_serializer (),
+ people_s.root_name ());
+ people_s.pre (*ppl);
+ doc_s.serialize (cout);
+ people_s.post ();
+}
+ </pre>
+
+ <p>The first modification the above application performs is iterating
+ over person records and incrementing the age value. This code
+ fragment shows how to modify the value of a required attribute
+ or element. The next modification shows how to set a new value
+ for the optional <code>middle-name</code> element as well
+ as clear its value. Finally, the example adds a copy of the
+ John Doe record to the <code>person</code> element sequence.</p>
+
+ <p>Note that in this case using references for the <code>ps</code>,
+ <code>john</code>, and <code>jane</code> variables is no longer
+ a performance improvement but a requirement for the application
+ to function correctly. If we hadn't used references, all our changes
+ would have been made on copies without affecting the object model.</p>
+
+ <p>If we run the above application on our sample <code>people.xml</code>,
+ the output looks as follows:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0"?>
+&lt;people>
+
+ &lt;person id="1">
+ &lt;first-name>John&lt;/first-name>
+ &lt;middle-name>Mary&lt;/middle-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>male&lt;/gender>
+ &lt;age>33&lt;/age>
+ &lt;/person>
+
+ &lt;person id="2">
+ &lt;first-name>Jane&lt;/first-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>female&lt;/gender>
+ &lt;age>29&lt;/age>
+ &lt;/person>
+
+ &lt;person id="1">
+ &lt;first-name>John&lt;/first-name>
+ &lt;middle-name>Mary&lt;/middle-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>male&lt;/gender>
+ &lt;age>33&lt;/age>
+ &lt;/person>
+
+&lt;/people>
+ </pre>
+
+ <h2><a name="4.7">4.7 Creating the Object Model from Scratch</a></h2>
+
+ <p>In this section we will examine how to create a new object model
+ for our person records vocabulary. The following application
+ recreates the content of the original <code>people.xml</code>
+ file:</p>
+
+ <pre class="c++">
+#include &lt;iostream>
+
+#include "people.hxx"
+#include "people-simpl.hxx"
+
+using namespace std;
+
+int
+main ()
+{
+ people ppl;
+ people::person_sequence&amp; ps = ppl.person ();
+
+ // John
+ //
+ {
+ person p;
+ p.first_name ("John");
+ p.last_name ("Doe");
+ p.age (32);
+ p.id (1);
+
+ gender g;
+ g.assign ("male");
+ p.gender (g);
+
+ ps.push_back (p);
+ }
+
+ // Jane
+ //
+ {
+ person p;
+ p.first_name ("Jane");
+ p.middle_name ("Mary");
+ p.last_name ("Doe");
+ p.age (28);
+ p.id (2);
+
+ gender g;
+ g.assign ("male");
+ p.gender (g);
+
+ ps.push_back (p);
+ }
+
+ // Serialize the object model to XML.
+ //
+ people_saggr people_s;
+ xml_schema::document_simpl doc_s (people_s.root_serializer (),
+ people_s.root_name ());
+ people_s.pre (ppl);
+ doc_s.serialize (cout);
+ people_s.post ();
+}
+ </pre>
+
+ <p>The only new part in the above application is the calls
+ to the <code>people</code> and <code>person</code>
+ constructors. As a general rule, a newly created instance
+ does not assign any values to its elements and attributes.
+ That is, members with the <em>one</em> cardinality
+ class are left uninitialized, members with the <em>optional</em>
+ cardinality class are set to the "not present" state,
+ and members with the <em>sequence</em> cardinality class
+ have empty containers. After the instance has been
+ created, we can set its element and attribute values
+ using the modifier functions.</p>
+
+ <p>The above application produces the following output:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0" ?>
+&lt;people>
+
+ &lt;person id="1">
+ &lt;first-name>John&lt;/first-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>male&lt;/gender>
+ &lt;age>32&lt;/age>
+ &lt;/person>
+
+ &lt;person id="2">
+ &lt;first-name>Jane&lt;/first-name>
+ &lt;middle-name>Mary&lt;/middle-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>female&lt;/gender>
+ &lt;age>28&lt;/age>
+ &lt;/person>
+
+&lt;/people>
+ </pre>
+
+ <h2><a name="4.8">4.8 Customizing the Object Model</a></h2>
+
+ <p>Sometimes it is desirable to be able to store extra,
+ application-specific data in some object model classes or
+ nested compositor classes. Cases where this functionality
+ may be required include handling of typeless content
+ matched by XML Schema wildcards as well as a need for
+ an application to pass extra data as part of the object
+ model. The C++/Hybrid mapping provides a light-weight
+ mechanism for storing custom data by allowing you to add
+ a sequence of opaque objects, stored as <code>void*</code>,
+ to select generated classes. It is also possible to
+ customize the parsing and serialization code for such
+ classes in order to populate the custom data sequence
+ during parsing and later serialize it to XML. See
+ <a href="#6.1">Section 6.1, "Customizing Parsers and
+ Serializers"</a> for details.</p>
+
+ <p>To instruct the XSD/e compiler to include custom data
+ in a specific object model class, we need to use the
+ <code>--custom-data</code> option with the corresponding
+ XML Schema type name as its argument. To include custom
+ data into a nested compositor class, use its qualified
+ name starting with the XML Schema type, for example
+ <code>type::sequence1</code>. If we would like to
+ add the ability to store custom data in the generated
+ <code>person</code> class for our person records
+ vocabulary, we can compile <code>people.xsd</code>
+ like this:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --custom-type person people.xsd
+ </pre>
+
+ <p>The resulting <code>person</code> class will have the
+ following extra set of type definitions and functions:</p>
+
+
+ <pre class="c++">
+// person (variable-length)
+//
+class person
+{
+public:
+
+ ...
+
+ // Custom data.
+ //
+ typedef xsde::data_sequence custom_data_sequence;
+ typedef custom_data_sequence::iterator custom_data_iterator;
+ typedef custom_data_sequence::const_iterator custom_data_const_iterator;
+
+ const custom_data_sequence&amp;
+ custom_data () const;
+
+ custom_data_sequence&amp;
+ custom_data ();
+};
+ </pre>
+
+ <p>Notice also that the <code>person</code> class is now variable-length
+ since it contains a sequence. When C++ exceptions are enabled, the
+ custom data sequence has the following interface:</p>
+
+ <pre class="c++">
+class data_sequence
+{
+public:
+ typedef void* value_type;
+ typedef void** pointer;
+ typedef const void** const_pointer;
+ typedef void* reference;
+ typedef const void* const_reference;
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ typedef void** iterator;
+ typedef const void* const* const_iterator;
+
+ typedef void (*destroy_func) (void* data, size_t pos);
+
+public:
+ data_sequence ();
+
+ void
+ destructor (destroy_func);
+
+ void
+ swap (data_sequence&amp;);
+
+private:
+ data_sequence (const data_sequence&amp;);
+
+ data_sequence&amp;
+ operator= (data_sequence&amp;);
+
+public:
+ iterator
+ begin ();
+
+ const_iterator
+ begin () const;
+
+ iterator
+ end ();
+
+ const_iterator
+ end () const;
+
+ void*
+ front ();
+
+ const void*
+ front () const;
+
+ void*
+ back ();
+
+ const void*
+ back () const;
+
+ void*
+ operator[] (size_t);
+
+ const void*
+ operator[] (size_t) const;
+
+public:
+ bool
+ empty () const;
+
+ size_t
+ size () const;
+
+ size_t
+ capacity () const;
+
+ size_t
+ max_size () const;
+
+public:
+ void
+ clear ();
+
+ void
+ pop_back ();
+
+ iterator
+ erase (iterator);
+
+ void
+ push_back (void*);
+
+ iterator
+ insert (iterator, void*);
+
+ void
+ reserve (size_t);
+};
+ </pre>
+
+ <p>The <code>destructor()</code> modifier allows you to specify
+ the clean up function used to free the sequence elements.
+ The second argument in this clean up function is the position
+ of the element in the sequence that is being freed. This allows
+ you to store objects of different types in the same custom
+ data sequence. The <code>push_back()</code> and <code>insert()</code>
+ functions free the passed object if the reallocation of the
+ underlying sequence buffer fails.</p>
+
+ <p>When exceptions are disabled, the <code>push_back()</code>,
+ <code>insert()</code>, and <code>reserve()</code> functions
+ return an error code to signal the out of memory condition:</p>
+
+ <pre class="c++">
+class data_sequence
+{
+public:
+ enum error
+ {
+ error_none,
+ error_no_memory
+ };
+
+ ...
+
+public:
+ error
+ push_back (void*);
+
+ error
+ insert (iterator, void*);
+
+ error
+ insert (iterator, void*, iterator&amp; result);
+
+ error
+ reserve (size_t);
+};
+ </pre>
+
+ <p>The following code fragment shows how we can store and retrieve
+ custom data in the <code>person</code> class:</p>
+
+ <pre class="c++">
+class data
+{
+ ...
+};
+
+void
+destroy_data (void* p, size_t)
+{
+ delete static_cast&lt;data*> (p);
+}
+
+person&amp; = ...;
+person::custom_data_sequence&amp; cd = p.custom_data ();
+
+cd.destructor (&amp;destroy_data);
+
+// Store.
+//
+data* d = new data;
+cd.push_back (d);
+
+// Retrieve.
+//
+for (person::custom_data_iterator i = cd.begin (); i != cd.end (); ++i)
+{
+ data* d = static_cast&lt;data*> (*i);
+}
+ </pre>
+
+
+ <!-- Built-in XML Schema Type Parsers -->
+
+
+ <h1><a name="5">5 Mapping for Built-In XML Schema Types</a></h1>
+
+ <p>In XML Schema, built-in types, such as <code>int</code>,
+ <code>string</code>, etc., are defined in the XML Schema namespace.
+ By default this namespace is mapped to C++ namespace
+ <code>xml_schema</code> (this mapping can be altered
+ with the <code>--namespace-map</code> option). The following table
+ summarizes the mapping of XML Schema built-in types to C++ types
+ in the C++/Hybrid mapping. Declarations for these types are
+ automatically included into each generated header file.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="builtin" border="1">
+ <tr>
+ <th>XML Schema type</th>
+ <th>Alias in the <code>xml_schema</code> namespace</th>
+ <th>C++ type</th>
+ </tr>
+
+ <tr>
+ <th colspan="3">fixed-length integral types</th>
+ </tr>
+ <!-- 8-bit -->
+ <tr>
+ <td><code>byte</code></td>
+ <td><code>byte</code></td>
+ <td><code>signed&nbsp;char</code></td>
+ </tr>
+ <tr>
+ <td><code>unsignedByte</code></td>
+ <td><code>unsigned_byte</code></td>
+ <td><code>unsigned&nbsp;char</code></td>
+ </tr>
+
+ <!-- 16-bit -->
+ <tr>
+ <td><code>short</code></td>
+ <td><code>short_</code></td>
+ <td><code>short</code></td>
+ </tr>
+ <tr>
+ <td><code>unsignedShort</code></td>
+ <td><code>unsigned_short</code></td>
+ <td><code>unsigned&nbsp;short</code></td>
+ </tr>
+
+ <!-- 32-bit -->
+ <tr>
+ <td><code>int</code></td>
+ <td><code>int_</code></td>
+ <td><code>int</code></td>
+ </tr>
+ <tr>
+ <td><code>unsignedInt</code></td>
+ <td><code>unsigned_int</code></td>
+ <td><code>unsigned&nbsp;int</code></td>
+ </tr>
+
+ <!-- 64-bit -->
+ <tr>
+ <td><code>long</code></td>
+ <td><code>long_</code></td>
+ <td><code>long</code> or<br/> <code>long&nbsp;long</code><br/>
+ <a href="#3.5">Section 3.5, "64-bit Integer Type"</a></td>
+ </tr>
+ <tr>
+ <td><code>unsignedLong</code></td>
+ <td><code>unsigned_long</code></td>
+ <td><code>unsigned&nbsp;long</code> or
+ <code>unsigned&nbsp;long&nbsp;long</code><br/>
+ <a href="#3.5">Section 3.5, "64-bit Integer Type"</a></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">arbitrary-length integral types</th>
+ </tr>
+ <tr>
+ <td><code>integer</code></td>
+ <td><code>integer</code></td>
+ <td><code>long</code></td>
+ </tr>
+ <tr>
+ <td><code>nonPositiveInteger</code></td>
+ <td><code>non_positive_integer</code></td>
+ <td><code>long</code></td>
+ </tr>
+ <tr>
+ <td><code>nonNegativeInteger</code></td>
+ <td><code>non_negative_integer</code></td>
+ <td><code>unsigned long</code></td>
+ </tr>
+ <tr>
+ <td><code>positiveInteger</code></td>
+ <td><code>positive_integer</code></td>
+ <td><code>unsigned long</code></td>
+ </tr>
+ <tr>
+ <td><code>negativeInteger</code></td>
+ <td><code>negative_integer</code></td>
+ <td><code>long</code></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">boolean types</th>
+ </tr>
+ <tr>
+ <td><code>boolean</code></td>
+ <td><code>boolean</code></td>
+ <td><code>bool</code></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">fixed-precision floating-point types</th>
+ </tr>
+ <tr>
+ <td><code>float</code></td>
+ <td><code>float_</code></td>
+ <td><code>float</code></td>
+ </tr>
+ <tr>
+ <td><code>double</code></td>
+ <td><code>double_</code></td>
+ <td><code>double</code></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">arbitrary-precision floating-point types</th>
+ </tr>
+ <tr>
+ <td><code>decimal</code></td>
+ <td><code>decimal</code></td>
+ <td><code>double</code></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">string types</th>
+ </tr>
+ <tr>
+ <td><code>string</code></td>
+ <td><code>string</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>normalizedString</code></td>
+ <td><code>normalized_string</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>token</code></td>
+ <td><code>token</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>Name</code></td>
+ <td><code>name</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>NMTOKEN</code></td>
+ <td><code>nmtoken</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>NMTOKENS</code></td>
+ <td><code>nmtokens</code></td>
+ <td><a href="#5.2">Section 5.2, "Mapping for <code>NMTOKENS</code> and <code>IDREFS</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>NCName</code></td>
+ <td><code>ncname</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>language</code></td>
+ <td><code>language</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">qualified name</th>
+ </tr>
+ <tr>
+ <td><code>QName</code></td>
+ <td><code>qname</code></td>
+ <td><a href="#5.1">Section 5.1, "Mapping for <code>QName</code>"</a></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">ID/IDREF types</th>
+ </tr>
+ <tr>
+ <td><code>ID</code></td>
+ <td><code>id</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>IDREF</code></td>
+ <td><code>idref</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+ <tr>
+ <td><code>IDREFS</code></td>
+ <td><code>idrefs</code></td>
+ <td><a href="#5.2">Section 5.2, "Mapping for <code>NMTOKENS</code> and <code>IDREFS</code>"</a></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">URI types</th>
+ </tr>
+ <tr>
+ <td><code>anyURI</code></td>
+ <td><code>uri</code></td>
+ <td><code>std::string</code> or <code>char*</code><br/>
+ <a href="#3.1">Section 3.1, "Standard Template Library"</a></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">binary types</th>
+ </tr>
+ <tr>
+ <td><code>base64Binary</code></td>
+ <td><code>base64_binary</code></td>
+ <td><a href="#5.3">Section 5.3, "Mapping for <code>base64Binary</code> and <code>hexBinary</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>hexBinary</code></td>
+ <td><code>hex_binary</code></td>
+ <td><a href="#5.3">Section 5.3, "Mapping for <code>base64Binary</code> and <code>hexBinary</code>"</a></td>
+ </tr>
+
+ <tr>
+ <th colspan="3">date/time types</th>
+ </tr>
+ <tr>
+ <td><code>date</code></td>
+ <td><code>date</code></td>
+ <td><a href="#5.5">Section 5.5, "Mapping for <code>date</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>dateTime</code></td>
+ <td><code>date_time</code></td>
+ <td><a href="#5.6">Section 5.6, "Mapping for <code>dateTime</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>duration</code></td>
+ <td><code>duration</code></td>
+ <td><a href="#5.7">Section 5.7, "Mapping for <code>duration</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>gDay</code></td>
+ <td><code>gday</code></td>
+ <td><a href="#5.8">Section 5.8, "Mapping for <code>gDay</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>gMonth</code></td>
+ <td><code>gmonth</code></td>
+ <td><a href="#5.9">Section 5.9, "Mapping for <code>gMonth</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>gMonthDay</code></td>
+ <td><code>gmonth_day</code></td>
+ <td><a href="#5.10">Section 5.10, "Mapping for <code>gMonthDay</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>gYear</code></td>
+ <td><code>gyear</code></td>
+ <td><a href="#5.11">Section 5.11, "Mapping for <code>gYear</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>gYearMonth</code></td>
+ <td><code>gyear_month</code></td>
+ <td><a href="#5.12">Section 5.12, "Mapping for <code>gYearMonth</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>time</code></td>
+ <td><code>time</code></td>
+ <td><a href="#5.13">Section 5.13, "Mapping for <code>time</code>"</a></td>
+ </tr>
+ </table>
+
+ <p>As you can see from the table above a number of built-in
+ XML Schema types are mapped to fundamental C++ types such
+ as <code>int</code> or <code>bool</code>. All string-based
+ XML Schema types are mapped to either <code>std::string</code>
+ or <code>char*</code>, depending on whether the use of STL is
+ enabled or not. A number of built-in types, such as
+ <code>QName</code>, the binary types, and the date/time types,
+ do not have suitable fundamental or standard C++ types to map to.
+ These types are implemented from scratch in the XSD/e runtime
+ and are discussed in more detail in the subsequent sections.</p>
+
+ <p>In cases where the schema calls for an inheritance from a built-in
+ type which is mapped to a fundamental C++ type, a special base
+ type corresponding to the fundamental type and defined in the
+ <code>xml_schema</code> namespace is used (C++ does not allow
+ inheritance from fundamental types). For example:</p>
+
+ <pre class="xml">
+&lt;complexType name="measure">
+ &lt;simpleContent>
+ &lt;extension base="int">
+ &lt;attribute name="unit" type="string" use="required"/>
+ &lt;/extension>
+ &lt;/simpleContent>
+&lt;/complexType>
+ </pre>
+
+ <p>The corresponding object model class is shown below:</p>
+
+ <pre class="c++">
+// measure (fixed-length)
+//
+class measure: public xml_schema::int_base
+{
+public:
+ measure ();
+ measure (const measure&amp;);
+ measure&amp; operator= (const measure&amp;);
+
+ // unit
+ //
+ const std::string&amp;
+ unit () const;
+
+ std::string&amp;
+ unit ();
+
+ void
+ unit (const std::string&amp;);
+
+private:
+ ...
+};
+ </pre>
+
+ <p>The <code>xml_schema::int_base</code> class has the following
+ interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class int_base
+ {
+ public:
+ int_base ();
+
+ int_base&amp;
+ operator= (int);
+
+ public:
+ int
+ base_value () const;
+
+ int&amp;
+ base_value ();
+
+ void
+ base_value (int);
+
+ operator const int&amp; () const;
+ operator int&amp; ();
+ };
+}
+ </pre>
+
+ <p>All other base types for fundamental C++ types have similar
+ interfaces. The only exception is the base type for string
+ types when STL is disabled:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class string_base
+ {
+ public:
+ string_base ();
+
+ string_base&amp;
+ operator= (char* x)
+
+ public:
+ const char*
+ base_value () const;
+
+ char*
+ base_value ();
+
+ void
+ base_value (char* x);
+
+ operator const char* () const;
+ operator char* ();
+ };
+}
+ </pre>
+
+ <p>Note that the <code>string_base</code> object assumes ownership
+ of the strings passed to the assignment operator and the
+ <code>base_value()</code> modifier.</p>
+
+ <h2><a name="5.1">5.1 Mapping for <code>QName</code></a></h2>
+
+ <p>The <code>QName</code> built-in XML Schema type is mapped to the
+ <code>qname</code> class which represents an XML qualified name.
+ With STL enabled (<a href="#3.1">Section 3.1, "Standard Template
+ Library"</a>), it has the following interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class qname
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ qname ();
+
+ explicit
+ qname (const std::string&amp; name);
+ qname (const std::string&amp; prefix, const std::string&amp; name);
+
+ void
+ swap (qname&amp;);
+
+ const std::string&amp;
+ prefix () const;
+
+ std::string&amp;
+ prefix ();
+
+ void
+ prefix (const std::string&amp;);
+
+ const std::string&amp;
+ name () const;
+
+ std::string&amp;
+ name ();
+
+ void
+ name (const std::string&amp;);
+ };
+
+ bool
+ operator== (const qname&amp;, const qname&amp;);
+
+ bool
+ operator!= (const qname&amp;, const qname&amp;);
+}
+ </pre>
+
+ <p>When STL is disabled and C++ exceptions are enabled
+ (<a href="#3.3">Section 3.3, "C++ Exceptions"</a>), the
+ <code>qname</code> type has the following interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class qname
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ qname ();
+
+ explicit
+ qname (char* name);
+ qname (char* prefix, char* name);
+
+ void
+ swap (qname&amp;);
+
+ private:
+ qname (const qname&amp;);
+
+ qname&amp;
+ operator= (const qname&amp;);
+
+ public:
+ char*
+ prefix ();
+
+ const char*
+ prefix () const;
+
+ void
+ prefix (char*);
+
+ void
+ prefix_copy (const char*);
+
+ char*
+ prefix_detach ();
+
+ public:
+ char*
+ name ();
+
+ const char*
+ name () const;
+
+ void
+ name (char*);
+
+ void
+ name_copy (const char*);
+
+ char*
+ name_detach ();
+ };
+
+ bool
+ operator== (const qname&amp;, const qname&amp;);
+
+ bool
+ operator!= (const qname&amp;, const qname&amp;);
+}
+</pre>
+
+ <p>The modifier functions and constructors that have the <code>char*</code>
+ argument assume ownership of the passed strings which should be allocated
+ with operator <code>new char[]</code> and will be deallocated with
+ operator <code>delete[]</code> by the <code>qname</code> object.
+ If you detach the underlying prefix or name strings, then they
+ should eventually be deallocated with operator <code>delete[]</code>.
+ </p>
+
+ <p>Finally, if both STL and C++ exceptions are disabled, the
+ <code>qname</code> type has the following interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class qname
+ {
+ public:
+ enum error
+ {
+ error_none,
+ error_no_memory
+ };
+
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ qname ();
+
+ explicit
+ qname (char* name);
+ qname (char* prefix, char* name);
+
+ void
+ swap (qname&amp;);
+
+ private:
+ qname (const qname&amp;);
+
+ qname&amp;
+ operator= (const qname&amp;);
+
+ public:
+ char*
+ prefix ();
+
+ const char*
+ prefix () const;
+
+ void
+ prefix (char*);
+
+ error
+ prefix_copy (const char*);
+
+ char*
+ prefix_detach ();
+
+ public:
+ char*
+ name ();
+
+ const char*
+ name () const;
+
+ void
+ name (char*);
+
+ error
+ name_copy (const char*);
+
+ char*
+ name_detach ();
+ };
+
+ bool
+ operator== (const qname&amp;, const qname&amp;);
+
+ bool
+ operator!= (const qname&amp;, const qname&amp;);
+}
+ </pre>
+
+ <h2><a name="5.2">5.2 Mapping for <code>NMTOKENS</code> and <code>IDREFS</code></a></h2>
+
+ <p>The <code>NMTOKENS</code> and <code>IDREFS</code> built-in
+ XML Schema types are mapped to the string sequence type which
+ is discussed in <a href="#4.3">Section 4.3, "Attributes and
+ Elements"</a>.</p>
+
+ <h2><a name="5.3">5.3 Mapping for <code>base64Binary</code> and <code>hexBinary</code></a></h2>
+
+ <p>The <code>base64Binary</code> and <code>hexBinary</code> built-in
+ XML Schema types are mapped to the <code>buffer</code> class.
+ With C++ exceptions enabled (<a href="#3.3">Section 3.3, "C++
+ Exceptions"</a>), it has the following interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class buffer
+ {
+ public:
+ class bounds {}; // Out of bounds exception.
+
+ public:
+ buffer ();
+
+ explicit
+ buffer (size_t size);
+ buffer (size_t size, size_t capacity);
+ buffer (const void* data, size_t size);
+ buffer (const void* data, size_t size, size_t capacity);
+
+ enum ownership_value { assume_ownership };
+
+ // This constructor assumes ownership of the memory passed.
+ //
+ buffer (void* data, size_t size, size_t capacity, ownership_value);
+
+ private:
+ buffer (const buffer&amp;);
+
+ buffer&amp;
+ operator= (const buffer&amp;);
+
+ public:
+ void
+ attach (void* data, size_t size, size_t capacity);
+
+ void*
+ detach ();
+
+ void
+ swap (buffer&amp;);
+
+ public:
+ size_t
+ capacity () const;
+
+ bool
+ capacity (size_t);
+
+ public:
+ size_t
+ size () const;
+
+ bool
+ size (size_t);
+
+ public:
+ const char*
+ data () const;
+
+ char*
+ data ();
+
+ const char*
+ begin () const;
+
+ char*
+ begin ();
+
+ const char*
+ end () const;
+
+ char*
+ end ();
+ };
+
+ bool
+ operator== (const buffer&amp;, const buffer&amp;);
+
+ bool
+ operator!= (const buffer&amp;, const buffer&amp;);
+}
+ </pre>
+
+ <p>The last constructor and the <code>attach()</code> member function
+ make the <code>buffer</code> instance assume the ownership of the
+ memory block pointed to by the <code>data</code> argument and
+ eventually release it by calling <code>operator delete()</code>.
+ The <code>detach()</code> member function detaches and returns the
+ underlying memory block which should eventually be released by
+ calling <code>operator delete()</code>.
+ </p>
+
+ <p>The <code>capacity()</code> and <code>size()</code> modifier functions
+ return <code>true</code> if the underlying buffer has moved. The
+ <code>bounds</code> exception is thrown if the constructor or
+ <code>attach()</code> member function arguments violate the
+ <code>(size&nbsp;&lt;=&nbsp;capacity)</code> constraint.</p>
+
+ <p>If C++ exceptions are disabled, the <code>buffer</code> class has
+ the following interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class buffer
+ {
+ public:
+ enum error
+ {
+ error_none,
+ error_bounds,
+ error_no_memory
+ };
+
+ buffer ();
+
+ private:
+ buffer (const buffer&amp;);
+
+ buffer&amp;
+ operator= (const buffer&amp;);
+
+ public:
+ error
+ attach (void* data, size_t size, size_t capacity);
+
+ void*
+ detach ();
+
+ void
+ swap (buffer&amp;);
+
+ public:
+ size_t
+ capacity () const;
+
+ error
+ capacity (size_t);
+
+ error
+ capacity (size_t, bool&amp; moved);
+
+ public:
+ size_t
+ size () const;
+
+ error
+ size (size_t);
+
+ error
+ size (size_t, bool&amp; moved);
+
+ public:
+ const char*
+ data () const;
+
+ char*
+ data ();
+
+ const char*
+ begin () const;
+
+ char*
+ begin ();
+
+ const char*
+ end () const;
+
+ char*
+ end ();
+ };
+
+ bool
+ operator== (const buffer&amp;, const buffer&amp;);
+
+ bool
+ operator!= (const buffer&amp;, const buffer&amp;);
+}
+ </pre>
+
+ <h2><a name="5.4">5.4 Time Zone Representation</a></h2>
+
+ <p>The <code>date</code>, <code>dateTime</code>, <code>gDay</code>,
+ <code>gMonth</code>, <code>gMonthDay</code>, <code>gYear</code>,
+ <code>gYearMonth</code>, and <code>time</code> XML Schema built-in
+ types all include an optional time zone component. The following
+ <code>time_zone</code> base class is used to represent this
+ information:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class time_zone
+ {
+ public:
+ time_zone ();
+ time_zone (short hours, short minutes);
+
+ bool
+ zone_present () const;
+
+ void
+ zone_reset ();
+
+ short
+ zone_hours () const;
+
+ void
+ zone_hours (short);
+
+ short
+ zone_minutes () const;
+
+ void
+ zone_minutes (short);
+ };
+
+ bool
+ operator== (const time_zone&amp;, const time_zone&amp;);
+
+ bool
+ operator!= (const time_zone&amp;, const time_zone&amp;);
+}
+ </pre>
+
+ <p>The <code>zone_present()</code> accessor function returns <code>true</code>
+ if the time zone is specified. The <code>zone_reset()</code> modifier
+ function resets the time zone object to the "not specified"
+ state. If the time zone offset is negative then both hours and
+ minutes components should be negative.</p>
+
+ <h2><a name="5.5">5.5 Mapping for <code>date</code></a></h2>
+
+ <p>The <code>date</code> built-in XML Schema type is mapped to the
+ <code>date</code> class which represents a year, a day, and a month
+ with an optional time zone. Its interface is presented below. For
+ more information on the base <code>xml_schema::time_zone</code>
+ class refer to <a href="#5.4">Section 5.4, "Time Zone
+ Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class date: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ date ();
+
+ date (int year, unsigned short month, unsigned short day);
+
+ date (int year, unsigned short month, unsigned short day,
+ short zone_hours, short zone_minutes);
+
+ int
+ year () const;
+
+ void
+ year (int);
+
+ unsigned short
+ month () const;
+
+ void
+ month (unsigned short);
+
+ unsigned short
+ day () const;
+
+ void
+ day (unsigned short);
+ };
+
+ bool
+ operator== (const date&amp;, const date&amp;);
+
+ bool
+ operator!= (const date&amp;, const date&amp;);
+}
+ </pre>
+
+ <h2><a name="5.6">5.6 Mapping for <code>dateTime</code></a></h2>
+
+ <p>The <code>dateTime</code> built-in XML Schema type is mapped to the
+ <code>date_time</code> class which represents a year, a month, a day,
+ hours, minutes, and seconds with an optional time zone. Its interface
+ is presented below. For more information on the base
+ <code>xml_schema::time_zone</code> class refer to <a href="#5.4">Section
+ 5.4, "Time Zone Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class date_time: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ date_time ();
+
+ date_time (int year, unsigned short month, unsigned short day,
+ unsigned short hours, unsigned short minutes,
+ double seconds);
+
+ date_time (int year, unsigned short month, unsigned short day,
+ unsigned short hours, unsigned short minutes,
+ double seconds, short zone_hours, short zone_minutes);
+
+ int
+ year () const;
+
+ void
+ year (int);
+
+ unsigned short
+ month () const;
+
+ void
+ month (unsigned short);
+
+ unsigned short
+ day () const;
+
+ void
+ day (unsigned short);
+
+ unsigned short
+ hours () const;
+
+ void
+ hours (unsigned short);
+
+ unsigned short
+ minutes () const;
+
+ void
+ minutes (unsigned short);
+
+ double
+ seconds () const;
+
+ void
+ seconds (double);
+ };
+
+ bool
+ operator== (const date_time&amp;, const date_time&amp;);
+
+ bool
+ operator!= (const date_time&amp;, const date_time&amp;);
+}
+ </pre>
+
+ <h2><a name="5.7">5.7 Mapping for <code>duration</code></a></h2>
+
+ <p>The <code>duration</code> built-in XML Schema type is mapped to the
+ <code>duration</code> class which represents a potentially
+ negative duration in the form of years, months, days, hours, minutes,
+ and seconds. Its interface is presented below.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class duration
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ duration ();
+
+ duration (bool negative,
+ unsigned int years, unsigned int months, unsigned int days,
+ unsigned int hours, unsigned int minutes, double seconds);
+
+ bool
+ negative () const;
+
+ void
+ negative (bool);
+
+ unsigned int
+ years () const;
+
+ void
+ years (unsigned int);
+
+ unsigned int
+ months () const;
+
+ void
+ months (unsigned int);
+
+ unsigned int
+ days () const;
+
+ void
+ days (unsigned int);
+
+ unsigned int
+ hours () const;
+
+ void
+ hours (unsigned int);
+
+ unsigned int
+ minutes () const;
+
+ void
+ minutes (unsigned int);
+
+ double
+ seconds () const;
+
+ void
+ seconds (double);
+ };
+
+ bool
+ operator== (const duration&amp;, const duration&amp;);
+
+ bool
+ operator!= (const duration&amp;, const duration&amp;);
+}
+ </pre>
+
+
+ <h2><a name="5.8">5.8 Mapping for <code>gDay</code></a></h2>
+
+ <p>The <code>gDay</code> built-in XML Schema type is mapped to the
+ <code>gday</code> class which represents a day of the month with
+ an optional time zone. Its interface is presented below. For
+ more information on the base <code>xml_schema::time_zone</code>
+ class refer to <a href="#5.4">Section 5.4, "Time Zone
+ Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class gday: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ gday ();
+
+ explicit
+ gday (unsigned short day);
+
+ gday (unsigned short day, short zone_hours, short zone_minutes);
+
+ unsigned short
+ day () const;
+
+ void
+ day (unsigned short);
+ };
+
+ bool
+ operator== (const gday&amp;, const gday&amp;);
+
+ bool
+ operator!= (const gday&amp;, const gday&amp;);
+}
+ </pre>
+
+ <h2><a name="5.9">5.9 Mapping for <code>gMonth</code></a></h2>
+
+ <p>The <code>gMonth</code> built-in XML Schema type is mapped to the
+ <code>gmonth</code> class which represents a month of the year
+ with an optional time zone. Its interface is presented below. For
+ more information on the base <code>xml_schema::time_zone</code>
+ class refer to <a href="#5.4">Section 5.4, "Time Zone
+ Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class gmonth: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ gmonth ();
+
+ explicit
+ gmonth (unsigned short month);
+
+ gmonth (unsigned short month,
+ short zone_hours, short zone_minutes);
+
+ unsigned short
+ month () const;
+
+ void
+ month (unsigned short);
+ };
+
+ bool
+ operator== (const gmonth&amp;, const gmonth&amp;);
+
+ bool
+ operator!= (const gmonth&amp;, const gmonth&amp;);
+}
+ </pre>
+
+ <h2><a name="5.10">5.10 Mapping for <code>gMonthDay</code></a></h2>
+
+ <p>The <code>gMonthDay</code> built-in XML Schema type is mapped to the
+ <code>gmonth_day</code> class which represents a day and a month of
+ the year with an optional time zone. Its interface is presented below.
+ For more information on the base <code>xml_schema::time_zone</code>
+ class refer to <a href="#5.4">Section 5.4, "Time Zone
+ Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class gmonth_day: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ gmonth_day ();
+
+ gmonth_day (unsigned short month, unsigned short day);
+
+ gmonth_day (unsigned short month, unsigned short day,
+ short zone_hours, short zone_minutes);
+
+ unsigned short
+ month () const;
+
+ void
+ month (unsigned short);
+
+ unsigned short
+ day () const;
+
+ void
+ day (unsigned short);
+ };
+
+ bool
+ operator== (const gmonth_day&amp;, const gmonth_day&amp;);
+
+ bool
+ operator!= (const gmonth_day&amp;, const gmonth_day&amp;);
+}
+ </pre>
+
+ <h2><a name="5.11">5.11 Mapping for <code>gYear</code></a></h2>
+
+ <p>The <code>gYear</code> built-in XML Schema type is mapped to the
+ <code>gyear</code> class which represents a year with
+ an optional time zone. Its interface is presented below.
+ For more information on the base <code>xml_schema::time_zone</code>
+ class refer to <a href="#5.4">Section 5.4, "Time Zone
+ Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class gyear: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ gyear ();
+
+ explicit
+ gyear (int year);
+
+ gyear (int year, short zone_hours, short zone_minutes);
+
+ int
+ year () const;
+
+ void
+ year (int);
+ };
+
+ bool
+ operator== (const gyear&amp;, const gyear&amp;);
+
+ bool
+ operator!= (const gyear&amp;, const gyear&amp;);
+}
+ </pre>
+
+ <h2><a name="5.12">5.12 Mapping for <code>gYearMonth</code></a></h2>
+
+ <p>The <code>gYearMonth</code> built-in XML Schema type is mapped to the
+ <code>gyear_month</code> class which represents a year and a month
+ with an optional time zone. Its interface is presented below.
+ For more information on the base <code>xml_schema::time_zone</code>
+ class refer to <a href="#5.4">Section 5.4, "Time Zone
+ Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class gyear_month: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ gyear_month ();
+
+ gyear_month (int year, unsigned short month);
+
+ gyear_month (int year, unsigned short month,
+ short zone_hours, short zone_minutes);
+
+ int
+ year () const;
+
+ void
+ year (int);
+
+ unsigned short
+ month () const;
+
+ void
+ month (unsigned short);
+ };
+
+ bool
+ operator== (const gyear_month&amp;, const gyear_month&amp;);
+
+ bool
+ operator!= (const gyear_month&amp;, const gyear_month&amp;);
+}
+ </pre>
+
+
+ <h2><a name="5.13">5.13 Mapping for <code>time</code></a></h2>
+
+ <p>The <code>time</code> built-in XML Schema type is mapped to the
+ <code>time</code> class which represents hours, minutes,
+ and seconds with an optional time zone. Its interface is presented below.
+ For more information on the base <code>xml_schema::time_zone</code>
+ class refer to <a href="#5.4">Section 5.4, "Time Zone
+ Representation"</a>.</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class time: public time_zone
+ {
+ public:
+ // The default constructor creates an uninitialized object.
+ // Use modifiers to initialize it.
+ //
+ time ();
+
+ time (unsigned short hours, unsigned short minutes, double seconds);
+
+ time (unsigned short hours, unsigned short minutes, double seconds,
+ short zone_hours, short zone_minutes);
+
+ unsigned short
+ hours () const;
+
+ void
+ hours (unsigned short);
+
+ unsigned short
+ minutes () const;
+
+ void
+ minutes (unsigned short);
+
+ double
+ seconds () const;
+
+ void
+ seconds (double);
+ };
+
+ bool
+ operator== (const time&amp;, const time&amp;);
+
+ bool
+ operator!= (const time&amp;, const time&amp;);
+}
+ </pre>
+
+ <!-- Parsing and Serialization -->
+
+ <h1><a name="6">6 Parsing and Serialization</a></h1>
+
+ <p>As was mentioned in the introduction, the C++/Hybrid mapping
+ uses the C++/Parser and C++/Serializer mappings for XML parsing
+ and serialization. If your parsing and serialization requirements
+ are fairly basic, for example, parsing from and serializing to
+ a file or a memory buffer, then you don't need to concern yourself
+ with these two underlying mappings. On the other hand, the C++/Parser
+ and C++/Serializer mappings provide well-defined APIs which allow
+ a great amount of flexibility that may be useful in certain situations.
+ In such cases, you may need to get an understanding of how the
+ C++/Parser and C++/Serializer mappings work. See the
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml">Embedded
+ C++/Parser Mapping Getting Started Guide</a> and the
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml">Embedded
+ C++/Serializer Mapping Getting Started Guide</a> for more detailed
+ information on these mappings.</p>
+
+ <p>For each type defined in XML Schema, the C++/Parser and
+ C++/Serializer mappings generate a parser skeleton class and
+ serializer skeleton class, respectively. These classes manage
+ parsing/serialization state, convert data between text
+ and C++ types, and perform XML Schema validation, if enabled.
+ Parser skeletons deliver the parsed data and serializer
+ skeletons request the data to be serialized with callbacks.
+ These callbacks are implemented by parser and serializer
+ implementation classes that are derived from the skeletons.
+ If the application uses the C++/Parser and C++/Serializer
+ mappings directly, these implementation classes are normally
+ written by the application developer to perform some
+ application-specific actions. In case of the C++/Hybrid mapping,
+ these implementations are automatically generated by the XSD/e
+ compiler to parse XML to object models and to serialize object
+ models to XML.
+ To request the generation of parser skeletons and
+ implementations, you need to specify the <code>--generate-parser</code>
+ XSD/e command line option. Similarly, to generate serializer
+ skeletons and implementations, you will need to use the
+ <code>--generate-serializer</code> option.</p>
+
+ <p>Before an XML document can be parsed or serialized, the
+ individual parser and serializer implementations need to
+ be instantiated and connected to each other. Again, if the
+ application uses the C++/Parser and C++/Serializer mappings
+ directly, this is done by the application developer. While
+ you can also do this with the generated C++/Hybrid parser and
+ serializer implementations, it is easier to request the
+ generation of parser and serializer aggregate classes with
+ the <code>--generate-aggregate</code> options. Aggregate
+ classes instantiate and connect all the necessary individual
+ parser and serializer implementations for a particular root
+ element or type. Consider again the <code>hello.xsd</code>
+ schema from <a href="#2">Chapter 2, "Hello World Example"</a>:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0"?>
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="hello">
+ &lt;xs:sequence>
+ &lt;xs:element name="greeting" type="xs:string"/>
+ &lt;xs:element name="name" type="xs:string" maxOccurs="unbounded"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="hello" type="hello"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>If we compile this schema with the <code>--generate-parser</code>,
+ <code>--generate-serializer</code>, and <code>--generate-aggregate</code>
+ options, we will have two aggregate classes, <code>hello_paggr</code>
+ and <code>hello_saggr</code>, generated for the root <code>hello</code>
+ element. The interface of the <code>hello_paggr</code> class is
+ presented below:</p>
+
+ <pre class="c++">
+class hello_paggr
+{
+public:
+ hello_paggr ();
+
+ void
+ pre ();
+
+ hello*
+ post ();
+
+ hello_pimpl&amp;
+ root_parser ();
+
+ static const char*
+ root_name ();
+
+ static const char*
+ root_namespace ();
+};
+ </pre>
+
+ <p>The <code>pre()</code> and <code>post()</code> functions
+ call the corresponding callbacks on the root parser
+ implementation. The <code>root_parser()</code> function
+ returns the root parser implementation. The <code>root_name()</code>
+ and <code>root_namespace()</code> functions return the
+ root element name and namespace, respectively.</p>
+
+ <p>As was shown in <a href="#2">Chapter 2, "Hello World Example"</a>,
+ we can use this parser aggregate to create the document parser
+ (supplied by the C++/Parser mapping) and perform the parsing:</p>
+
+ <pre class="c++">
+hello_paggr hello_p;
+xml_schema::document_pimpl doc_p (hello_p.root_parser (),
+ hello_p.root_name ());
+hello_p.pre ();
+doc_p.parse ("hello.xml");
+hello* h = hello_p.post ();
+ </pre>
+
+ <p>For more information on the <code>document_pimpl</code> class,
+ including the other variants of the <code>parse()</code> function
+ as well as error handling during parsing, see
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#7">Chapter 7,
+ "Document Parser and Error Handling"</a> in the Embedded C++/Parser
+ Mapping Getting Started Guide.</p>
+
+ <p>The interface of the <code>hello_saggr</code> serializer aggregate
+ mirrors that of <code>hello_paggr</code> and is presented below:</p>
+
+ <pre class="c++">
+class hello_saggr
+{
+public:
+ hello_saggr ();
+
+ void
+ pre (const hello&amp;);
+
+ void
+ post ();
+
+ hello_simpl&amp;
+ root_serializer ();
+
+ static const char*
+ root_name ();
+
+ static const char*
+ root_namespace ();
+};
+ </pre>
+
+ <p>The <code>pre()</code> and <code>post()</code> functions
+ call the corresponding callbacks on the root serializer
+ implementation. The <code>root_serializer()</code> function
+ returns the root serializer implementation. The
+ <code>root_name()</code> and <code>root_namespace()</code>
+ functions return the root element name and namespace,
+ respectively.</p>
+
+ <p>As was shown in <a href="#2">Chapter 2, "Hello World Example"</a>,
+ we can use this serializer aggregate to create the document
+ serializer (supplied by the C++/Serializer mapping) and perform
+ the serialization:</p>
+
+ <pre class="c++">
+hello_saggr hello_s;
+xml_schema::document_simpl doc_s (hello_s.root_serializer (),
+ hello_s.root_name ());
+hello_s.pre (*h);
+doc_s.serialize (std::cout);
+hello_s.post ();
+ </pre>
+
+ <p>For more information on the <code>document_simpl</code> class,
+ including the other variants of the <code>serialize()</code>
+ function as well as error handling during serialization, see
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#8">Chapter 8,
+ "Document Serializer and Error Handling"</a> in the Embedded
+ C++/Serializer Mapping Getting Started Guide.</p>
+
+ <h2><a name="6.1">6.1 Customizing Parsers and Serializers</a></h2>
+
+ <p>The C++/Hybrid mapping allows you to customize the generated
+ parser and serializer implementations. This mechanism can be
+ used, for example, to implement filtering, partially
+ event-driven XML processing, as well as parsing of content
+ matched by XML Schema wildcards. Filtering allows only parts
+ of the XML document to be parsed into the object model or only
+ parts of the object model to be serialized to XML. With
+ partially event-driven parsing and serialization, we can
+ process parts of the document as they become available as
+ well as handle documents that are too large to fit into
+ memory. This section expects you to have an understanding
+ of the C++/Parser and C++/Serializer programming models.</p>
+
+ <p>To request customization of a parser or serializer
+ implementation, you will need to specify the
+ <code>--custom-parser</code> or <code>--custom-serializer</code>
+ option, respectively. The argument format for these two options
+ is <code>type[=base[/include]]</code>. The <code>type</code>
+ component is the XML Schema type name being customized. Optional
+ <code>base</code> is a C++ name that should be given to the
+ generated version. It is normally used as a base for the custom
+ implementation. Optional <code>include</code> is the header file
+ that defines the custom implementation. It is <code>#include</code>'ed
+ into the generated code immediately after (if <code>base</code>
+ is specified) or instead of the generated version. The following
+ examples show how we can use these options:</p>
+
+ <pre class="terminal">
+--custom-parser foo
+--custom-parser foo=foo_base_pimpl
+--custom-parser foo=foo_base_pimpl/foo/foo-custom.hxx
+--custom-parser foo=/foo/foo-custom.hxx
+ </pre>
+
+ <p>The first version instructs the XSD/e compiler not to generate
+ the parser implementation for the <code>foo</code> XML Schema
+ type. The second version instructs the compiler to generate
+ the parser implementation for type <code>foo</code> but call
+ it <code>foo_base_pimpl</code>. The third version is similar to the
+ second except that the compiler generates the <code>#include</code>
+ directive with the <code>foo/foo-custom.hxx</code> file (which
+ presumably defines <code>foo_pimpl</code>) right after the
+ <code>foo_base_pimpl</code> class. The last version instructs
+ the XSD/e compiler to include <code>foo/foo-custom.hxx</code>
+ instead of generating the parser implementation for
+ <code>foo</code>. If you omit the last component, then
+ you can include the custom parser/serializer definitions
+ using one of the prologue or epilogue XSD/e compiler options.
+ See the <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e
+ Compiler Command Line Manual</a> for details.</p>
+
+ <p>Once you specify the <code>--custom-parser</code> or
+ <code>--custom-serializer</code> option, you will need to
+ provide the custom implementation. You have a choice of either
+ basing it on the generated version and overriding some
+ callbacks or implementing it from scratch.</p>
+
+ <p>In the remainder of this section we will examine how to
+ customize the <code>people</code> parser and serializer
+ implementations from the example presented in <a href="#4">Chapter 4,
+ "Working with Object Models"</a>. Our custom parser
+ implementation will filter the records being parsed
+ based on a person's age. Similarly, the serializer will
+ only serialize records of a specific gender. The code
+ presented below is taken from the <code>filter</code>
+ example in the XSD/e distribution. Other examples
+ related to parser/serializer customization are
+ <code>wildcard</code> and <code>streaming</code>.</p>
+
+ <p>First, we compile the <code>people.xsd</code> schema
+ and instruct the XSD/e compiler to customize the
+ parser and serializer implementations for the <code>people</code>
+ XML Schema type:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--custom-parser people=people_base_pimpl/people-custom-pimpl.hxx \
+--custom-serializer people=people_base_simpl/people-custom-simpl.hxx \
+--generate-aggregate people.xsd
+ </pre>
+
+ <p>The custom <code>people_pimpl</code> parser implementation
+ is based on the generated version and is saved to
+ <code>people-custom-pimpl.hxx</code>:</p>
+
+ <pre class="c++">
+class people_pimpl: public people_base_pimpl
+{
+public:
+ void
+ age_filter (unsigned short min, unsigned short max)
+ {
+ min_age_ = min;
+ max_age_ = max;
+ }
+
+ virtual void
+ person (const ::person&amp; p)
+ {
+ // Check if the age constraints are met.
+ //
+ unsigned short age = p.age ();
+
+ if (age >= min_age_ &amp;&amp; age &lt;= max_age_)
+ people_base_pimpl::person (p);
+ }
+
+private:
+ unsigned short min_age_;
+ unsigned short max_age_;
+};
+ </pre>
+
+ <p>Here we override the <code>person()</code> callback and,
+ if the filter conditions are satisfied, call the original
+ version which adds the person record to the object model.
+ Note that if the <code>person</code> object model class
+ were variable-length, then the instance would be
+ dynamically allocated and passed as a pointer. In this
+ situation, if we don't use the object, we need to delete it,
+ for example:</p>
+
+<pre class="c++">
+virtual void
+person (const ::person* p)
+{
+ unsigned short age = p->age ();
+
+ if (age >= min_age_ &amp;&amp; age &lt;= max_age_)
+ people_base_pimpl::person (p);
+ else
+ delete p;
+}
+ </pre>
+
+ <p>The custom <code>people_simpl</code> parser implementation
+ is also based on the generated version and is saved to
+ <code>people-custom-simpl.hxx</code>:</p>
+
+ <pre class="c++">
+class people_simpl: public people_base_simpl
+{
+public:
+ void
+ gender_filter (gender g)
+ {
+ gender_ = g;
+ }
+
+ virtual bool
+ person_next ()
+ {
+ // See if we have any more person records with the gender we
+ // are interested in.
+ //
+ people::person_const_iterator&amp; i = people_base_simpl_state_.person_;
+ people::person_const_iterator&amp; e = people_base_simpl_state_.person_end_;
+
+ for (; i != e; ++i)
+ {
+ if (i->gender () == gender_)
+ break;
+ }
+
+ return i != e;
+ }
+
+private:
+ gender gender_;
+};
+ </pre>
+
+ <p>Here we override the <code>person_next()</code> callback
+ where we locate the next record that satisfies the filter
+ conditions. Note that we use the serialization state
+ provided by the generated <code>people_base_simpl</code>
+ implementation.</p>
+
+ <p>The following code fragment shows a test driver that uses
+ the above implementations to filter the data during parsing
+ and serialization:</p>
+
+ <pre class="c++">
+#include &lt;memory>
+#include &lt;iostream>
+
+#include "people.hxx"
+
+#include "people-pimpl.hxx"
+#include "people-simpl.hxx"
+
+using namespace std;
+
+int
+main (int argc, char* argv[])
+{
+ // Parse.
+ //
+ people_paggr people_p;
+ people_pimpl&amp; root_p = people_p.root_parser ();
+
+ // Initialize the filter.
+ //
+ root_p.age_filter (1, 30);
+
+ xml_schema::document_pimpl doc_p (root_p, people_p.root_name ());
+
+ people_p.pre ();
+ doc_p.parse (argv[1]);
+ auto_ptr&lt;people> ppl (people_p.post ());
+
+ // Print what we've got.
+ //
+ people::person_sequence&amp; ps = ppl->person ();
+
+ for (people::person_iterator i = ps.begin (); i != ps.end (); ++i)
+ {
+ cerr &lt;&lt; "first: " &lt;&lt; i->first_name () &lt;&lt; endl
+ &lt;&lt; "last: " &lt;&lt; i->last_name () &lt;&lt; endl
+ &lt;&lt; "gender: " &lt;&lt; i->gender () &lt;&lt; endl
+ &lt;&lt; "age: " &lt;&lt; i->age () &lt;&lt; endl
+ &lt;&lt; endl;
+ }
+
+ // Serialize.
+ //
+ people_saggr people_s;
+ people_simpl&amp; root_s = people_s.root_serializer ();
+
+ // Initialize the filter.
+ //
+ gender g;
+ g.assign ("female");
+ root_s.gender_filter (g);
+
+ xml_schema::document_simpl doc_s (root_s, people_s.root_name ());
+
+ people_s.pre (*ppl);
+ doc_s.serialize (cout);
+ people_s.post ();
+}
+ </pre>
+
+ <p>If we run this test driver on the following XML document:</p>
+
+ <pre class="xml">
+&lt;?xml version="1.0"?>
+&lt;people>
+
+ &lt;person>
+ &lt;first-name>John&lt;/first-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>male&lt;/gender>
+ &lt;age>32&lt;/age>
+ &lt;/person>
+
+ &lt;person>
+ &lt;first-name>Jane&lt;/first-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>female&lt;/gender>
+ &lt;age>28&lt;/age>
+ &lt;/person>
+
+ &lt;person>
+ &lt;first-name>Joe&lt;/first-name>
+ &lt;last-name>Dirt&lt;/last-name>
+ &lt;gender>male&lt;/gender>
+ &lt;age>25&lt;/age>
+ &lt;/person>
+
+&lt;/people>
+ </pre>
+
+ <p>We will get the following output:</p>
+
+ <pre class="terminal">
+first: Jane
+last: Doe
+gender: female
+age: 28
+
+first: Joe
+last: Dirt
+gender: male
+age: 25
+
+&lt;people>
+ &lt;person>
+ &lt;first-name>Jane&lt;/first-name>
+ &lt;last-name>Doe&lt;/last-name>
+ &lt;gender>female&lt;/gender>
+ &lt;age>28&lt;/age>
+ &lt;/person>
+&lt;/people>
+ </pre>
+
+
+
+ </div>
+</div>
+
+
+</body>
+</html>