aboutsummaryrefslogtreecommitdiff
path: root/documentation/cxx/hybrid/guide/index.xhtml
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2014-02-25 09:22:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2014-02-25 09:22:06 +0200
commit3939c9a6ceebbb237d8bdc041fd11f90ffc3b7ea (patch)
treea9273a78e9406a447976d22a3e2448c8debf5f49 /documentation/cxx/hybrid/guide/index.xhtml
parent7f2876d1fb227951bf2531847a4f540df7fcbb78 (diff)
Rename documentation/ to doc/
Diffstat (limited to 'documentation/cxx/hybrid/guide/index.xhtml')
-rw-r--r--documentation/cxx/hybrid/guide/index.xhtml6521
1 files changed, 0 insertions, 6521 deletions
diff --git a/documentation/cxx/hybrid/guide/index.xhtml b/documentation/cxx/hybrid/guide/index.xhtml
deleted file mode 100644
index 9bf3df1..0000000
--- a/documentation/cxx/hybrid/guide/index.xhtml
+++ /dev/null
@@ -1,6521 +0,0 @@
-<?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>