aboutsummaryrefslogtreecommitdiff
path: root/doc/cxx/hybrid/guide/index.xhtml
diff options
context:
space:
mode:
Diffstat (limited to 'doc/cxx/hybrid/guide/index.xhtml')
-rw-r--r--doc/cxx/hybrid/guide/index.xhtml6521
1 files changed, 6521 insertions, 0 deletions
diff --git a/doc/cxx/hybrid/guide/index.xhtml b/doc/cxx/hybrid/guide/index.xhtml
new file mode 100644
index 0000000..9bf3df1
--- /dev/null
+++ b/doc/cxx/hybrid/guide/index.xhtml
@@ -0,0 +1,6521 @@
+<?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-2011 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;
+ }
+</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-2011 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>
+ <tr><th>3.7</th><td><a href="#3.7">Support for Polymorphism</a></td></tr>
+ <tr><th>3.8</th><td><a href="#3.8">Custom Allocators</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">Enumerations</a></td></tr>
+ <tr><th>4.4</th><td><a href="#4.4">Attributes and Elements</a></td></tr>
+ <tr><th>4.5</th><td><a href="#4.5">Compositors</a></td></tr>
+ <tr><th>4.6</th><td><a href="#4.6">Accessing the Object Model</a></td></tr>
+ <tr><th>4.7</th><td><a href="#4.7">Modifying the Object Model</a></td></tr>
+ <tr><th>4.8</th><td><a href="#4.8">Creating the Object Model from Scratch</a></td></tr>
+ <tr><th>4.9</th><td><a href="#4.9">Customizing the Object Model</a></td></tr>
+ <tr><th>4.10</th><td><a href="#4.10">Polymorphic Object Models</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>
+ <tr><th>5.14</th><td><a href="#5.14">Mapping for <code>anyType</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>
+
+ <tr>
+ <th>7</th><td><a href="#7">Binary Representation</a>
+ <table class="toc">
+ <tr><th>7.1</th><td><a href="#7.1">CDR (Common Data Representation)</a></td></tr>
+ <tr><th>7.2</th><td><a href="#7.2">XDR (eXternal Data Representation)</a></td></tr>
+ <tr><th>7.3</th><td><a href="#7.3">Custom Representations</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 dependency-free W3C XML Schema to C++ compiler for mobile,
+ embedded, and light-weight applications. Embedded C++/Hybrid is an 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>Besides reading from and writing to XML, the C++/Hybrid mapping
+ also supports saving the object model to and loading it from a
+ number of predefined as well as custom binary formats. Binary
+ representations contain only the data without any meta information
+ or markup. Consequently, saving to and loading from a binary
+ format can be an order of magnitude faster as well as result
+ in a much smaller application footprint compared to parsing and
+ serializing the same data in XML. Furthermore, the resulting
+ representation is normally several times smaller than the equivalent
+ XML.</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>moon&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 xml_schema::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 <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.cxx hello-pskel.cxx \
+ hello-pimpl.cxx
+
+$ c++ -o driver driver.o hello.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, xml_schema::document_simpl::pretty_print);
+ 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 <code>hello_saggr</code> class
+ is the serializer aggregate class we discussed earlier.</p>
+
+ <p>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 second argument in the call to
+ <code>serialize()</code> is a flag that requests pretty-printing
+ of the resulting XML document. You would normally specify this flag
+ during testing to obtain easily-readable XML and remove it
+ in production to get faster serialization and smaller documents.
+ 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>moon&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, xml_schema::document_simpl::pretty_print);
+ hello_s.post ();
+
+ cout &lt;&lt; ostr.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.
+ //
+ char* str = strdupx ("Hi");
+
+ if (str == 0)
+ {
+ fprintf (stderr, "error: no memory\n");
+ delete h;
+ return 1;
+ }
+
+ h->greeting (str);
+
+ // Add another entry to the name sequence.
+ //
+ str = strdupx ("mars");
+
+ if (str == 0)
+ {
+ fprintf (stderr, "error: no memory\n");
+ delete h;
+ return 1;
+ }
+
+ if (h->name ().push_back (str) != 0)
+ {
+ // The sequence has already freed str.
+ //
+ fprintf (stderr, "error: no memory\n");
+ delete h;
+ return 1;
+ }
+
+ // 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, xml_schema::document_simpl::pretty_print);
+
+ 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 C++/Hybrid
+ object model always stores character data in the same encoding,
+ called application encoding. The application encoding can either be
+ UTF-8 (default) or ISO-8859-1. To select a particular encoding, configure
+ the XSD/e runtime library accordingly and pass the <code>--char-encoding</code>
+ option to the XSD/e compiler when translating your schemas.</p>
+
+ <p>When using ISO-8859-1 as the application encoding, XML documents
+ being parsed may contain characters with Unicode values greater
+ than 0xFF which are unrepresentable in the ISO-8859-1 encoding.
+ By default, in such situations parsing will terminate with
+ an error. However, you can suppress the error by providing a
+ replacement character that should be used instead of
+ unrepresentable characters, for example:</p>
+
+ <pre class="c++">
+xml_schema::iso8859_1::unrep_char ('?');
+ </pre>
+
+ <p>To revert to the default behavior, set the replacement character
+ to <code>'\0'</code>.</p>
+
+ <p>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. The underlying XML
+ serializer used by C++/Hybrid produces the resulting
+ XML documents in the UTF-8 encoding.</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>
+
+ <h2><a name="3.7">3.7 Support for Polymorphism</a></h2>
+
+ <p>By default the XSD/e compiler generates non-polymorphic code. If your
+ vocabulary uses XML Schema polymorphism in the form of <code>xsi:type</code>
+ and/or substitution groups, then you will need to configure the XSD/e
+ runtime with support for polymorphism, compile your schemas with the
+ <code>--generate-polymorphic</code> option to produce polymorphism-aware
+ code, as well as pass <code>true</code> as the last argument to the
+ <code>xml_schema::document_pimpl</code> and
+ <code>xml_schema::document_simpl</code> constructors (see
+ <a href="#6">Chapter 6, "Parsing and Serialization"</a> for details).
+ If some of your schemas do not require support for polymorphism then
+ you can compile them with the <code>--runtime-polymorphic</code> option
+ and still use the XSD/e runtime configured with polymorphism support.
+ </p>
+
+ <p>The XSD/e compiler can often automatically determine which types are
+ polymorphic based on the substitution group declarations. However,
+ if your XML vocabulary is not using substitution groups or if
+ substitution groups are defined in a separate schema, then you will
+ need to use the <code>--polymorphic-type</code> option to specify
+ which types are polymorphic. When using this option you only need
+ to specify the root of a polymorphic type hierarchy and the XSD/e
+ compiler will assume that all the derived types are also polymorphic.
+ Also note that you need to specify this option when compiling every
+ schema file that references the polymorphic type. Consider the following
+ two schemas as an example:</p>
+
+ <pre class="xml">
+&lt;!-- base.xsd -->
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="base">
+ &lt;xs:sequence>
+ &lt;xs:element name="b" type="xs:int"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- substitution group root -->
+ &lt;xs:element name="base" type="base"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <pre class="xml">
+&lt;!-- derived.xsd -->
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;include schemaLocation="base.xsd"/>
+
+ &lt;xs:complexType name="derived">
+ &lt;xs:complexContent>
+ &lt;xs:extension base="base">
+ &lt;xs:sequence>
+ &lt;xs:element name="d" type="xs:string"/>
+ &lt;/xs:sequence>
+ &lt;/xs:extension>
+ &lt;/xs:complexContent>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="derived" type="derived" substitutionGroup="base"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>In this example we need to specify "<code>--polymorphic-type base</code>"
+ when compiling both schemas because the substitution group is declared
+ in a schema other than the one defining type <code>base</code>.</p>
+
+ <p>Another issue that may arise when compiling polymorphic schemas is
+ the situation where the XSD/e compiler is unaware of all the
+ derivations of a polymorphic type while generating parser and
+ serializer aggregates. As a result, the generated code may not
+ be able to parse and serialize these "invisible" to the compiler
+ types. The following example will help illustrate this case.
+ Consider a modified version of <code>base.xsd</code> from the
+ above example:</p>
+
+ <pre class="xml">
+&lt;!-- base.xsd -->
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="base">
+ &lt;xs:sequence>
+ &lt;xs:element name="b" type="xs:int"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- substitution group root -->
+ &lt;xs:element name="base" type="base"/>
+
+ &lt;xs:complexType name="root">
+ &lt;xs:sequence>
+ &lt;xs:element ref="base" maxOccurs="unbounded"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- document root -->
+ &lt;xs:element name="root" type="root"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>Suppose we compile this schema as follows:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root base.xsd
+ </pre>
+
+ <p>The resulting parser and serializer aggregates for the <code>root</code>
+ element will not include the parser and serializer for the
+ <code>derived</code> type that can be used instead of the
+ <code>base</code> type. This is because the XSD/e compiler
+ has no knowledge of the <code>derived</code>'s existence when
+ compiling <code>base.xsd</code>.</p>
+
+ <p>There are two ways to overcome this problem. The easier but
+ potentially slower approach is to compile all your schemas
+ at once, for example:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root base.xsd derived.xsd
+ </pre>
+
+ <p>This will make sure the XSD/e compiler "sees" all the derivations
+ of the polymorphic types. The other approach allows
+ you to explicitly specify, with the <code>--polymorphic-schema</code>
+ option, additional schemas that may contain derivations of the
+ polymorphic types. Using this approach we would compile
+ <code>base.xsd</code> and <code>derived.xsd</code> like this:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root \
+--polymorphic-schema derived.xsd base.xsd
+
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base derived.xsd
+ </pre>
+
+ <p>For information on how to use object models with polymorphic types,
+ refer to <a href="#4.10">Section 4.10, "Polymorphic Object Models"</a>.</p>
+
+ <h2><a name="3.8">3.8 Custom Allocators</a></h2>
+
+ <p>By default the XSD/e runtime and generated code use
+ the standard operators <code>new</code> and <code>delete</code>
+ to manage dynamic memory. However, it is possible to instead
+ use custom allocator functions provided by your application.
+ To achieve this, configure the XSD/e runtime library to use
+ custom allocator functions as well as pass the
+ <code>--custom-allocator</code> option to the XSD/e compiler
+ when translating your schemas. The signatures of the custom
+ allocator functions that should be provided by your application
+ are listed below. Their semantics should be equivalent to the
+ standard C <code>malloc()</code>, <code>realloc()</code>, and
+ <code>free()</code> functions.</p>
+
+ <pre class="c++">
+extern "C" void*
+xsde_alloc (size_t);
+
+extern "C" void*
+xsde_realloc (void*, size_t);
+
+extern "C" void
+xsde_free (void*);
+ </pre>
+
+ <p>Note also that when custom allocators are enabled, any
+ dynamically-allocated object of which the XSD/e runtime
+ or generated code assume ownership should be allocated
+ using the custom allocation function. Similarly, if your
+ application assumes ownership of any dynamically-allocated
+ object returned by the XSD/e runtime or the generated code,
+ then such an object should be disposed of using the custom
+ deallocation function. To help with these tasks the generated
+ <code>xml_schema</code> namespace defines the following two
+ helper functions and, if C++ exceptions are enabled, automatic
+ pointer class:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ void*
+ alloc (size_t);
+
+ void
+ free (void*);
+
+ struct alloc_guard
+ {
+ alloc_guard (void*);
+ ~alloc_guard ();
+
+ void*
+ get () const;
+
+ void
+ release ();
+
+ private:
+ ...
+ };
+}
+ </pre>
+
+ <p>If C++ exceptions are disabled, these functions are equivalent
+ to <code>xsde_alloc()</code> and <code>xsde_free()</code>.
+ If exceptions are enabled, <code>xml_schema::alloc()</code>
+ throws <code>std::bad_alloc</code> on memory allocation failure.</p>
+
+ <p>The following code fragment shows how to create and destroy a
+ dynamically-allocated object with custom allocators when C++
+ exceptions are disabled:</p>
+
+ <pre class="c++">
+void* v = xml_schema::alloc (sizeof (type));
+
+if (v == 0)
+{
+ // Handle out of memory condition.
+}
+
+type* x = new (v) type (1, 2);
+
+...
+
+if (x)
+{
+ x->~type ();
+ xml_schema::free (x);
+}
+ </pre>
+
+ <p>The equivalent code fragment for configurations with C++ exceptions
+ enabled is shown below:</p>
+
+ <pre class="c++">
+xml_schema::alloc_guard g (xml_schema::alloc (sizeof (type)));
+type* x = new (g.get ()) type (1, 2);
+g.release ();
+
+...
+
+if (x)
+{
+ x->~type ();
+ xml_schema::free (x);
+}
+ </pre>
+
+ <p>For a complete example that shows how to use custom allocators, see
+ the <code>allocator</code> example which can be found in the
+ <code>examples/cxx/hybrid/</code> directory of the XSD/e distribution.</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:
+ enum value_type
+ {
+ male,
+ female
+ };
+
+ gender ();
+ gender (value_type);
+ gender (const gender&amp;);
+ gender&amp; operator= (const gender&amp;);
+
+ void
+ value (value_type);
+
+ operator value_type () const;
+
+ const char*
+ string () const;
+
+private:
+ ...
+};
+
+// 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 xml_schema::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>
+
+ <li>it is polymorphic (see <a href="#4.10">Section 4.10, "Polymorphic
+ Object Models"</a> for details)</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 <code>person</code> type will also become variable-length
+ since it 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. Unless you are using custom allocators
+ (see <a href="#3.8">Section 3.8, "Custom Allocators"</a>),
+ the object model expects you to allocate such an object with
+ operator <code>new</code> and will eventually delete it
+ with operator <code>delete</code>.</p>
+
+ <p>If you wish to make copies of variable-length objects, then
+ you can request the generation of the object cloning functions
+ with the <code>--generate-clone</code> compiler
+ option. When this option is specified, each variable-length
+ type implements the <code>_clone()</code> function which returns
+ a dynamically-allocated copy of the object or <code>NULL</code>
+ if the allocation failed and C++ exceptions are disabled (see
+ <a href="#3.3">Section 3.3, "C++ Exceptions"</a>). </p>
+
+ <p>You can also request generation of detach functions with the
+ <code>--generate-detach</code> compiler option. These functions
+ allow you to detach a variable-length object from the object model.
+ 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 and specify the
+ <code>--generate-clone</code> and <code>--generate-detach</code>
+ options, we will get the following C++ class:</p>
+
+ <pre class="c++">
+// staff (variable-length)
+//
+class staff
+{
+public:
+ staff ();
+
+ staff*
+ _clone () const;
+
+private:
+ staff (const staff&amp;);
+ staff&amp; operator= (const staff&amp;);
+
+public:
+ // permanent
+ //
+ const people&amp;
+ permanent () const;
+
+ people&amp;
+ permanent ();
+
+ void
+ permanent (people*);
+
+ people*
+ permanent_detach ();
+
+ // contract
+ //
+ const people&amp;
+ contract () const;
+
+ people&amp;
+ contract ();
+
+ void
+ contract (people*);
+
+ people*
+ contract_detach ();
+
+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 of per.
+s->contract (con) // Assumes ownership of con.
+ </pre>
+
+ <h2><a name="4.3">4.3 Enumerations</a></h2>
+
+ <p>By default, string-based types that use XML Schema restriction by
+ enumeration are mapped to C++ classes with semantics similar to
+ C++ enum (you can suppress this mapping and instead get the plain
+ inheritance by specifying the <code>--suppress-enum</code> compiler
+ option). The following code fragment again shows the C++ class that
+ was generated for the <code>gender</code> XML Schema type presented
+ at the beginning of this chapter:</p>
+
+ <pre class="c++">
+// gender (fixed-length)
+//
+class gender
+{
+public:
+ enum value_type
+ {
+ male,
+ female
+ };
+
+ gender ();
+ gender (value_type);
+ gender (const gender&amp;);
+ gender&amp; operator= (const gender&amp;);
+
+ void
+ value (value_type);
+
+ operator value_type () const;
+
+ const char*
+ string () const;
+
+private:
+ value_type v_;
+};
+</pre>
+
+ <p>The <code>gender</code> class defines the underlying C++ enum type
+ (<code>value_type</code>) with enumerators corresponding to the
+ <code>enumeration</code> elements in XML Schema. The class also
+ defines the default constructor, copy constructor, constructor
+ with the underlying enum type as its argument, and the assignment
+ operator. The <code>gender</code> class also supports the implicit
+ conversion to the underlying enum type and the explicit conversion
+ to string via the <code>string()</code> function. Finally, it
+ provides the <code>value()</code> modifier function which allows you
+ to set the underlying enum value explicitly. Note also that such an
+ enumeration class is always fixed-length since it only contains the
+ C++ enum value. The following example shows how we can use the
+ <code>gender</code> class:</p>
+
+ <pre class="c++">
+gender g = gender::male;
+g = gender::female;
+g.value (gender::female); // Same as above.
+
+cerr &lt;&lt; g.string () &lt;&lt; endl;
+
+if (g != gender::male)
+ ...
+
+switch (g)
+{
+case gender::male:
+ ...
+case gender::female:
+ ...
+}
+ </pre>
+
+
+ <h2><a name="4.4">4.4 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 again shows 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 again shows 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
+ functions for querying and modifying the member'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>If an optional member is of a variable-length type, then the second
+ <code>_present()</code> function is omitted. This is done to help
+ detect programming errors that result from a type becoming
+ variable-length due to schema changes. In this situation, before
+ the type becomes variable-length, calling the presence function
+ with <code>true</code> as its argument and then accessing the
+ member is valid. Once the type becomes variable-length, the
+ same sequence of calls would lead to a runtime error. By
+ omitting the second <code>_present()</code> function for
+ variable-length types, this kind of errors can be detected
+ at compile time. To reset an optional member of a variable-length
+ type you can call the member modifier function with <code>NULL</code>
+ as its argument. For example, if the <code>middle_name</code>
+ member was of a variable-length type, then the above code fragment
+ would look like this:</p>
+
+ <pre class="c++">
+person&amp; p = ...
+
+if (p.middle_name_present ())
+{
+ cout &lt;&lt; *p.middle_name () &lt;&lt; endl;
+ p.middle_name (0); // Reset to the "not present" state.
+}
+ </pre>
+
+
+ <p>There are two cases in the <em>optional</em> cardinality class that
+ are handled differently. These are optional attributes with default
+ and fixed values. When an optional attribute declaration in XML Schema
+ specifies a default or fixed value and such an attribute is not present
+ in the XML document, the attribute is assumed to have the default or
+ fixed value, respectively. Furthermore, if an attribute with the
+ fixed value is set in the XML document, then the attribute value
+ should be the same as its fixed value.</p>
+
+ <p>For an optional attribute with a default value, the functions for
+ querying and modifying the attribute's presence status are replaced
+ with functions that allow you to determine whether the attribute has
+ the default value. The accessor functions can be called at any time
+ since an optional attribute with a default value always has some
+ value. Also an extra static function is provided to allow you to
+ obtain the default value. Consider the following modification to
+ the <code>person</code> type which adds the <code>verified</code>
+ attribute with the default value:</p>
+
+ <pre class="xml">
+&lt;xs:complexType name="person">
+ &lt;xs:sequence>
+ &lt;xs:element name="first-name" type="xs:string"/>
+ ...
+ &lt;/xs:sequence>
+ &lt;xs:attribute name="id" type="xs:unsignedInt" use="required"/>
+ &lt;xs:attribute name="verified" type="xs:boolean" default="false"/>
+&lt;/xs:complexType>
+ </pre>
+
+ <p>The code fragment below shows the accessor and modifier functions
+ that are generated for this new attribute in the <code>person</code>
+ class:</p>
+
+ <pre class="c++">
+class person
+{
+ // verified
+ //
+ bool
+ verified_default () const;
+
+ void
+ verified_default (bool);
+
+ bool
+ verified () const;
+
+ bool&amp;
+ verified ();
+
+ void
+ verified (bool);
+
+ static bool
+ verified_default_value ();
+};
+ </pre>
+
+ <p>When we create an object of the <code>person</code> class, the
+ <code>verified</code> member is automatically initialized to the
+ default value. The following example shows how we can manipulate
+ the <code>verified</code> attribute value:</p>
+
+ <pre class="c++">
+person p; // verified is set to the default value (false).
+
+if (p.verified_default ())
+ p.verified (true);
+else
+ p.verified_default (true); // Revert to the default value.
+
+bool v = p.verified (); // Ok, can always be called.
+bool vd = person::verified_default_value ();
+ </pre>
+
+ <p>Note that modifying an attribute of a variable-length type via
+ the reference when the attribute is set to the default value is
+ illegal since this will modify the default value shared by all
+ instances. For example:</p>
+
+ <pre class="c++">
+type&amp; x = ...
+
+if (x.foo_default ())
+{
+ foo&amp; f = x.foo (); // foo is variable-length, for example NMTOKENS
+ f.push_back ("aaa"); // Illegal.
+}
+
+if (x.foo_default ())
+{
+ foo* f = new foo;
+ f->push_back ("aaa");
+ x.foo (f); // Ok.
+}
+ </pre>
+
+ <p>Because an attribute with a fixed value can only be set to that
+ value, only the read-only (constant) accessor and the static
+ function for obtaining the fixed value are provided for such
+ attributes. Similar to the default values, members with fixed
+ values of a newly created object are automatically initialized
+ to their respective fixed values. Consider the following
+ modification to the <code>verified</code> attribute from the
+ schema above:</p>
+
+ <pre class="xml">
+&lt;xs:complexType name="person">
+ ...
+ &lt;xs:attribute name="verified" type="xs:boolean" fixed="true"/>
+&lt;/xs:complexType>
+ </pre>
+
+ <p>The code fragment below shows the accessor functions that are
+ generated for this attribute in the <code>person</code>
+ class:</p>
+
+ <pre class="c++">
+class person
+{
+ // verified
+ //
+ bool
+ verified () const;
+
+ static bool
+ verified_fixed_value ();
+};
+ </pre>
+
+ <p>During serialization, attributes that are set to default and fixed
+ values are explicitly specified in the resulting XML document.
+ You can use the <code>--omit-default-attributes</code> XSD/e
+ compiler option to omit such attributes from the serialized XML.</p>
+
+ <p>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 xml_schema::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++">
+namespace xml_schema
+{
+ 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);
+
+ void
+ assign (const T* src, size_t n);
+ };
+}
+ </pre>
+
+ <p>When C++ exceptions are disabled, the signatures of the
+ <code>push_back()</code>, <code>insert()</code>,
+ <code>reserve()</code>, and <code>assign()</code> functions
+ change as follows:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ 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);
+
+ error
+ assign (const T* src, size_t n);
+ };
+}
+ </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++">
+namespace xml_schema
+{
+ 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
+ push_back (T*);
+
+ iterator
+ insert (iterator, T*);
+
+ void
+ pop_back ();
+
+ iterator
+ erase (iterator);
+
+ void
+ reserve (size_t);
+
+ T*
+ detach (iterator);
+
+ void
+ attach (iterator, 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. The <code>var_sequence</code>
+ class template also provides the <code>detach()</code> and <code>attach()</code>
+ functions. The <code>detach()</code> function allows you to detach
+ the contained object at the specified position. A detached object
+ should eventually be deallocated with operator <code>delete</code>.
+ Similarly, the <code>attach()</code> function allows you to attach
+ a new object at the specified position.</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++">
+namespace xml_schema
+{
+ 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 <code>string_sequence</code> class has
+ the same interface as <code>fix_sequence&lt;std::string></code>. When
+ STL is disabled and strings are mapped to <code>char*</code>,
+ <code>string_sequence</code> 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);
+
+ char*
+ detach (iterator);
+
+ void
+ attach (iterator, char*);
+ };
+}
+ </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.
+ The <code>string_sequence</code> class also provides the
+ <code>detach()</code> and <code>attach()</code> functions.
+ The <code>detach()</code> function allows you to detach
+ the contained string at the specified position. A detached string
+ should eventually be deallocated with operator <code>delete[]</code>.
+ Similarly, the <code>attach()</code> function allows you to attach
+ a new string at the specified position.</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.5">4.5 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.4">Section
+ 4.4, "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 xml_schema::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;
+
+ 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 xml_schema::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 xml_schema::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.6">4.6 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 ().string () &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.7">4.7 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, xml_schema::document_simpl::pretty_print);
+ 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.8">4.8 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.gender (gender::male);
+ p.age (32);
+ p.id (1);
+
+ ps.push_back (p);
+ }
+
+ // Jane
+ //
+ {
+ person p;
+ p.first_name ("Jane");
+ p.middle_name ("Mary");
+ p.last_name ("Doe");
+ p.gender (gender::female);
+ p.age (28);
+ p.id (2);
+
+ 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, xml_schema::document_simpl::pretty_print);
+ 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.9">4.9 Customizing the Object Model</a></h2>
+
+ <p>Sometimes it is desirable to add extra, application-specific
+ data or functionality to some object model classes or
+ nested compositor classes. Cases where this 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 or provide custom functions as part of the object model.
+ The C++/Hybrid mapping provides two mechanisms for accomplishing
+ this: custom data and custom types. Custom data is a light-weight
+ mechanism for storing application-specific data by allowing you
+ to add a sequence of opaque objects, stored as <code>void*</code>,
+ to select generated classes. Type customization is a more
+ powerful mechanism that allows you to provide custom implementations
+ for select object model classes. You have the option of either extending
+ the generated version of the class (for example, by adding extra data
+ members and/or functions) or providing your own implementation from
+ scratch. The latter approach essentially allows you to change the
+ mapping of XML Schema to C++ on a case by case basis.</p>
+
+ <p>It is also possible to customize the parsing and serialization code,
+ for example, to populate the custom data sequence or custom data
+ members during parsing and later serialize them to XML. See
+ <a href="#6.1">Section 6.1, "Customizing Parsers and
+ Serializers"</a> for details. The remainder of this section discusses
+ the custom data and custom types mechanisms in more detail.</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 from our person records
+ vocabulary, we can compile <code>people.xsd</code>
+ like this:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --custom-data 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 xml_schema::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++">
+namespace xml_schema
+{
+ 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);
+ typedef void* (*clone_func) (void* data, size_t pos);
+
+ public:
+ data_sequence ();
+
+ void
+ destructor (destroy_func);
+
+ void
+ clone (clone_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.
+ Similarly, the <code>clone()</code> modifier allows you to specify
+ the cloning function used to copy the sequence elements.
+ The second argument in these functions is the position
+ of the element in the sequence. This allows you to store objects
+ of different types in the same custom
+ data sequence.</p>
+
+ <p>The <code>push_back()</code> and <code>insert()</code> functions
+ free the passed object if the reallocation of the underlying
+ sequence buffer fails. 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++">
+namespace xml_schema
+{
+ 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>
+
+ <p>To instruct the XSD/e compiler to use a custom implementation
+ for a specific object model class, we need to use the
+ <code>--custom-type</code> option. The argument format for this
+ option is <code>name[=[flags][/[type][/[base][/include]]]]</code>.
+ The <code><i>name</i></code> component is the XML Schema type name being
+ customized. Optional <code><i>flags</i></code> allow you to specify whether
+ the custom class is fixed or variable-length since customization can
+ alter this property, normally from fixed-length to
+ variable-length. The <code>f</code> flag indicates the type is
+ fixed-length and the <code>v</code> flag indicates the type is
+ variable-length. If omitted, the default rules are used to determine
+ the type length (see <a href="#4.2">Section 4.2, "Memory Management"</a>).
+
+ Optional <code><i>type</i></code> is a C++ type name, potentially qualified,
+ that should be used as a custom implementation. If specified, the
+ object model type is defined as a <code>typedef</code> alias for
+ this C++ type. Optional <code><i>base</i></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><i>include</i></code> is the header
+ file that defines the custom implementation. It is <code>#include</code>'ed
+ into the generated code immediately after (if <code><i>base</i></code> is
+ specified) or instead of the generated version. The following
+ examples show how we can use this option:</p>
+
+ <pre class="terminal">
+--custom-type foo
+--custom-type foo=///foo.hxx
+--custom-type foo=v///foo.hxx
+--custom-type foo=f/int
+--custom-type foo=//foo_base/my/foo.hxx
+--custom-type foo=v/wrapper&lt;foo_base>/foo_base
+ </pre>
+
+ <p>The first version instructs the XSD/e compiler not to generate
+ the object model class for the <code>foo</code> XML Schema
+ type. The generated code simply forward-declares <code>foo</code>
+ as a class and leaves it to you to provide the implementation.
+
+ The second version is similar to the first, except now we specify
+ the header file which defines the custom implementation.
+ This file is automatically included into the generated header
+ file instead of the standard implementation.
+
+ The third version is similar to the second, except now we specify
+ that the <code>foo</code> type is variable-length. In the previous
+ two cases the type length was determined automatically based on the
+ type definition in the schema.
+
+ In the fourth version we specify that schema type <code>foo</code>
+ is fixed-length and should be mapped to <code>int</code>.
+
+ The fifth version instructs the XSD/e compiler to generate
+ the object model class for type <code>foo</code> but call it
+ <code>foo_base</code>. It also tells the compiler to generate
+ the <code>#include</code> directive with the <code>my/foo.hxx</code>
+ file (which presumably defines <code>foo</code>) right after the
+ <code>foo_base</code> class.
+
+ Finally, the last version specifies that schema type <code>foo</code>
+ is variable-length and should be mapped to <code>wrapper&lt;foo_base></code>.
+ The compiler is also instructed to generate the standard object
+ model class for type <code>foo</code> but call it <code>foo_base</code>.
+
+ If you omit the last component (<code><i>include</i></code>), as in the
+ final version, then you can provide the custom type 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>Note also that if the type length you specified with the
+ <code>--custom-type</code> option differs from the default type
+ length that would have been determined by the XSD/e compiler,
+ then you need to specify this <code>--custom-type</code> option
+ when compiling every schema file that includes or imports the
+ schema that defines the type being customized.</p>
+
+ <p>As an example, let us add a flag to the <code>person</code> class
+ from our person records vocabulary. This flag can be used by the
+ application to keep track of whether a particular person record
+ has been verified. To customize the <code>person</code> type we
+ can compile <code>people.xsd</code> like this:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --custom-type person=//person_base/person.hxx \
+people.xsd
+ </pre>
+
+ <p>The relevant code fragment from the generated header file
+ looks like this:</p>
+
+ <pre class="c++">
+// person_base (fixed-length)
+//
+class person_base
+{
+ ...
+};
+
+#include "person.hxx"
+
+// people (variable-length)
+//
+class people
+{
+ ...
+
+ // person
+ //
+ typedef xml_schema::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 base our custom implementation of the <code>person</code>
+ class on generated <code>person_base</code> and save it to
+ <code>person.hxx</code>:</p>
+
+ <pre class="c++">
+class person: public person_base
+{
+public:
+ person ()
+ : verified_ (false)
+ {
+ }
+
+ bool
+ verified () const
+ {
+ return verified_;
+ }
+
+ void
+ verified (bool v)
+ {
+ verified_ = v;
+ }
+
+private:
+ bool verified_;
+};
+ </pre>
+
+ <p>The client code can use our custom implementation as if the
+ flag was part of the vocabulary:</p>
+
+ <pre class="c++">
+people::person_sequence&amp; ps = ...;
+
+for (people::person_iterator i = ps.begin (); i != ps.end (); ++i)
+{
+ if (!i->verified ())
+ {
+ // Verify the record.
+
+ ...
+
+ i->verified (true);
+ }
+}
+ </pre>
+
+
+ <h2><a name="4.10">4.10 Polymorphic Object Models</a></h2>
+
+ <p>When generating polymorphism-aware code (see <a href="#3.7">Section
+ 3.7, "Support for Polymorphism"</a>), some objects
+ in the resulting object model will be polymorphic. By polymorphic
+ we mean that the object's (static) type as specified in the
+ object model's interface may differ from the object's actual
+ (dynamic) type. Because of this, it may be necessary to discover
+ the object's actual type at runtime and cast it to this type to
+ gain access to the object's extended interface. Consider the
+ following schema as an example:</p>
+
+ <pre class="xml">
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="person">
+ &lt;xs:sequence>
+ &lt;xs:element name="name" type="xs:string"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- substitution group root -->
+ &lt;xs:element name="person" type="person"/>
+
+ &lt;xs:complexType name="superman">
+ &lt;xs:complexContent>
+ &lt;xs:extension base="person">
+ &lt;xs:attribute name="can-fly" type="xs:boolean"/>
+ &lt;/xs:extension>
+ &lt;/xs:complexContent>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="superman"
+ type="superman"
+ substitutionGroup="person"/>
+
+ &lt;xs:complexType name="batman">
+ &lt;xs:complexContent>
+ &lt;xs:extension base="superman">
+ &lt;xs:attribute name="wing-span" type="xs:unsignedInt"/>
+ &lt;/xs:extension>
+ &lt;/xs:complexContent>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="batman"
+ type="batman"
+ substitutionGroup="superman"/>
+
+ &lt;xs:complexType name="supermen">
+ &lt;xs:sequence>
+ &lt;xs:element ref="person" maxOccurs="unbounded"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="supermen" type="supermen"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>Conforming XML documents can use the <code>superman</code>
+ and <code>batman</code> types in place of the <code>person</code>
+ type either by specifying the type with the <code>xsi:type</code>
+ attributes or by using the elements from the substitution
+ group, for instance:</p>
+
+
+ <pre class="xml">
+&lt;supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ &lt;person>
+ &lt;name>John Doe&lt;/name>
+ &lt;/person>
+
+ &lt;superman can-fly="false">
+ &lt;name>James "007" Bond&lt;/name>
+ &lt;/superman>
+
+ &lt;superman can-fly="true" wing-span="10" xsi:type="batman">
+ &lt;name>Bruce Wayne&lt;/name>
+ &lt;/superman>
+
+&lt;/supermen>
+ </pre>
+
+ <p>When compiling the schema above with the
+ <code>--generate-polymorphic</code> option, the XSD/e compiler
+ automatically detects that the type hierarchy starting with
+ the <code>person</code> type is polymorphic. A polymorphic
+ type is always variable-length which means objects of polymorphic
+ types are allocated dynamically and are stored and passed around
+ as pointers or references. A polymorphic type also defines a
+ virtual <code>_clone()</code> function (see <a href="#4.2">Section 4.2,
+ "Memory Management"</a>) and a virtual destructor
+ which allow you to copy and delete an instance of a
+ polymorphic type via a pointer to its base. The following code
+ fragment shows how we can parse, access, modify, and serialize
+ the above XML document:</p>
+
+ <pre class="c++">
+// Parse.
+//
+supermen_paggr supermen_p;
+
+// The last argument to the document's constructor indicates that we
+// are parsing polymorphic XML documents.
+//
+xml_schema::document_pimpl doc_p (
+ supermen_p.root_parser (),
+ supermen_p.root_name (),
+ true);
+
+supermen_p.pre ();
+doc_p.parse ("supermen.xml");
+auto_ptr&lt;supermen> sm (supermen_p.post ());
+
+// Print what we've got.
+//
+for (supermen::person_iterator i = sm->person ().begin ();
+ i != sm->person ().end ();
+ ++i)
+{
+ person&amp; p = *i;
+
+ if (batman* b = dynamic_cast&lt;batman*> (&amp;p))
+ {
+ cerr &lt;&lt; b->name () &lt;&lt; ", batman, wing span " &lt;&lt;
+ b->wing_span () &lt;&lt; endl;
+ }
+ else if (superman* s = dynamic_cast&lt;superman*> (&amp;p))
+ {
+ cerr &lt;&lt; s->name () &lt;&lt; ", ";
+
+ if (s->can_fly ())
+ cerr &lt;&lt; "flying ";
+
+ cerr &lt;&lt; "superman" &lt;&lt; endl;
+ }
+ else
+ {
+ cerr &lt;&lt; p.name () &lt;&lt; ", ordinary person" &lt;&lt; endl;
+ }
+}
+
+// Add another superman entry.
+//
+auto_ptr&lt;superman> s (new superman);
+s->name ("Clark Kent");
+s->can_fly (true);
+sm->person ().push_back (s.release ());
+
+// Serialize.
+//
+supermen_saggr supermen_s;
+
+// The last argument to the document's constructor indicates that we
+// are serializing polymorphic XML documents.
+//
+xml_schema::document_simpl doc_s (
+ supermen_s.root_serializer (),
+ supermen_s.root_name (),
+ true);
+
+doc_s.add_no_namespace_schema ("supermen.xsd");
+
+supermen_s.pre (*sm);
+doc_s.serialize (cout, xml_schema::document_simpl::pretty_print);
+supermen_s.post ();
+ </pre>
+
+ <p>In the example above we used the standard C++ RTTI mechanism
+ to detect the object's actual (dynamic) type. If RTTI is not
+ available on your platform, then you can request the generation
+ of custom runtime type information for polymorphic types
+ with the <code>--generate-typeinfo</code> XSD/e compiler
+ option. When this option is specified, each polymorphic
+ type provides the following two public functions:</p>
+
+ <pre class="c++">
+virtual const std::string&amp;
+_dynamic_type () const;
+
+static const std::string&amp;
+_static_type ();
+ </pre>
+
+ <p>Or, if STL is disabled (<a href="#3.1">Section 3.1, "Standard Template
+ Library"</a>), the following two functions:</p>
+
+ <pre class="c++">
+virtual const char*
+_dynamic_type () const;
+
+static const char*
+_static_type ();
+ </pre>
+
+ <p>The <code>_dynamic_type()</code> function returns the object's
+ dynamic type id. The <code>_static_type()</code> function
+ returns the type's static id that can be compared to the
+ dynamic id. The following code fragment shows how
+ we can change the previous example to use custom type information
+ instead of C++ RTTI:</p>
+
+ <pre class="c++">
+for (supermen::person_iterator i = sm->person ().begin ();
+ i != sm->person ().end ();
+ ++i)
+{
+ person&amp; p = *i;
+ const string&amp; dt = p._dynamic_type ();
+
+ if (dt == batman::_static_type ())
+ {
+ batman&amp; b = static_cast&lt;batman&amp;> (p)
+ cerr &lt;&lt; b.name () &lt;&lt; ", batman, wing span " &lt;&lt;
+ b.wing_span () &lt;&lt; endl;
+ }
+ else if (dt == superman::_static_type ())
+ {
+ superman&amp; s = static_cast&lt;superman&amp;> (p)
+ cerr &lt;&lt; s.name () &lt;&lt; ", ";
+
+ if (s.can_fly ())
+ cerr &lt;&lt; "flying ";
+
+ cerr &lt;&lt; "superman" &lt;&lt; endl;
+ }
+ else
+ {
+ cerr &lt;&lt; p.name () &lt;&lt; ", ordinary person" &lt;&lt; endl;
+ }
+}
+ </pre>
+
+ <p>Most of the code presented in this section is taken from the
+ <code>polymorphism</code> example which can be found in the
+ <code>examples/cxx/hybrid/</code> directory of the XSD/e distribution.
+ Handling of <code>xsi:type</code> and substitution groups when used
+ on root elements requires a number of special actions as shown in
+ the <code>polyroot</code> example.</p>
+
+
+ <!-- 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>
+
+ <tr>
+ <th colspan="3">anyType and anySimpleType</th>
+ </tr>
+ <tr>
+ <td><code>anyType</code></td>
+ <td><code>any_type</code></td>
+ <td><a href="#5.14">Section 5.14, "Mapping for <code>anyType</code>"</a></td>
+ </tr>
+ <tr>
+ <td><code>anySimpleType</code></td>
+ <td><code>any_simple_type</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>
+ </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);
+
+ char*
+ base_value_detach ();
+
+ 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. If you detach the
+ string value then it should eventually be deallocated with
+ operator <code>delete[]</code>.</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.4">Section 4.4, "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
+ assign (void* data, size_t size);
+
+ 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
+ assign (void* data, size_t size);
+
+ 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>
+
+ <h2><a name="5.14">5.14 Mapping for <code>anyType</code></a></h2>
+
+ <p>The <code>anyType</code> built-in XML Schema type is mapped to
+ the <code>any_type</code> class in the <code>xml_schema</code>
+ namespace. 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 any_type
+ {
+ public:
+ // Custom data.
+ //
+ typedef xml_schema::data_sequence custom_data_sequence;
+ typedef custom_data_sequence::iterator custom_data_iterator;
+ typedef custom_data_sequence::const_iterator custom_data_const_iterator;
+
+ void
+ allocate_custom_data ();
+
+ const custom_data_sequence&amp;
+ custom_data () const;
+
+ custom_data_sequence&amp;
+ custom_data ();
+ };
+}
+ </pre>
+
+ <p>If C++ exceptions are disabled, the <code>any_type</code> class has
+ the following interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ class any_type
+ {
+ public:
+ // Custom data.
+ //
+ typedef xml_schema::data_sequence custom_data_sequence;
+ typedef custom_data_sequence::iterator custom_data_iterator;
+ typedef custom_data_sequence::const_iterator custom_data_const_iterator;
+
+ bool
+ allocate_custom_data ();
+
+ const custom_data_sequence&amp;
+ custom_data () const;
+
+ custom_data_sequence&amp;
+ custom_data ();
+ };
+}
+ </pre>
+
+ <p>The <code>allocate_custom_data()</code> function allocates the
+ custom data sequence. With C++ exceptions disabled, it returns
+ <code>false</code> if memory allocation has failed and <code>true</code>
+ otherwise. For more information on custom data, refer to
+ <a href="#4.9">Section 4.9, "Customizing the Object Model"</a>.</p>
+
+ <p>The default parser and serializer implementations for the
+ <code>anyType</code> built-in type ignore all its content and
+ return an empty <code>any_type</code> instance. If your application
+ needs to access this content, then you will need to provide your
+ own implementations of these parser and serializer and use the
+ custom data sequence to store the extracted data.</p>
+
+ <!-- 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, xml_schema::document_simpl::pretty_print);
+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>name[=[base][/include]]]</code>. The <code><i>name</i></code>
+ component is the XML Schema type name being customized. Optional
+ <code><i>base</i></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><i>include</i></code> is the header file
+ that defines the custom implementation. It is <code>#include</code>'ed
+ into the generated code immediately after (if <code><i>base</i></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
+ (<code><i>include</i></code>), 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 ().string () &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.
+ //
+ root_s.gender_filter (gender::female);
+
+ xml_schema::document_simpl doc_s (root_s, people_s.root_name ());
+
+ people_s.pre (*ppl);
+ doc_s.serialize (cout, xml_schema::document_simpl::pretty_print);
+ 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>
+
+
+ <!-- Binary Representations -->
+
+ <h1><a name="7">7 Binary Representation</a></h1>
+
+ <p>Besides reading from and writing to XML, the C++/Hybrid mapping
+ also allows you to save the object model to and load it from a
+ number of predefined as well as custom data representation
+ formats. The predefined binary formats are CDR (Common Data
+ Representation) and XDR (eXternal Data Representation). A
+ custom format can easily be supported by providing
+ insertion and extraction operators for basic types.</p>
+
+ <p>Binary representations contain only the data without any meta
+ information or markup. Consequently, saving to and loading
+ from a binary representation can be an order of magnitude
+ faster as well as result in a much smaller footprint compared
+ to parsing and serializing the same data in XML. Furthermore,
+ the resulting representation is normally several times smaller
+ than the equivalent XML representation. These properties make a
+ binary representation ideal for internal data exchange and storage.
+ A typical application that uses this facility stores the data and
+ communicates within the system using a binary format and reads/writes
+ the data in XML when communicating with the outside world.</p>
+
+ <p>In order to request the generation of insertion and extraction
+ operators for a specific predefined or custom data representation
+ stream, you will need to use the <code>--generate-insertion</code>
+ and <code>--generate-extraction</code> compiler options. See the
+ <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e
+ Compiler Command Line Manual</a> for more information.</p>
+
+ <p>The XSD/e runtime provides implementations of the base insertion
+ and extraction operators for the ACE (Adaptive Communication
+ Environment) CDR streams and the XDR API. The XDR API is available
+ out of the box on most POSIX systems as part of Sun RPC. On other
+ platforms you may need to install a third-party library which
+ provides the XDR API.
+
+ The XSD/e compiler recognizes two special argument values to the
+ <code>--generate-insertion</code> and <code>--generate-extraction</code>
+ options: <code>CDR</code> and <code>XDR</code>. When one of these
+ arguments is specified, the corresponding implementation from the
+ XSD/e runtime is automatically used. The following two sections
+ describe each of these two formats in more detail. It is also
+ possible to add support for saving the object model to and loading
+ it from custom data representation formats as discussed in the
+ last section of this chapter.</p>
+
+ <p>The saving of the object model types to a representation stream
+ is implemented with stream insertion operators
+ (<code>operator&lt;&lt;</code>). Similarly, loading of the object
+ model from a representation stream is implemented with stream
+ extraction operators (<code>operator>></code>). The insertion
+ and extraction operators for the built-in XML Schema types as
+ well as the sequence templates are provided by the stream
+ implementation (that is, by the XSD/e runtime in case of CDR and
+ XDR and by you for custom formats). The XSD/e compiler automatically
+ generates insertion and extraction operators for the generated object
+ model types.</p>
+
+ <p>When C++ exceptions are enabled (<a href="#3.3">Section 3.3, "C++
+ Exceptions"</a>), the signatures of the insertion and extraction
+ operators are as follows:</p>
+
+ <pre class="c++">
+void
+operator&lt;&lt; (ostream&amp;, const type&amp;);
+
+void
+operator>> (istream&amp;, type&amp;);
+ </pre>
+
+ <p>The insertion and extraction errors are indicated by throwing
+ stream-specific exceptions. When C++ exceptions are disabled,
+ the signatures of the insertion and extraction operators are
+ as follows:</p>
+
+ <pre class="c++">
+bool
+operator&lt;&lt; (ostream&amp;, const type&amp;);
+
+bool
+operator>> (istream&amp;, type&amp;);
+ </pre>
+
+ <p>In this case the insertion and extraction operators return
+ <code>true</code> if the operation was successful and
+ <code>false</code> otherwise. The stream object may
+ provide additional error information.</p>
+
+
+ <h2><a name="7.1">7.1 CDR (Common Data Representation)</a></h2>
+
+ <p>When you request the generation of CDR stream insertion and extraction
+ operators, the <code>ocdrstream</code> and <code>icdrstream</code>
+ types are defined in the <code>xml_schema</code> namespace. Additionally,
+ if C++ exceptions are enabled, the <code>cdr_exception</code> exception
+ is also defined in <code>xml_schema</code>. The <code>icdrstream</code>
+ and <code>ocdrstream</code> types are simple wrappers for the
+ ACE_InputCDR and ACE_OutputCDR streams. The following code fragment
+ shows how we can use these types when C++ exceptions are enabled:</p>
+
+ <pre class="c++">
+try
+{
+ const type&amp; x = ... // Object model.
+
+ // Save to a CDR stream.
+ //
+ ACE_OutputCDR ace_ocdr;
+ xml_schema::ocdrstream ocdr (ace_ocdr);
+
+ ocdr &lt;&lt; x;
+
+ // Load from a CDR stream.
+ //
+ ACE_InputCDR ace_icdr (buf, size);
+ xml_schema::icdrstream icdr (ace_icdr);
+
+ type copy;
+ icdr >> copy;
+}
+catch (const xml_schema::cdr_exception&amp;)
+{
+ cerr &lt;&lt; "CDR operation failed" &lt;&lt; endl;
+}
+ </pre>
+
+ <p>The same code fragment but when C++ exceptions are disabled:</p>
+
+ <pre class="c++">
+const type&amp; x = ... // Object model.
+
+// Save to a CDR stream.
+//
+ACE_OutputCDR ace_ocdr;
+xml_schema::ocdrstream ocdr (ace_ocdr);
+
+if (!(ocdr &lt;&lt; x))
+{
+ cerr &lt;&lt; "CDR operation failed" &lt;&lt; endl;
+}
+
+// Load from a CDR stream.
+//
+ACE_InputCDR ace_icdr (buf, size);
+xml_schema::icdrstream icdr (ace_icdr);
+
+type copy;
+
+if (!(icdr >> copy))
+{
+ cerr &lt;&lt; "CDR operation failed" &lt;&lt; endl;
+}
+ </pre>
+
+ <p>The <code>cdr</code> example which can be found in the
+ <code>examples/cxx/hybrid/binary/</code> directory of the XSD/e
+ distribution includes complete source code that shows how to
+ save the object model to and load it from the CDR format.</p>
+
+ <h2><a name="7.2">7.2 XDR (eXternal Data Representation)</a></h2>
+
+ <p>When you request the generation of XDR stream insertion and extraction
+ operators, the <code>oxdrstream</code> and <code>xcdrstream</code>
+ types are defined in the <code>xml_schema</code> namespace. Additionally,
+ if C++ exceptions are enabled, the <code>xdr_exception</code> exception
+ is also defined in <code>xml_schema</code>. The <code>ixdrstream</code>
+ and <code>oxdrstream</code> types are simple wrappers for the XDR
+ API. The following code fragment shows how we can use these types
+ when C++ exceptions are enabled:</p>
+
+ <pre class="c++">
+try
+{
+ const type&amp; x = ... // Object model.
+
+ // Save to a XDR stream.
+ //
+ XDR xdr;
+ xdrrec_create (&amp;xdr, ...);
+ xml_schema::oxdrstream oxdr (xdr);
+
+ oxdr &lt;&lt; x;
+
+ // Load from a XDR stream.
+ //
+ xdrrec_create (&amp;xdr, ...);
+ xml_schema::ixdrstream ixdr (xdr);
+
+ type copy;
+ ixdr >> copy;
+}
+catch (const xml_schema::xdr_exception&amp;)
+{
+ cerr &lt;&lt; "XDR operation failed" &lt;&lt; endl;
+}
+ </pre>
+
+ <p>The same code fragment but when C++ exceptions are disabled:</p>
+
+ <pre class="c++">
+const type&amp; x = ... // Object model.
+
+// Save to a XDR stream.
+//
+XDR xdr;
+xdrrec_create (&amp;xdr, ...);
+xml_schema::oxdrstream oxdr (xdr);
+
+if (!(oxdr &lt;&lt; x))
+{
+ cerr &lt;&lt; "XDR operation failed" &lt;&lt; endl;
+}
+
+// Load from a XDR stream.
+//
+xdrrec_create (&amp;xdr, ...);
+xml_schema::ixdrstream ixdr (xdr);
+
+type copy;
+
+if (!(ixdr >> copy))
+{
+ cerr &lt;&lt; "XDR operation failed" &lt;&lt; endl;
+}
+ </pre>
+
+ <p>The <code>xdr</code> example which can be found in the
+ <code>examples/cxx/hybrid/binary/</code> directory of the XSD/e
+ distribution includes complete source code that shows how to
+ save the object model to and load it from the XDR format.</p>
+
+
+ <h2><a name="7.3">7.3 Custom Representations</a></h2>
+
+ <p>To add support for saving the object model to and loading it
+ from a custom format, you will need to perform the following
+ general steps:</p>
+
+ <ol class="list">
+ <li>Generate a header file corresponding to the XML Schema
+ namespace using the <code>--generate-xml-schema</code>
+ compiler option.</li>
+
+ <li>Implement custom stream insertion and extraction operators
+ for the built-in XML Schema types and sequence templates.
+ Include the header file obtained in the previous step to
+ get definitions for these types.</li>
+
+ <li>Compile your schemas with the <code>--generate-insertion</code>
+ and <code>--generate-extraction</code> options. The arguments
+ to these options will be your custom output and input stream
+ types, respectively. Use the <code>--hxx-prologue</code>
+ option to include the definitions for these stream types
+ into the generated code. Also use the
+ <code>--extern-xml-schema</code> option to include the
+ header file obtained in the first step instead of generating
+ the same code directly.</li>
+ </ol>
+
+ <p>The <code>custom</code> example which can be found in the
+ <code>examples/cxx/hybrid/binary/</code> directory of the XSD/e
+ distribution includes complete source code that shows how to
+ save the object model to and load it from a custom format using
+ the raw binary representation as an example. You can use the
+ source code from this example as a base to implement support
+ for your own format.</p>
+
+ </div>
+</div>
+
+
+</body>
+</html>