diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2014-02-25 09:22:06 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2014-02-25 09:22:06 +0200 |
commit | 3939c9a6ceebbb237d8bdc041fd11f90ffc3b7ea (patch) | |
tree | a9273a78e9406a447976d22a3e2448c8debf5f49 /documentation/cxx/hybrid/guide/index.xhtml | |
parent | 7f2876d1fb227951bf2531847a4f540df7fcbb78 (diff) |
Rename documentation/ to doc/
Diffstat (limited to 'documentation/cxx/hybrid/guide/index.xhtml')
-rw-r--r-- | documentation/cxx/hybrid/guide/index.xhtml | 6521 |
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="© 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 © 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"> -<?xml version="1.0"?> -<hello> - - <greeting>Hello</greeting> - - <name>sun</name> - <name>moon</name> - <name>world</name> - -</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"> -<?xml version="1.0"?> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - <xs:complexType name="hello"> - <xs:sequence> - <xs:element name="greeting" type="xs:string"/> - <xs:element name="name" type="xs:string" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - - <xs:element name="hello" type="hello"/> - -</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& - greeting () const; - - std::string& - greeting (); - - void - greeting (const std::string&); - - // 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& - name () const; - - name_sequence& - 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 <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 << h->greeting () << ", " << *i << "!" << endl; - } - - delete h; - } - catch (const xml_schema::parser_exception& e) - { - cerr << argv[1] << ":" << e.line () << ":" << e.column () - << ": " << e.text () << 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 <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& e) - { - cerr << argv[1] << ":" << e.line () << ":" << e.column () - << ": " << e.text () << endl; - return 1; - } - catch (const xml_schema::serializer_exception& e) - { - cerr << "error: " << e.text () << 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"> -<hello> - <greeting>Hi</greeting> - <name>sun</name> - <name>moon</name> - <name>world</name> - <name>mars</name> -</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 <sstream> -#include <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& 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 << ostr.str () << endl; - } - catch (const xml_schema::serializer_exception& e) - { - cerr << "error: " << e.text () << 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"> -<hello> - <greeting>Hi</greeting> - <name>Jane</name> - <name>John</name> -</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 <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) && ferror (f)) - { - io_error = true; - break; - } - - doc_p.parse (buf, s, feof (f) != 0); - pe = doc_p._error (); - - } while (!pe && !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"> -<!-- base.xsd --> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - <xs:complexType name="base"> - <xs:sequence> - <xs:element name="b" type="xs:int"/> - </xs:sequence> - </xs:complexType> - - <!-- substitution group root --> - <xs:element name="base" type="base"/> - -</xs:schema> - </pre> - - <pre class="xml"> -<!-- derived.xsd --> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - <include schemaLocation="base.xsd"/> - - <xs:complexType name="derived"> - <xs:complexContent> - <xs:extension base="base"> - <xs:sequence> - <xs:element name="d" type="xs:string"/> - </xs:sequence> - </xs:extension> - </xs:complexContent> - </xs:complexType> - - <xs:element name="derived" type="derived" substitutionGroup="base"/> - -</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"> -<!-- base.xsd --> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - <xs:complexType name="base"> - <xs:sequence> - <xs:element name="b" type="xs:int"/> - </xs:sequence> - </xs:complexType> - - <!-- substitution group root --> - <xs:element name="base" type="base"/> - - <xs:complexType name="root"> - <xs:sequence> - <xs:element ref="base" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - - <!-- document root --> - <xs:element name="root" type="root"/> - -</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"> -<?xml version="1.0"?> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - <xs:simpleType name="gender"> - <xs:restriction base="xs:string"> - <xs:enumeration value="male"/> - <xs:enumeration value="female"/> - </xs:restriction> - </xs:simpleType> - - <xs:complexType name="person"> - <xs:sequence> - <xs:element name="first-name" type="xs:string"/> - <xs:element name="middle-name" type="xs:string" minOccurs="0"/> - <xs:element name="last-name" type="xs:string"/> - <xs:element name="gender" type="gender"/> - <xs:element name="age" type="xs:unsignedShort"/> - </xs:sequence> - <xs:attribute name="id" type="xs:unsignedInt" use="required"/> - </xs:complexType> - - <xs:complexType name="people"> - <xs:sequence> - <xs:element name="person" type="person" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - - <xs:element name="people" type="people"/> - -</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"> -<?xml version="1.0"?> -<people> - - <person id="1"> - <first-name>John</first-name> - <last-name>Doe</last-name> - <gender>male</gender> - <age>32</age> - </person> - - <person id="2"> - <first-name>Jane</first-name> - <middle-name>Mary</middle-name> - <last-name>Doe</last-name> - <gender>female</gender> - <age>28</age> - </person> - -</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&); - gender& operator= (const gender&); - - void - value (value_type); - - operator value_type () const; - - const char* - string () const; - -private: - ... -}; - -// person (fixed-length) -// -class person -{ -public: - person (); - person (const person&); - person& operator= (const person&); - - // id - // - unsigned int - id () const; - - unsigned int& - id (); - - void - id (unsigned int); - - // first-name - // - const std::string& - first_name () const; - - std::string& - first_name (); - - void - first_name (const std::string&); - - // middle-name - // - bool - middle_name_present () const; - - void - middle_name_present (bool); - - const std::string& - middle_name () const; - - std::string& - middle_name (); - - void - middle_name (const std::string&); - - // last-name - // - const std::string& - last_name () const; - - std::string& - last_name (); - - void - last_name (const std::string&); - - // gender - // - const ::gender& - gender () const; - - ::gender& - gender (); - - void - gender (const ::gender&); - - // age - // - unsigned short - age () const; - - unsigned short& - age (); - - void - age (unsigned short); - -private: - ... -}; - -// people (variable-length) -// -class people -{ -public: - people (); - -private: - people (const people&); - people& operator= (const people&); - -public: - // person - // - typedef xml_schema::fix_sequence<person> person_sequence; - typedef person_sequence::iterator person_iterator; - typedef person_sequence::const_iterator person_const_iterator; - - const person_sequence& - person () const; - - person_sequence& - 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"> -<xs:complexType name="staff"> - <xs:sequence> - <xs:element name="permanent" type="people"/> - <xs:element name="contract" type="people"/> - </xs:sequence> -</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&); - staff& operator= (const staff&); - -public: - // permanent - // - const people& - permanent () const; - - people& - permanent (); - - void - permanent (people*); - - people* - permanent_detach (); - - // contract - // - const people& - contract () const; - - people& - 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&); - gender& operator= (const gender&); - - 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 << g.string () << 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& - first_name () const; - - std::string& - first_name (); - - void - first_name (const std::string&); -}; - </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& - middle_name () const; - - std::string& - middle_name (); - - void - middle_name (const std::string&); -}; - </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& p = ... - -if (p.middle_name_present ()) -{ - cout << p.middle_name () << 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& p = ... - -if (p.middle_name_present ()) -{ - cout << *p.middle_name () << 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"> -<xs:complexType name="person"> - <xs:sequence> - <xs:element name="first-name" type="xs:string"/> - ... - </xs:sequence> - <xs:attribute name="id" type="xs:unsignedInt" use="required"/> - <xs:attribute name="verified" type="xs:boolean" default="false"/> -</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& - 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& x = ... - -if (x.foo_default ()) -{ - foo& 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"> -<xs:complexType name="person"> - ... - <xs:attribute name="verified" type="xs:boolean" fixed="true"/> -</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<person> person_sequence; - typedef person_sequence::iterator person_iterator; - typedef person_sequence::const_iterator person_const_iterator; - - const person_sequence& - person () const; - - person_sequence& - 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 <typename T> - class fix_sequence - { - public: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& 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&); - - private: - fix_sequence (const fix_sequence&); - - fix_sequence& - operator= (fix_sequence&); - - public: - iterator - begin (); - - const_iterator - begin () const; - - iterator - end (); - - const_iterator - end () const; - - T& - front (); - - const T& - front () const; - - T& - back (); - - const T& - back () const; - - T& - operator[] (size_t); - - const T& - 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&); - - iterator - insert (iterator, const T&); - - 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 <typename T> - class fix_sequence - { - public: - enum error - { - error_none, - error_no_memory - }; - - ... - - public: - error - push_back (const T&); - - error - insert (iterator, const T&); - - error - insert (iterator, const T&, iterator& 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 <typename T> - class var_sequence - { - public: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - typedef <implementation details> iterator; - typedef <implementation details> const_iterator; - - public: - var_sequence (); - - void - swap (var_sequence&); - - private: - var_sequence (const var_sequence&); - - var_sequence& - operator= (var_sequence&); - - public: - iterator - begin (); - - const_iterator - begin () const; - - iterator - end (); - - const_iterator - end () const; - - T& - front (); - - const T& - front () const; - - T& - back (); - - const T& - back () const; - - T& - operator[] (size_t); - - const T& - 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 <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& 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<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&); - - private: - string_sequence (string_sequence&); - - string_sequence& - operator= (string_sequence&); - - 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& 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"> -<complexType name="type"> - <sequence> - <sequence minOccurs="0"> - <element name="a" type="int"/> - <element name="b" type="string" maxOccurs="unbounded"/> - </sequence> - <sequence maxOccurs="unbounded"> - <element name="c" type="int"/> - <element name="d" type="string"/> - </sequence> - </sequence> -</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&); - type& operator= (const type&); - -public: - // sequence (variable-length) - // - class sequence_type - { - public: - sequence_type (); - - private: - sequence_type (const sequence_type&); - sequence_type& operator= (const sequence_type&); - - public: - // a - // - int - a () const; - - int& - 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& - b () const; - - b_sequence& - b (); - - private: - ... - }; - - bool - sequence_present () const; - - const sequence_type& - sequence () const; - - sequence_type& - sequence (); - - void - sequence (sequence_type*); - - // sequence1 (fixed-length) - // - class sequence1_type - { - public: - sequence1_type (); - sequence1_type (const sequence1_type&); - sequence1_type& operator= (const sequence1_type&); - - // c - // - int - c () const; - - int& - c (); - - void - c (int); - - // d - // - const std::string& - d () const; - - std::string& - d (); - - void - d (const std::string&); - - private: - ... - }; - - typedef xml_schema::fix_sequence<sequence1_type> sequence1_sequence; - typedef sequence1_sequence::iterator sequence1_iterator; - typedef sequence1_sequence::const_iterator sequence1_const_iterator; - - const sequence1_sequence& - sequence1 () const; - - sequence1_sequence& - 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"> -<complexType name="type"> - <choice> - <element name="a" type="int"/> - <element name="b" type="string"/> - <element name="c" type="boolean"/> - </choice> -</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&); - type& operator= (const type&); - - // 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& - a (); - - void - a (int); - - // b - // - const std::string& - b () const; - - std::string& - b (); - - void - b (const std::string&); - - // c - // - bool - c () const; - - bool& - 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& x = ... - -switch (x.choice_arm ()) -{ -case type::a_tag: - { - cout << "a: " << x.a () << endl; - break; - } -case type::b_tag: - { - cout << "b: " << x.b () << endl; - break; - } -case type::c_tag: - { - cout << "c: " << x.c () << 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"> -<complexType name="type"> - <choice maxOccurs="unbounded"> - <sequence> - <element name="a" type="int"/> - <element name="b" type="string"/> - </sequence> - <element name="c" type="boolean"/> - </choice> -</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&); - type& operator= (const type&); - -public: - // choice (fixed-length) - // - class choice_type - { - public: - choice_type (); - choice_type (const choice_type&); - choice_type& operator= (const choice_type&); - - 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&); - sequence_type& operator= (const sequence_type&); - - // a - // - int - a () const; - - int& - a (); - - void - a (int); - - // b - // - const std::string& - b () const; - - std::string& - b (); - - void - b (const std::string&); - - private: - ... - }; - - const sequence_type& - sequence () const; - - sequence_type& - sequence (); - - void - sequence (const sequence_type&); - - // c - // - bool - c () const; - - bool& - c (); - - void - c (bool); - - private: - ... - }; - - typedef xml_schema::fix_sequence<choice_type> choice_sequence; - typedef choice_sequence::iterator choice_iterator; - typedef choice_sequence::const_iterator choice_const_iterator; - - const choice_sequence& - choice () const; - - choice_sequence& - 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 <memory> -#include <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<people> ppl (people_p.post ()); - - // Iterate over individual person records. - // - people::person_sequence& ps = ppl->person (); - - for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) - { - person& p = *i; - - // Print names: first-name and last-name are required elements, - // middle-name is optional. - // - cout << "name: " << p.first_name () << " "; - - if (p.middle_name_present ()) - cout << p.middle_name () << " "; - - cout << p.last_name () << endl; - - // Print gender, age, and id which are all required. - // - cout << "gender: " << p.gender ().string () << endl - << "age: " << p.age () << endl - << "id: " << p.id () << endl - << 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 <memory> -#include <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<people> ppl (people_p.post ()); - - // Iterate over individual person records and increment - // the age. - // - people::person_sequence& 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& john = ps[0]; - person& 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"> -<?xml version="1.0"?> -<people> - - <person id="1"> - <first-name>John</first-name> - <middle-name>Mary</middle-name> - <last-name>Doe</last-name> - <gender>male</gender> - <age>33</age> - </person> - - <person id="2"> - <first-name>Jane</first-name> - <last-name>Doe</last-name> - <gender>female</gender> - <age>29</age> - </person> - - <person id="1"> - <first-name>John</first-name> - <middle-name>Mary</middle-name> - <last-name>Doe</last-name> - <gender>male</gender> - <age>33</age> - </person> - -</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 <iostream> - -#include "people.hxx" -#include "people-simpl.hxx" - -using namespace std; - -int -main () -{ - people ppl; - people::person_sequence& 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"> -<?xml version="1.0" ?> -<people> - - <person id="1"> - <first-name>John</first-name> - <last-name>Doe</last-name> - <gender>male</gender> - <age>32</age> - </person> - - <person id="2"> - <first-name>Jane</first-name> - <middle-name>Mary</middle-name> - <last-name>Doe</last-name> - <gender>female</gender> - <age>28</age> - </person> - -</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& - custom_data () const; - - custom_data_sequence& - 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&); - - private: - data_sequence (const data_sequence&); - - data_sequence& - operator= (data_sequence&); - - 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& 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<data*> (p); -} - -person& = ...; -person::custom_data_sequence& cd = p.custom_data (); - -cd.destructor (&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<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<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<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<person> person_sequence; - typedef person_sequence::iterator person_iterator; - typedef person_sequence::const_iterator person_const_iterator; - - const person_sequence& - person () const; - - person_sequence& - 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& 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"> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - <xs:complexType name="person"> - <xs:sequence> - <xs:element name="name" type="xs:string"/> - </xs:sequence> - </xs:complexType> - - <!-- substitution group root --> - <xs:element name="person" type="person"/> - - <xs:complexType name="superman"> - <xs:complexContent> - <xs:extension base="person"> - <xs:attribute name="can-fly" type="xs:boolean"/> - </xs:extension> - </xs:complexContent> - </xs:complexType> - - <xs:element name="superman" - type="superman" - substitutionGroup="person"/> - - <xs:complexType name="batman"> - <xs:complexContent> - <xs:extension base="superman"> - <xs:attribute name="wing-span" type="xs:unsignedInt"/> - </xs:extension> - </xs:complexContent> - </xs:complexType> - - <xs:element name="batman" - type="batman" - substitutionGroup="superman"/> - - <xs:complexType name="supermen"> - <xs:sequence> - <xs:element ref="person" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - - <xs:element name="supermen" type="supermen"/> - -</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"> -<supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - - <person> - <name>John Doe</name> - </person> - - <superman can-fly="false"> - <name>James "007" Bond</name> - </superman> - - <superman can-fly="true" wing-span="10" xsi:type="batman"> - <name>Bruce Wayne</name> - </superman> - -</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<supermen> sm (supermen_p.post ()); - -// Print what we've got. -// -for (supermen::person_iterator i = sm->person ().begin (); - i != sm->person ().end (); - ++i) -{ - person& p = *i; - - if (batman* b = dynamic_cast<batman*> (&p)) - { - cerr << b->name () << ", batman, wing span " << - b->wing_span () << endl; - } - else if (superman* s = dynamic_cast<superman*> (&p)) - { - cerr << s->name () << ", "; - - if (s->can_fly ()) - cerr << "flying "; - - cerr << "superman" << endl; - } - else - { - cerr << p.name () << ", ordinary person" << endl; - } -} - -// Add another superman entry. -// -auto_ptr<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& -_dynamic_type () const; - -static const std::string& -_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& p = *i; - const string& dt = p._dynamic_type (); - - if (dt == batman::_static_type ()) - { - batman& b = static_cast<batman&> (p) - cerr << b.name () << ", batman, wing span " << - b.wing_span () << endl; - } - else if (dt == superman::_static_type ()) - { - superman& s = static_cast<superman&> (p) - cerr << s.name () << ", "; - - if (s.can_fly ()) - cerr << "flying "; - - cerr << "superman" << endl; - } - else - { - cerr << p.name () << ", ordinary person" << 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 char</code></td> - </tr> - <tr> - <td><code>unsignedByte</code></td> - <td><code>unsigned_byte</code></td> - <td><code>unsigned 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 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 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 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 long</code> or - <code>unsigned long 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"> -<complexType name="measure"> - <simpleContent> - <extension base="int"> - <attribute name="unit" type="string" use="required"/> - </extension> - </simpleContent> -</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&); - measure& operator= (const measure&); - - // unit - // - const std::string& - unit () const; - - std::string& - unit (); - - void - unit (const std::string&); - -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& - operator= (int); - - public: - int - base_value () const; - - int& - base_value (); - - void - base_value (int); - - operator const int& () const; - operator int& (); - }; -} - </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& - 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& name); - qname (const std::string& prefix, const std::string& name); - - void - swap (qname&); - - const std::string& - prefix () const; - - std::string& - prefix (); - - void - prefix (const std::string&); - - const std::string& - name () const; - - std::string& - name (); - - void - name (const std::string&); - }; - - bool - operator== (const qname&, const qname&); - - bool - operator!= (const qname&, const qname&); -} - </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&); - - private: - qname (const qname&); - - qname& - operator= (const qname&); - - 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&, const qname&); - - bool - operator!= (const qname&, const qname&); -} -</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&); - - private: - qname (const qname&); - - qname& - operator= (const qname&); - - 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&, const qname&); - - bool - operator!= (const qname&, const qname&); -} - </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&); - - buffer& - operator= (const buffer&); - - public: - void - assign (void* data, size_t size); - - void - attach (void* data, size_t size, size_t capacity); - - void* - detach (); - - - void - swap (buffer&); - - 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&, const buffer&); - - bool - operator!= (const buffer&, const buffer&); -} - </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 <= 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&); - - buffer& - operator= (const buffer&); - - public: - error - assign (void* data, size_t size); - - error - attach (void* data, size_t size, size_t capacity); - - void* - detach (); - - void - swap (buffer&); - - public: - size_t - capacity () const; - - error - capacity (size_t); - - error - capacity (size_t, bool& moved); - - public: - size_t - size () const; - - error - size (size_t); - - error - size (size_t, bool& moved); - - public: - const char* - data () const; - - char* - data (); - - const char* - begin () const; - - char* - begin (); - - const char* - end () const; - - char* - end (); - }; - - bool - operator== (const buffer&, const buffer&); - - bool - operator!= (const buffer&, const buffer&); -} - </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&, const time_zone&); - - bool - operator!= (const time_zone&, const time_zone&); -} - </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&, const date&); - - bool - operator!= (const date&, const date&); -} - </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&, const date_time&); - - bool - operator!= (const date_time&, const date_time&); -} - </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&, const duration&); - - bool - operator!= (const duration&, const duration&); -} - </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&, const gday&); - - bool - operator!= (const gday&, const gday&); -} - </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&, const gmonth&); - - bool - operator!= (const gmonth&, const gmonth&); -} - </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&, const gmonth_day&); - - bool - operator!= (const gmonth_day&, const gmonth_day&); -} - </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&, const gyear&); - - bool - operator!= (const gyear&, const gyear&); -} - </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&, const gyear_month&); - - bool - operator!= (const gyear_month&, const gyear_month&); -} - </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&, const time&); - - bool - operator!= (const time&, const time&); -} - </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& - custom_data () const; - - custom_data_sequence& - 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& - custom_data () const; - - custom_data_sequence& - 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"> -<?xml version="1.0"?> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - <xs:complexType name="hello"> - <xs:sequence> - <xs:element name="greeting" type="xs:string"/> - <xs:element name="name" type="xs:string" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - - <xs:element name="hello" type="hello"/> - -</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& - 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&); - - void - post (); - - hello_simpl& - 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& p) - { - // Check if the age constraints are met. - // - unsigned short age = p.age (); - - if (age >= min_age_ && age <= 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_ && age <= 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& i = people_base_simpl_state_.person_; - people::person_const_iterator& 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 <memory> -#include <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& 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<people> ppl (people_p.post ()); - - // Print what we've got. - // - people::person_sequence& ps = ppl->person (); - - for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) - { - cerr << "first: " << i->first_name () << endl - << "last: " << i->last_name () << endl - << "gender: " << i->gender ().string () << endl - << "age: " << i->age () << endl - << endl; - } - - // Serialize. - // - people_saggr people_s; - people_simpl& 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"> -<?xml version="1.0"?> -<people> - - <person> - <first-name>John</first-name> - <last-name>Doe</last-name> - <gender>male</gender> - <age>32</age> - </person> - - <person> - <first-name>Jane</first-name> - <last-name>Doe</last-name> - <gender>female</gender> - <age>28</age> - </person> - - <person> - <first-name>Joe</first-name> - <last-name>Dirt</last-name> - <gender>male</gender> - <age>25</age> - </person> - -</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 - -<people> - <person> - <first-name>Jane</first-name> - <last-name>Doe</last-name> - <gender>female</gender> - <age>28</age> - </person> -</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<<</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<< (ostream&, const type&); - -void -operator>> (istream&, type&); - </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<< (ostream&, const type&); - -bool -operator>> (istream&, type&); - </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& x = ... // Object model. - - // Save to a CDR stream. - // - ACE_OutputCDR ace_ocdr; - xml_schema::ocdrstream ocdr (ace_ocdr); - - ocdr << 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&) -{ - cerr << "CDR operation failed" << endl; -} - </pre> - - <p>The same code fragment but when C++ exceptions are disabled:</p> - - <pre class="c++"> -const type& x = ... // Object model. - -// Save to a CDR stream. -// -ACE_OutputCDR ace_ocdr; -xml_schema::ocdrstream ocdr (ace_ocdr); - -if (!(ocdr << x)) -{ - cerr << "CDR operation failed" << endl; -} - -// Load from a CDR stream. -// -ACE_InputCDR ace_icdr (buf, size); -xml_schema::icdrstream icdr (ace_icdr); - -type copy; - -if (!(icdr >> copy)) -{ - cerr << "CDR operation failed" << 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& x = ... // Object model. - - // Save to a XDR stream. - // - XDR xdr; - xdrrec_create (&xdr, ...); - xml_schema::oxdrstream oxdr (xdr); - - oxdr << x; - - // Load from a XDR stream. - // - xdrrec_create (&xdr, ...); - xml_schema::ixdrstream ixdr (xdr); - - type copy; - ixdr >> copy; -} -catch (const xml_schema::xdr_exception&) -{ - cerr << "XDR operation failed" << endl; -} - </pre> - - <p>The same code fragment but when C++ exceptions are disabled:</p> - - <pre class="c++"> -const type& x = ... // Object model. - -// Save to a XDR stream. -// -XDR xdr; -xdrrec_create (&xdr, ...); -xml_schema::oxdrstream oxdr (xdr); - -if (!(oxdr << x)) -{ - cerr << "XDR operation failed" << endl; -} - -// Load from a XDR stream. -// -xdrrec_create (&xdr, ...); -xml_schema::ixdrstream ixdr (xdr); - -type copy; - -if (!(ixdr >> copy)) -{ - cerr << "XDR operation failed" << 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> |