diff options
author | Jörg Frings-Fürst <debian@jff.email> | 2024-03-06 10:24:08 +0100 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff.email> | 2024-03-06 10:24:08 +0100 |
commit | aad5ad9bf0c02aa4e79bc6b7d6c934612fff4026 (patch) | |
tree | 9cc224b059f248a6229ab0dcdc64eb4a73fa9800 /doc/cxx/tree | |
parent | c1034fc5e99197f507caf450aa15bc178698b26e (diff) |
New upstream version 4.2.0upstream/4.2.0upstream
Diffstat (limited to 'doc/cxx/tree')
-rw-r--r-- | doc/cxx/tree/guide/guide.html2ps.in | 65 | ||||
-rw-r--r-- | doc/cxx/tree/guide/index.xhtml | 2736 | ||||
-rw-r--r-- | doc/cxx/tree/guide/index.xhtml.in | 2736 | ||||
-rw-r--r-- | doc/cxx/tree/manual/index.xhtml | 6826 | ||||
-rw-r--r-- | doc/cxx/tree/manual/index.xhtml.in | 6826 | ||||
-rw-r--r-- | doc/cxx/tree/manual/manual.html2ps.in | 66 |
6 files changed, 19255 insertions, 0 deletions
diff --git a/doc/cxx/tree/guide/guide.html2ps.in b/doc/cxx/tree/guide/guide.html2ps.in new file mode 100644 index 0000000..461ffde --- /dev/null +++ b/doc/cxx/tree/guide/guide.html2ps.in @@ -0,0 +1,65 @@ +@@html2ps { + option { + toc: hb; + colour: 1; + hyphenate: 1; + titlepage: 1; + } + + datefmt: "%B %Y"; + + titlepage { + content: " +<div align=center> + <h1><big>C++/Tree Mapping</big></h1> + <h1><big>Getting Started Guide</big></h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> +</div> + <p>Copyright © @copyright@.</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href='https://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='https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/index.xhtml'>XHTML</a>, + <a href='https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/cxx-parser-guide.pdf'>PDF</a>, and + <a href='https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/cxx-parser-guide.ps'>PostScript</a>.</p>"; + } + + toc { + indent: 2em; + } + + header { + odd-right: $H; + even-left: $H; + } + + footer { + odd-left: $D; + odd-center: $T; + odd-right: $N; + + even-left: $N; + even-center: $T; + even-right: $D; + } +} + +body { + font-size: 12pt; + text-align: justify; +} + +pre { + font-size: 10pt; +} diff --git a/doc/cxx/tree/guide/index.xhtml b/doc/cxx/tree/guide/index.xhtml new file mode 100644 index 0000000..fdaaa45 --- /dev/null +++ b/doc/cxx/tree/guide/index.xhtml @@ -0,0 +1,2736 @@ +<?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>C++/Tree Mapping Getting Started Guide</title> + + <meta name="copyright" content="© 2005-2023 Code Synthesis"/> + <meta name="keywords" content="xsd,xml,schema,c++,mapping,data,binding,parsing,serialization,validation"/> + <meta name="description" content="C++/Tree 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 { + 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; + } + + /* 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; + } + + /* 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; + } +</style> + + +</head> + +<body> +<div id="container"> + <div id="content"> + + <div class="noprint"> + + <div id="titlepage"> + <div class="title" id="first-title">C++/Tree Mapping</div> + <div class="title" id="second-title">Getting Started Guide</div> + + <p>Copyright © 2005-2023 Code Synthesis.</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href="https://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="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/index.xhtml">XHTML</a>, + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/cxx-tree-guide.pdf">PDF</a>, and + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/cxx-tree-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">Selecting Naming Convention</a></td></tr> + <tr><th>2.7</th><td><a href="#2.7">Generating Documentation</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">Overall Mapping Configuration</a> + <table class="toc"> + <tr><th>3.1</th><td><a href="#3.1">C++ Standard</a></td></tr> + <tr><th>3.2</th><td><a href="#3.2">Character Type and Encoding</a></td></tr> + <tr><th>3.3</th><td><a href="#3.3">Support for Polymorphism </a></td></tr> + <tr><th>3.4</th><td><a href="#3.4">Namespace Mapping</a></td></tr> + <tr><th>3.5</th><td><a href="#3.5">Thread Safety</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">Attribute and Element Cardinalities</a></td></tr> + <tr><th>4.2</th><td><a href="#4.2">Accessing the Object Model</a></td></tr> + <tr><th>4.3</th><td><a href="#4.3">Modifying the Object Model</a></td></tr> + <tr><th>4.4</th><td><a href="#4.4">Creating the Object Model from Scratch</a></td></tr> + <tr><th>4.5</th><td><a href="#4.5">Mapping for the Built-in XML Schema Types</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>5</th><td><a href="#5">Parsing</a> + <table class="toc"> + <tr><th>5.1</th><td><a href="#5.1">XML Schema Validation and Searching</a></td></tr> + <tr><th>5.2</th><td><a href="#5.2">Error Handling</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>6</th><td><a href="#6">Serialization</a> + <table class="toc"> + <tr><th>6.1</th><td><a href="#6.1">Namespace and Schema Information</a></td></tr> + <tr><th>6.2</th><td><a href="#6.2">Error Handling</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++/Tree programming model and allow you to efficiently evaluate + XSD against your project's technical requirements. As such, this + document is intended for C++ developers and software architects + who are looking for an XML processing solution. For a more in-depth + description of the C++/Tree mapping refer to the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/">C++/Tree + Mapping User Manual</a>.</p> + + <p>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="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/">C++/Tree + Mapping User Manual</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/Customization_guide">C++/Tree + Mapping Customization Guide</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree + Mapping Frequently Asked Questions (FAQ)</a></li> + + <li><a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a></li> + + <li>The <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + contains a collection of examples and a README file with an overview + of each example.</li> + + <li>The <code>README</code> file in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + explains how to build the examples.</li> + + <li>The <a href="https://www.codesynthesis.com/mailman/listinfo/xsd-users">xsd-users</a> + mailing list is the place to ask technical questions about XSD and the C++/Parser mapping. + Furthermore, the <a href="https://www.codesynthesis.com/pipermail/xsd-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 and the C++/Tree mapping. XSD is a + cross-platform W3C XML Schema to C++ data binding compiler. C++/Tree + is a W3C XML Schema to C++ mapping that represents the data stored + in XML as a statically-typed, vocabulary-specific 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++/Tree 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 as well as XML parsing and + serialization code.</p> + + <p>Besides the core features, C++/Tree provide a number of additional + mapping elements that can be useful in some applications. These + include serialization and extraction to/from formats others than + XML, such as unstructured text (useful for debugging) and binary + representations such as XDR and CDR for high-speed data processing + as well as automatic documentation generation. The C++/Tree mapping + also provides a wide range of mechanisms for controlling and + customizing the generated code.</p> + + <p>A typical application that uses C++/Tree for XML processing usually + 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.</p> + + <p>The next chapter presents a simple application that performs these + three steps. The following chapters show how to use the C++/Tree + 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) have a number of drawbacks that + make them less suitable for creating robust and maintainable + 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 because the data is represented as text.</li> + + <li>Resulting applications are hard to debug, change, and + maintain.</li> + </ul> + + <p>In contrast, statically-typed, vocabulary-specific object model + produced by the C++/Tree mapping allows you to operate in your + domain terms instead of the generic elements, attributes, and + text. 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++/Tree 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>Compatibility.</b> Sequences of elements are represented in + the object model as containers conforming to the standard C++ + sequence requirements. This makes it possible to use standard + C++ algorithms on the object representation and frees you from + learning yet another container interface, as is the case with + DOM.</li> + + <li><b>Efficiency.</b> If the application makes repetitive use + of the data extracted from XML, then the C++/Tree 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. Furthermore, the runtime memory + usage is 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.</li> + </ul> + + + <!-- Hello World Parser --> + + + <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 XSD-generated + C++/Tree object model. The code presented in this chapter is + based on the <code>hello</code> example which can be found in + the <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package.</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_t"> + <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_t"/> + +</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_t</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. We can also update our <code>hello.xml</code> to include the + information about the schema so that XML parsers can validate + our document:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="hello.xsd"> + + <greeting>Hello</greeting> + + <name>sun</name> + <name>moon</name> + <name>world</name> + +</hello> + </pre> + + + <p>The next step is to compile the schema to generate the object + model and parsing functions.</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 compiler from a terminal (UNIX) or + a command prompt (Windows): + </p> + + <pre class="terminal"> +$ xsd cxx-tree hello.xsd + </pre> + + <p>The XSD compiler produces two C++ files: <code>hello.hxx</code> and + <code>hello.cxx</code>. The following code fragment is taken from + <code>hello.hxx</code>; it should give you an idea about what gets + generated: + </p> + + <pre class="c++"> +class hello_t +{ +public: + // greeting + // + typedef xml_schema::string greeting_type; + + const greeting_type& + greeting () const; + + greeting_type& + greeting (); + + void + greeting (const greeting_type& x); + + // name + // + typedef xml_schema::string name_type; + typedef xsd::sequence<name_type> name_sequence; + typedef name_sequence::iterator name_iterator; + typedef name_sequence::const_iterator name_const_iterator; + + const name_sequence& + name () const; + + name_sequence& + name (); + + void + name (const name_sequence& s); + + // Constructor. + // + hello_t (const greeting_type&); + + ... + +}; + +std::unique_ptr<hello_t> +hello (const std::string& uri); + +std::unique_ptr<hello_t> +hello (std::istream&); + </pre> + + <p>The <code>hello_t</code> C++ class corresponds to the + <code>hello_t</code> XML Schema type. For each element + in this type a set of C++ type definitions as well as + accessor and modifier functions are generated inside the + <code>hello_t</code> class. Note that the type definitions + and member functions for the <code>greeting</code> and + <code>name</code> elements are different because of the + cardinality differences between these two elements + (<code>greeting</code> is a required single element and + <code>name</code> is a sequence of elements).</p> + + <p>The <code>xml_schema::string</code> type used in the type + definitions is a C++ class provided by the XSD runtime + that corresponds to built-in XML Schema type + <code>string</code>. The <code>xml_schema::string</code> + is based on <code>std::string</code> and can be used as + such. Similarly, the <code>sequence</code> class template + that is used in the <code>name_sequence</code> type + definition is based on and has the same interface as + <code>std::vector</code>. The mapping between the built-in + XML Schema types and C++ types is described in more detail in + <a href="#4.5">Section 4.5, "Mapping for the Built-in XML Schema + Types"</a>. The <code>hello_t</code> class also includes a + constructor with an initializer for the required + <code>greeting</code> element as its argument.</p> + + <p>The <code>hello</code> overloaded global functions correspond + to the <code>hello</code> global element in XML Schema. A + global element in XML Schema is a valid document root. + By default XSD generated a set of parsing functions for each + global element defined in XML Schema (this can be overridden + with the <code>--root-element-*</code> options). Parsing + functions return a dynamically allocated object model as an + automatic pointer. The actual pointer used depends on the + C++ standard selected. For C++11 it is <code>std::unique_ptr</code> + as shown above. For C++98 it is <code>std::auto_ptr</code>. + For example, if we modify our XSD compiler invocation to + select C++98:</p> + + <pre class="terminal"> +$ xsd cxx-tree --std c++98 hello.xsd + </pre> + + <p>Then the parsing function signatures will become:</p> + + <pre class="c++"> +std::auto_ptr<hello_t> +hello (const std::string& uri); + +std::auto_ptr<hello_t> +hello (std::istream&); + </pre> + + <p>For more information on parsing functions see <a href="#5">Chapter 5, + "Parsing"</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" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + unique_ptr<hello_t> h (hello (argv[1])); + + for (hello_t::name_const_iterator i (h->name ().begin ()); + i != h->name ().end (); + ++i) + { + cerr << h->greeting () << ", " << *i << "!" << endl; + } + } + catch (const xml_schema::exception& e) + { + cerr << e << endl; + return 1; + } +} + </pre> + + <p>The first part of our application calls one of the parsing + functions to parser an XML file specified in the command line. + We then use the returned object model to iterate over names + and print a greeting line for each of them. Finally, we + catch and print the <code>xml_schema::exception</code> + exception in case something goes wrong. This exception + is the root of the exception hierarchy used by the + XSD-generated code. + </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 a UNIX + system this can be done with the following commands: + </p> + + <pre class="terminal"> +$ c++ -std=c++11 -I.../libxsd -c driver.cxx hello.cxx +$ c++ -std=c++11 -o driver driver.o hello.o -lxerces-c +$ ./driver hello.xml +Hello, sun! +Hello, moon! +Hello, world! + </pre> + + <p>Here <code>.../libxsd</code> represents the path to the + <a href="https://cppget.org/libxsd">libxsd</a> package root + directory. Note also that we are required to link our + application with the Xerces-C++ library because the generated + code uses it as the underlying XML parser.</p> + + <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. By default XSD does + not produce serialization code. We will need to request + it with the <code>--generate-serialization</code> options:</p> + + <pre class="terminal"> +$ xsd cxx-tree --generate-serialization hello.xsd + </pre> + + <p>If we now examine the generated <code>hello.hxx</code> file, + we will find a set of overloaded serialization functions, + including the following version:</p> + + <pre class="c++"> +void +hello (std::ostream&, + const hello_t&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap ()); + + </pre> + + <p>Just like with parsing functions, XSD generates serialization + functions for each global element unless instructed otherwise + with one of the <code>--root-element-*</code> options. For more + information on serialization functions see <a href="#6">Chapter 6, + "Serialization"</a>.</p> + + <p>We 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" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + unique_ptr<hello_t> h (hello (argv[1])); + + // 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. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "hello.xsd"; + + hello (cout, *h, map); + } + catch (const xml_schema::exception& e) + { + cerr << e << 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 serializes the object model back to XML by calling + the serialization function.</p> + + <p>The first argument we pass to the serialization function is + <code>cout</code> which results in the XML being written to + the standard output 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 instead of <code>cout</code>. The second argument is the + object model we want to serialize. The final argument is an optional + namespace information map for our vocabulary. It captures information + such as namespaces, namespace prefixes to which they should be mapped, + and schemas associated with these namespaces. If we don't provide + this argument then generic namespace prefixes (<code>p1</code>, + <code>p2</code>, etc.) will be automatically assigned to XML namespaces + and no schema information will be added to the resulting document + (see <a href="#6">Chapter 6, "Serialization"</a> for details). + In our case, the prefix (map key) and namespace name are empty + because our vocabulary does not use XML namespaces.</p> + + <p>If we now compile and run this application we will see the + output as shown in the following listing:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="hello.xsd"> + + <greeting>Hi</greeting> + + <name>sun</name> + <name>moon</name> + <name>world</name> + <name>mars</name> + +</hello> + </pre> + + <p>We can also create and serialize an object model from scratch + as shown in the following example:</p> + + <pre class="c++"> +#include <iostream> +#include <fstream> +#include "hello.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + hello_t h ("Hi"); + + hello_t::name_sequence& ns (h.name ()); + + ns.push_back ("Jane"); + ns.push_back ("John"); + + // Serialize the object model to XML. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "hello.xsd"; + + std::ofstream ofs (argv[1]); + hello (ofs, h, map); + } + catch (const xml_schema::exception& e) + { + cerr << e << endl; + return 1; + } +} + </pre> + + <p>In this example we used the generated constructor to create + an instance of type <code>hello_t</code>. To reduce typing, + we obtained a reference to the name sequence which we then + used to add a few names. The serialization part is identical + to the previous example except this time we are writing to + a file. If we compile and run this program, it produces the + following XML file:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="hello.xsd"> + + <greeting>Hi</greeting> + + <name>Jane</name> + <name>John</name> + +</hello> + </pre> + + <h2><a name="2.6">2.6 Selecting Naming Convention</a></h2> + + <p>By default XSD uses the so-called K&R (Kernighan and Ritchie) + identifier naming convention in the generated code. In this + convention both type and function names are in lower case and + words are separated by underscores. If your application code or + schemas use a different notation, you may want to change the + naming convention used in the generated code for consistency. + XSD supports a set of widely-used naming conventions + that you can select with the <code>--type-naming</code> and + <code>--function-naming</code> options. You can also further + refine one of the predefined conventions or create a completely + custom naming scheme by using the <code>--*-regex</code> options.</p> + + <p>As an example, let's assume that our "Hello World" application + uses the so-called upper-camel-case naming convention for types + (that is, each word in a type name is capitalized) and the K&R + convention for function names. Since K&R is the default + convention for both type and function names, we only need to + change the type naming scheme:</p> + + <pre class="terminal"> +$ xsd cxx-tree --type-naming ucc hello.xsd + </pre> + + <p>The <code>ucc</code> argument to the <code>--type-naming</code> + options stands for upper-camel-case. If we now examine the + generated <code>hello.hxx</code>, we will see the following + changes compared to the declarations shown in the previous + sections:</p> + + <pre class="c++"> +class Hello_t +{ +public: + // greeting + // + typedef xml_schema::String GreetingType; + + const GreetingType& + greeting () const; + + GreetingType& + greeting (); + + void + greeting (const GreetingType& x); + + // name + // + typedef xml_schema::String NameType; + typedef xsd::sequence<NameType> NameSequence; + typedef NameSequence::iterator NameIterator; + typedef NameSequence::const_iterator NameConstIterator; + + const NameSequence& + name () const; + + NameSequence& + name (); + + void + name (const NameSequence& s); + + // Constructor. + // + Hello_t (const GreetingType&); + + ... + +}; + +std::unique_ptr<Hello_t> +hello (const std::string& uri); + +std::unique_ptr<Hello_t> +hello (std::istream&); + </pre> + + <p>Notice that the type names in the <code>xml_schema</code> namespace, + for example <code>xml_schema::String</code>, now also use the + upper-camel-case naming convention. The only thing that we may + be unhappy about in the above code is the <code>_t</code> + suffix in <code>Hello_t</code>. If we are not in a position + to change the schema, we can <em>touch-up</em> the <code>ucc</code> + convention with a custom translation rule using the + <code>--type-regex</code> option:</p> + + <pre class="terminal"> +$ xsd cxx-tree --type-naming ucc --type-regex '/ (.+)_t/\u$1/' hello.xsd + </pre> + + <p>This results in the following changes to the generated code:</p> + + <pre class="c++"> +class Hello +{ +public: + // greeting + // + typedef xml_schema::String GreetingType; + + const GreetingType& + greeting () const; + + GreetingType& + greeting (); + + void + greeting (const GreetingType& x); + + // name + // + typedef xml_schema::String NameType; + typedef xsd::sequence<NameType> NameSequence; + typedef NameSequence::iterator NameIterator; + typedef NameSequence::const_iterator NameConstIterator; + + const NameSequence& + name () const; + + NameSequence& + name (); + + void + name (const NameSequence& s); + + // Constructor. + // + Hello (const GreetingType&); + + ... + +}; + +std::unique_ptr<Hello> +hello (const std::string& uri); + +std::unique_ptr<Hello> +hello (std::istream&); + </pre> + + <p>For more detailed information on the <code>--type-naming</code>, + <code>--function-naming</code>, <code>--type-regex</code>, and + other <code>--*-regex</code> options refer to the NAMING + CONVENTION section in the <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>.</p> + + <h2><a name="2.7">2.7 Generating Documentation</a></h2> + + <p>While our object model is quite simple, real-world vocabularies + can be quite complex with hundreds of types, elements, and + attributes. For such vocabularies figuring out which types + provide which member functions by studying the generated + source code or schemas can be a daunting task. To provide + application developers with a more accessible way of + understanding the generated object models, the XSD compiler + can be instructed to produce source code with documentation + comments in the Doxygen format. Then the source code can be + processed with the <a href="http://www.doxygen.org">Doxygen</a> + documentation system to extract this information and produce + documentation in various formats. + </p> + + <p>In this section we will see how to generate documentation + for our "Hello World" vocabulary. To showcase the full power + of the XSD documentation facilities, we will first document + our schema. The XSD compiler will then transfer + this information from the schema to the generated code and + then to the object model documentation. Note that the + documentation in the schema is not required for XSD to + generate useful documentation. Below you will find + our <code>hello.xsd</code> with added documentation:</p> + + <pre class="xml"> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:complexType name="hello_t"> + + <xs:annotation> + <xs:documentation> + The hello_t type consists of a greeting phrase and a + collection of names to which this greeting applies. + </xs:documentation> + </xs:annotation> + + <xs:sequence> + + <xs:element name="greeting" type="xs:string"> + <xs:annotation> + <xs:documentation> + The greeting element contains the greeting phrase + for this hello object. + </xs:documentation> + </xs:annotation> + </xs:element> + + <xs:element name="name" type="xs:string" maxOccurs="unbounded"> + <xs:annotation> + <xs:documentation> + The name elements contains names to be greeted. + </xs:documentation> + </xs:annotation> + </xs:element> + + </xs:sequence> + </xs:complexType> + + <xs:element name="hello" type="hello_t"> + <xs:annotation> + <xs:documentation> + The hello element is a root of the Hello XML vocabulary. + Every conforming document should start with this element. + </xs:documentation> + </xs:annotation> + </xs:element> + +</xs:schema> + </pre> + + <p>The first step in obtaining the documentation is to recompile + our schema with the <code>--generate-doxygen</code> option:</p> + + <pre class="terminal"> +$ xsd cxx-tree --generate-serialization --generate-doxygen hello.xsd + </pre> + + <p>Now the generated <code>hello.hxx</code> file contains comments + in the Doxygen format. The next step is to process this file + with the Doxygen documentation system. If your project does + not use Doxygen then you first need to create a configuration + file for your project:</p> + + <pre class="terminal"> +$ doxygen -g hello.doxygen + </pre> + + <p>You only need to perform this step once. Now we can generate + the documentation by executing the following command in the + directory with the generated source code:</p> + + <pre class="terminal"> +$ doxygen hello.doxygen + </pre> + + <p>While the generated documentation can be useful as is, we can + go one step further and link (using the Doxygen tags mechanism) + the documentation for our object model with the documentation + for the XSD runtime library which defines C++ classes for the + built-in XML Schema types. This way we can seamlessly browse + between documentation for the <code>hello_t</code> class which + is generated by the XSD compiler and the <code>xml_schema::string</code> + class which is defined in the XSD runtime library. The Doxygen + configuration file for the XSD runtime is provided with the XSD + distribution.</p> + + <p>You can view the result of the steps described in this section + on the <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/hello/html/annotated.html">Hello + Example Documentation</a> page.</p> + + <!-- Chapater 3 --> + + + <h1><a name="3">3 Overall Mapping Configuration</a></h1> + + <p>The C++/Tree mapping has a number of configuration parameters that + determine the overall properties and behavior of the generated code. + Configuration parameters are specified with the XSD command line + options. This chapter describes configuration aspects that are most + commonly encountered by application developers. These include: the + C++ standard, the character type that is used by the generated code, + handling of vocabularies that use XML Schema polymorphism, XML Schema + to C++ namespace mapping, and thread safety. For more ways to configure + the generated code refer to the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>. + </p> + + <h2><a name="3.1">3.1 C++ Standard</a></h2> + + <p>The C++/Tree mapping provides support for ISO/IEC C++ 2011 (C++11) + and ISO/IEC C++ 1998/2003 (C++98). To select the C++ standard for the + generated code we use the <code>--std</code> XSD compiler command + line option. While the majority of the examples in this guide use + C++11, the document explains the C++11/98 usage difference and so + they can easily be converted to C++98.</p> + + <h2><a name="3.2">3.2 Character Type and Encoding</a></h2> + + <p>The C++/Tree mapping has built-in support for two character types: + <code>char</code> and <code>wchar_t</code>. You can select the + character type with the <code>--char-type</code> command line + option. The default character type is <code>char</code>. The + character type affects all string and string-based types that + are used in the mapping. These include the string-based built-in + XML Schema types, exception types, stream types, etc.</p> + + <p>Another aspect of the mapping that depends on the character type + is character encoding. For the <code>char</code> character type + the default encoding is UTF-8. Other supported encodings are + ISO-8859-1, Xerces-C++ Local Code Page (LPC), as well as + custom encodings. You can select which encoding should be used + in the object model with the <code>--char-encoding</code> command + line option.</p> + + <p>For the <code>wchar_t</code> character type the encoding is + automatically selected between UTF-16 and UTF-32/UCS-4 depending + on the size of the <code>wchar_t</code> type. On some platforms + (for example, Windows with Visual C++ and AIX with IBM XL C++) + <code>wchar_t</code> is 2 bytes long. For these platforms the + encoding is UTF-16. On other platforms <code>wchar_t</code> is 4 bytes + long and UTF-32/UCS-4 is used.</p> + + <p>Note also that the character encoding that is used in the object model + is independent of the encodings used in input and output XML. In fact, + all three (object mode, input XML, and output XML) can have different + encodings.</p> + + <h2><a name="3.3">3.3 Support for Polymorphism</a></h2> + + <p>By default XSD 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 compile + your schemas with the <code>--generate-polymorphic</code> option + to produce polymorphism-aware code. For more information on + working with polymorphic object models, refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.11">Section 2.11, + "Mapping for <code>xsi:type</code> and Substitution Groups"</a> in + the C++/Tree Mapping User Manual.</p> + + <h2><a name="3.4">3.4 Namespace Mapping</a></h2> + + <p>XSD 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.</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 namespace URI <code>https://www.codesynthesis.com/my</code> to + C++ namespace <code>cs::my</code>, we can use the following option:</p> + + <pre class="terminal"> +--namespace-map https://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:</p> + + <pre class="terminal"> +--namespace-map =cs + </pre> + + <h2><a name="3.5">3.5 Thread Safety</a></h2> + + <p>XSD-generated code is thread-safe in the sense that you can + use different instantiations of the object model in several + threads concurrently. This is possible due to the generated + code not relying on any writable global variables. If you need + to share the same object between several threads then you will + need to provide some form of synchronization. One approach would + be to use the generated code customization mechanisms to embed + synchronization primitives into the generated C++ classes. For more + information on generated code customization refer to the + <a href="http://wiki.codesynthesis.com/Tree/Customization_guide">C++/Tree + Mapping Customization Guide</a>.</p> + + <p>If you also would like to call parsing and/or serialization + functions from several threads potentially concurrently, then + you will need to make sure the Xerces-C++ runtime is initialized + and terminated only once. The easiest way to do this is to + initialize/terminate Xerces-C++ from <code>main()</code> when + there are no threads yet/anymore:</p> + + <pre class="c++"> +#include <xercesc/util/PlatformUtils.hpp> + +int +main () +{ + xercesc::XMLPlatformUtils::Initialize (); + + { + // Start/terminate threads and parse/serialize here. + } + + xercesc::XMLPlatformUtils::Terminate (); +} + </pre> + + <p>Because you initialize the Xerces-C++ runtime yourself you should + also pass the <code>xml_schema::flags::dont_initialize</code> flag + to parsing and serialization functions. See <a href="#5">Chapter 5, + "Parsing"</a> and <a href="#6">Chapter 6, "Serialization"</a> for + more information.</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 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 elements that comprise an + object model class as well as how to create, access, and modify + object models.</p> + + <p>In this and subsequent chapters 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_t"> + <xs:restriction base="xs:string"> + <xs:enumeration value="male"/> + <xs:enumeration value="female"/> + </xs:restriction> + </xs:simpleType> + + <xs:complexType name="person_t"> + <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_t"/> + <xs:element name="age" type="xs:short"/> + </xs:sequence> + <xs:attribute name="id" type="xs:unsignedInt" use="required"/> + </xs:complexType> + + <xs:complexType name="people_t"> + <xs:sequence> + <xs:element name="person" type="person_t" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="people" type="people_t"/> + +</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 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <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 compiler results + in three generated C++ classes: <code>gender_t</code>, + <code>person_t</code>, and <code>people_t</code>. + The <code>gender_t</code> class is modelled after the C++ + <code>enum</code> type. Its definition is presented below:</p> + + <pre class="c++"> +class gender_t: public xml_schema::string +{ +public: + enum value + { + male, + female + }; + + gender_t (value); + gender_t (const xml_schema::string&); + + gender_t& + operator= (value); + + operator value () const; +}; + </pre> + + <p>The following listing shows how we can use this type:</p> + + <pre class="c++"> +gender_t m (gender_t::male); +gender_t f ("female"); + +if (m == "female" || f == gender_t::male) +{ + ... +} + +switch (m) +{ +case gender_t::male: + { + ... + } +case gender_t::female: + { + ... + } +} + </pre> + + <p>The other two classes will be examined in detail in the subsequent + sections.</p> + + <h2><a name="4.1">4.1 Attribute and Element Cardinalities</a></h2> + + <p>As we have seen in the previous chapters, XSD generates a different + set of type definitions and member functions for elements with + different cardinalities. The C++/Tree 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 required attributes. In our + example, the <code>first-name</code>, <code>last-name</code>, + <code>gender</code>, and <code>age</code> elements as well as + the <code>id</code> attribute belong to this cardinality class. + The following code fragment shows type definitions as well as the + accessor and modifier functions that are generated for the + <code>gender</code> element in the <code>person_t</code> class:</p> + + <pre class="c++"> +class person_t +{ + // gender + // + typedef gender_t gender_type; + + const gender_type& + gender () const; + + gender_type& + gender (); + + void + gender (const gender_type&); +}; + </pre> + + <p>The <code>gender_type</code> type is an alias for the element's type. + 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.</p> + + <p>The <em>optional</em> cardinality class covers all elements that + can occur zero or one time as well as optional attributes. In our + example, the <code>middle-name</code> element belongs to this + cardinality class. The following code fragment shows the type + definitions as well as the accessor and modifier functions that + are generated for this element in the <code>person_t</code> class:</p> + + <pre class="c++"> +class person_t +{ + // middle-name + // + typedef xml_schema::string middle_name_type; + typedef xsd::optional<middle_name_type> middle_name_optional; + + const middle_name_optional& + middle_name () const; + + middle_name_optional& + middle_name (); + + void + middle_name (const middle_name_type&); + + void + middle_name (const middle_name_optional&); +}; + </pre> + + <p>As with the <code>gender</code> element, <code>middle_name_type</code> + is an alias for the element's type. The <code>middle_name_optional</code> + type is a container for the element's optional value. It can be queried + for the presence of the value using the <code>present()</code> function. + The value itself can be retrieved using the <code>get()</code> + accessor and set using the <code>set()</code> modifier. The container + can be reverted to the value not present state with the call to the + <code>reset()</code> function. The following example shows how we + can use this container:</p> + + <pre class="c++"> +person_t::middle_name_optional n ("John"); + +if (n.present ()) +{ + cout << n.get () << endl; +} + +n.set ("Jane"); +n.reset (); + </pre> + + + <p>Unlike the <em>one</em> cardinality class, the accessor functions + for the <em>optional</em> class return read-only (constant) and + read-write references to the container instead of the element's + value directly. The modifier functions set the new value for the + element.</p> + + <p>Finally, the <em>sequence</em> cardinality class covers all elements + that can occur more than once. In our example, the + <code>person</code> element in the <code>people_t</code> type + belongs to this cardinality class. The following code fragment shows + the type definitions as well as the accessor and modifier functions + that are generated for this element in the <code>people_t</code> + class:</p> + + <pre class="c++"> +class people_t +{ + // person + // + typedef person_t person_type; + typedef xsd::sequence<person_type> person_sequence; + typedef person_sequence::iterator person_iterator; + typedef person_sequence::const_iterator person_const_iterator; + + const person_sequence& + person () const; + + person_sequence& + person (); + + void + person (const person_sequence&); +}; + </pre> + + <p>Identical to the other cardinality classes, <code>person_type</code> + is an alias for the element's type. The <code>person_sequence</code> + type is a sequence container for the element's values. It is based + on and has the same interface as <code>std::vector</code> and + therefore can be used in similar ways. The <code>person_iterator</code> + and <code>person_const_iterator</code> types are read-only + (constant) and read-write iterators for the <code>person_sequence</code> + container.</p> + + <p>Similar to the <em>optional</em> cardinality class, the + accessor functions for the <em>sequence</em> class return + read-only (constant) and read-write references to the sequence + container. The modifier functions copies the entries from + the passed sequence.</p> + + <p>C++/Tree is a "flattening" mapping in a sense that many levels of + nested compositors (<code>choice</code> and <code>sequence</code>), + all potentially with their own cardinalities, are in the end mapped + to a flat set of elements with one of the three cardinality classes + discussed above. While this results in a simple and easy to use API + for most types, in certain cases, the order of elements in the actual + XML documents is not preserved once parsed into the object model. To + overcome this limitation we can mark certain schema types, for which + content order is not sufficiently preserved, as ordered. For more + information on this functionality refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.8.4">Section + 2.8.4, "Element Order"</a> in the C++/Tree Mapping User Manual.</p> + + <p>For complex schemas with many levels of nested compositors + (<code>choice</code> and <code>sequence</code>) it can also + be hard to deduce the cardinality class of a particular element. + The generated Doxygen documentation can greatly help with + this task. For each element and attribute the documentation + clearly identifies its cardinality class. Alternatively, you + can study the generated header files to find out the cardinality + class of a particular attribute or element.</p> + + <p>In the next sections we will examine how to access and modify + information stored in an object model using accessor and modifier + functions described in this section.</p> + + <h2><a name="4.2">4.2 Accessing the Object Model</a></h2> + + <p>In this section we will learn how to get to the information + stored in the object model for our person records vocabulary. + The following application accesses and prints the contents + of the <code>people.xml</code> file:</p> + + <pre class="c++"> +#include <iostream> +#include "people.hxx" + +using namespace std; + +int +main () +{ + unique_ptr<people_t> ppl (people ("people.xml")); + + // Iterate over individual person records. + // + people_t::person_sequence& ps (ppl->person ()); + + for (people_t::person_iterator i (ps.begin ()); i != ps.end (); ++i) + { + person_t& 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 ().get () << " "; + + cout << p.last_name () << endl; + + // Print gender, age, and id which are all required. + // + cout << "gender: " << p.gender () << 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 <code>people_t</code>) 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 element + <code>middle-name</code> we first check if the value is present + and only then call <code>get()</code> 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 potentially + expensive copy. This is generally a good rule to follow when + creating high-performance 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.3">4.3 Modifying the Object Model</a></h2> + + <p>In this section we will learn 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 <iostream> +#include "people.hxx" + +using namespace std; + +int +main () +{ + unique_ptr<people_t> ppl (people ("people.xml")); + + // Iterate over individual person records and increment + // the age. + // + people_t::person_sequence& ps (ppl->person ()); + + for (people_t::person_iterator i (ps.begin ()); i != ps.end (); ++i) + { + // Alternative way: i->age ()++; + // + i->age (i->age () + 1); + } + + // Add middle-name to the first record and remove it from + // the second. + // + person_t& john (ps[0]); + person_t& jane (ps[1]); + + john.middle_name ("Mary"); + jane.middle_name ().reset (); + + // Add another John record. + // + ps.push_back (john); + + // Serialize the modified object model to XML. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "people.xsd"; + + people (cout, *ppl, map); +} + </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 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <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.4">4.4 Creating the Object Model from Scratch</a></h2> + + <p>In this section we will learn 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" + +using namespace std; + +int +main () +{ + people_t ppl; + people_t::person_sequence& ps (ppl.person ()); + + // Add the John Doe record. + // + ps.push_back ( + person_t ("John", // first-name + "Doe", // last-name + gender_t::male, // gender + 32, // age + 1)); + + // Add the Jane Doe record. + // + ps.push_back ( + person_t ("Jane", // first-name + "Doe", // last-name + gender_t::female, // gender + 28, // age + 2)); // id + + // Add middle name to the Jane Doe record. + // + person_t& jane (ps.back ()); + jane.middle_name ("Mary"); + + // Serialize the object model to XML. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "people.xsd"; + + people (cout, ppl, map); +} + </pre> + + <p>The only new part in the above application is the calls + to the <code>people_t</code> and <code>person_t</code> + constructors. As a general rule, for each C++ class + XSD generates a constructor with initializers + for each element and attribute belonging to the <em>one</em> + cardinality class. For our vocabulary, the following + constructors are generated:</p> + + <pre class="c++"> +class person_t +{ + person_t (const first_name_type&, + const last_name_type&, + const gender_type&, + const age_type&, + const id_type&); +}; + +class people_t +{ + people_t (); +}; + </pre> + + <p>Note also that we set the <code>middle-name</code> element + on the Jane Doe record by obtaining a reference to that record + in the object model and setting the <code>middle-name</code> + value on it. This is a general rule that should be followed + in order to obtain the best performance: if possible, + direct modifications to the object model should be preferred + to modifications on temporaries with subsequent copying. The + following code fragment shows a semantically equivalent but + slightly slower version:</p> + + <pre class="c++"> +// Add the Jane Doe record. +// +person_t jane ("Jane", // first-name + "Doe", // last-name + gender_t::female, // gender + 28, // age + 2); // id + +jane.middle_name ("Mary"); + +ps.push_back (jane); + </pre> + + <p>We can also go one step further to reduce copying and improve + the performance of our application by using the non-copying + <code>push_back()</code> function which assumes ownership + of the passed objects:</p> + + <pre class="c++"> +// Add the Jane Doe record. C++11 version +// +unique_ptr<person_t> jane_p ( + new person_t ("Jane", // first-name + "Doe", // last-name + gender_t::female, // gender + 28, // age + 2)); // id +ps.push_back (std::move (jane_p)); // assumes ownership + +// Add the John Doe record. C++98 version. +// +auto_ptr<person_t> john_p ( + new person_t ("John", // first-name + "Doe", // last-name + gender_t::male, // gender + 32, // age + 1)); +ps.push_back (john_p); // assumes ownership + </pre> + + <p>For more information on the non-copying modifier functions refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.8">Section + 2.8, "Mapping for Local Elements and Attributes"</a> in the C++/Tree Mapping + User Manual. The above application produces the following output:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <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.5">4.5 Mapping for the Built-in XML Schema Types</a></h2> + + <p>Our person record vocabulary uses several built-in XML Schema + types: <code>string</code>, <code>short</code>, and + <code>unsignedInt</code>. Until now we haven't talked about + the mapping of built-in XML Schema types to C++ types and how + to work with them. This section provides an overview + of the built-in types. For more detailed information refer + to <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.5">Section + 2.5, "Mapping for Built-in Data Types"</a> in the C++/Tree Mapping + User Manual.</p> + + <p>In XML Schema, built-in types are defined in the XML Schema namespace. + By default, the C++/Tree mapping maps this namespace 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:</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 long</code></td> + </tr> + <tr> + <td><code>unsignedLong</code></td> + <td><code>unsigned_long</code></td> + <td><code>unsigned long long</code></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 long</code></td> + </tr> + <tr> + <td><code>nonPositiveInteger</code></td> + <td><code>non_positive_integer</code></td> + <td><code>long long</code></td> + </tr> + <tr> + <td><code>nonNegativeInteger</code></td> + <td><code>non_negative_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>positiveInteger</code></td> + <td><code>positive_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>negativeInteger</code></td> + <td><code>negative_integer</code></td> + <td><code>long 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>type derived from <code>std::basic_string</code></td> + </tr> + <tr> + <td><code>normalizedString</code></td> + <td><code>normalized_string</code></td> + <td>type derived from <code>string</code></td> + </tr> + <tr> + <td><code>token</code></td> + <td><code>token</code></td> + <td>type derived from <code>normalized_string</code></td> + </tr> + <tr> + <td><code>Name</code></td> + <td><code>name</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKEN</code></td> + <td><code>nmtoken</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKENS</code></td> + <td><code>nmtokens</code></td> + <td>type derived from <code>sequence<nmtoken></code></td> + </tr> + <tr> + <td><code>NCName</code></td> + <td><code>ncname</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>language</code></td> + <td><code>language</code></td> + <td>type derived from <code>token</code></td> + </tr> + + <tr> + <th colspan="3">qualified name</th> + </tr> + <tr> + <td><code>QName</code></td> + <td><code>qname</code></td> + <td><code>xml_schema::qname</code></td> + </tr> + + <tr> + <th colspan="3">ID/IDREF types</th> + </tr> + <tr> + <td><code>ID</code></td> + <td><code>id</code></td> + <td>type derived from <code>ncname</code></td> + </tr> + <tr> + <td><code>IDREF</code></td> + <td><code>idref</code></td> + <td>type derived from <code>ncname</code></td> + </tr> + <tr> + <td><code>IDREFS</code></td> + <td><code>idrefs</code></td> + <td>type derived from <code>sequence<idref></code></td> + </tr> + + <tr> + <th colspan="3">URI types</th> + </tr> + <tr> + <td><code>anyURI</code></td> + <td><code>uri</code></td> + <td>type derived from <code>std::basic_string</code></td> + </tr> + + <tr> + <th colspan="3">binary types</th> + </tr> + <tr> + <td><code>base64Binary</code></td> + <td><code>base64_binary</code></td> + <td><code>xml_schema::base64_binary</code></td> + </tr> + <tr> + <td><code>hexBinary</code></td> + <td><code>hex_binary</code></td> + <td><code>xml_schema::hex_binary</code></td> + </tr> + + <tr> + <th colspan="3">date/time types</th> + </tr> + <tr> + <td><code>date</code></td> + <td><code>date</code></td> + <td><code>xml_schema::date</code></td> + </tr> + <tr> + <td><code>dateTime</code></td> + <td><code>date_time</code></td> + <td><code>xml_schema::date_time</code></td> + </tr> + <tr> + <td><code>duration</code></td> + <td><code>duration</code></td> + <td><code>xml_schema::duration</code></td> + </tr> + <tr> + <td><code>gDay</code></td> + <td><code>gday</code></td> + <td><code>xml_schema::gday</code></td> + </tr> + <tr> + <td><code>gMonth</code></td> + <td><code>gmonth</code></td> + <td><code>xml_schema::gmonth</code></td> + </tr> + <tr> + <td><code>gMonthDay</code></td> + <td><code>gmonth_day</code></td> + <td><code>xml_schema::gmonth_day</code></td> + </tr> + <tr> + <td><code>gYear</code></td> + <td><code>gyear</code></td> + <td><code>xml_schema::gyear</code></td> + </tr> + <tr> + <td><code>gYearMonth</code></td> + <td><code>gyear_month</code></td> + <td><code>xml_schema::gyear_month</code></td> + </tr> + <tr> + <td><code>time</code></td> + <td><code>time</code></td> + <td><code>xml_schema::time</code></td> + </tr> + + <tr> + <th colspan="3">entity types</th> + </tr> + <tr> + <td><code>ENTITY</code></td> + <td><code>entity</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>ENTITIES</code></td> + <td><code>entities</code></td> + <td>type derived from <code>sequence<entity></code></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 C++ types that are derived + from either <code>std::string</code> or + <code>std::wstring</code>, depending on the character + type selected. For access and modification purposes these + types can be treated as <code>std::string</code>. 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. As a result, + these types are implemented from scratch in the XSD runtime. + For more information on their interfaces refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.5">Section + 2.5, "Mapping for Built-in Data Types"</a> in the C++/Tree Mapping + User Manual.</p> + + + <!-- Chapater 5 --> + + + <h1><a name="5">5 Parsing</a></h1> + + <p>We have already seen how to parse XML to an object model in this guide + before. In this chapter we will discuss the parsing topic in more + detail.</p> + + <p>By default, the C++/Tree mapping provides a total of 14 overloaded + parsing functions. They differ in the input methods used to + read XML as well as the error reporting mechanisms. It is also possible + to generate types for root elements instead of parsing and serialization + functions. This may be useful if your XML vocabulary has multiple + root elements. For more information on element types refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.9">Section + 2.9, "Mapping for Global Elements"</a> in the C++/Tree Mapping User + Manual.</p> + + + <p>In this section we will discuss the most commonly used versions of + the parsing functions. For a comprehensive description of parsing + refer to <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#3">Chapter + 3, "Parsing"</a> in the C++/Tree Mapping User Manual. For the <code>people</code> + global element from our person record vocabulary, we will concentrate + on the following three parsing functions:</p> + + <pre class="c++"> +std::[unique|auto]_ptr<people_t> +people (const std::string& uri, + xml_schema::flags f = 0, + const xml_schema::properties& p = xml_schema::properties ()); + +std::[unique|auto]_ptr<people_t> +people (std::istream& is, + xml_schema::flags f = 0, + const xml_schema::properties& p = xml_schema::properties ()); + +std::[unique|auto]_ptr<people_t> +people (std::istream& is, + const std::string& resource_id, + xml_schema::flags f = 0, + const xml_schema::properties& p = ::xml_schema::properties ()); + </pre> + + <p>The first function parses a local file or a URI. We have already + used this parsing function in the previous chapters. The second + and third functions read XML from a standard input stream. The + last function also requires a resource id. This id is used to + identify the XML document being parser in diagnostics messages + as well as to resolve relative paths to other documents (for example, + schemas) that might be referenced from the XML document.</p> + + <p>The last two arguments to all three parsing functions are parsing + flags and properties. The flags argument provides a number of ways + to fine-tune the parsing process. The properties argument allows + to pass additional information to the parsing functions. We will + use these two arguments in <a href="#5.1">Section 5.1, "XML Schema + Validation and Searching"</a> below. All three functions return + the object model as either <code>std::unique_ptr</code> (C++11) or + <code>std::auto_ptr</code> (C++98), depending on the C++ standard + selected (<code>--std</code> XSD compiler option). The following + example shows how we can use the above parsing functions:</p> + + <pre class="c++"> +using std::unique_ptr; + +// Parse a local file or URI. +// +unique_ptr<people_t> p1 (people ("people.xml")); +unique_ptr<people_t> p2 (people ("http://example.com/people.xml")); + +// Parse a local file via ifstream. +// +std::ifstream ifs ("people.xml"); +unique_ptr<people_t> p3 (people (ifs, "people.xml")); + +// Parse an XML string. +// +std::string str ("..."); // XML in a string. +std::istringstream iss (str); +unique_ptr<people_t> p4 (people (iss)); + </pre> + + + <h2><a name="5.1">5.1 XML Schema Validation and Searching</a></h2> + + <p>The C++/Tree mapping relies on the underlying Xerces-C++ XML + parser for full XML document validation. The XML Schema + validation is enabled by default and can be disabled by + passing the <code>xml_schema::flags::dont_validate</code> + flag to the parsing functions, for example:</p> + + <pre class="c++"> +unique_ptr<people_t> p ( + people ("people.xml", xml_schema::flags::dont_validate)); + </pre> + + <p>Even when XML Schema validation is disabled, the generated + code still performs a number of checks to prevent + construction of an inconsistent object model (for example, an + object model with missing required attributes or elements).</p> + + <p>When XML Schema validation is enabled, the XML parser needs + to locate a schema to validate against. There are several + methods to provide the schema location information to the + parser. The easiest and most commonly used method is to + specify schema locations in the XML document itself + with the <code>schemaLocation</code> or + <code>noNamespaceSchemaLocation</code> attributes, for example:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd" + xsi:schemaLocation="http://www.w3.org/XML/1998/namespace xml.xsd"> + </pre> + + <p>As you might have noticed, we used this method in all the sample XML + documents presented in this guide up until now. Note that the + schema locations specified with these two attributes are relative + to the document's path unless they are absolute URIs (that is + start with <code>http://</code>, <code>file://</code>, etc.). + In particular, if you specify just file names as your schema + locations, as we did above, then the schemas should reside in + the same directory as the XML document itself.</p> + + <p>Another method of providing the schema location information + is via the <code>xml_schema::properties</code> argument, as + shown in the following example:</p> + + <pre class="c++"> +xml_schema::properties props; +props.no_namespace_schema_location ("people.xsd"); +props.schema_location ("http://www.w3.org/XML/1998/namespace", "xml.xsd"); + +unique_ptr<people_t> p (people ("people.xml", 0, props)); + </pre> + + <p>The schema locations provided with this method overrides + those specified in the XML document. As with the previous + method, the schema locations specified this way are + relative to the document's path unless they are absolute URIs. + In particular, if you want to use local schemas that are + not related to the document being parsed, then you will + need to use the <code>file://</code> URI. The following + example shows how to use schemas that reside in the current + working directory:</p> + + <pre class="c++"> +#include <unistd.h> // getcwd +#include <limits.h> // PATH_MAX + +char cwd[PATH_MAX]; +if (getcwd (cwd, PATH_MAX) == 0) +{ + // Buffer too small? +} + +xml_schema::properties props; + +props.no_namespace_schema_location ( + "file:///" + std::string (cwd) + "/people.xsd"); + +props.schema_location ( + "http://www.w3.org/XML/1998/namespace", + "file:///" + std::string (cwd) + "/xml.xsd"); + +unique_ptr<people_t> p (people ("people.xml", 0, props)); + </pre> + + <p>A third method is the most useful if you are planning to parse + several XML documents of the same vocabulary. In that case + it may be beneficial to pre-parse and cache the schemas in + the XML parser which can then be used to parse all documents + without re-parsing the schemas. For more information on + this method refer to the <code>caching</code> example in the + <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package. + It is also possible to convert the schemas into a pre-compiled + binary representation and embed this representation directly into + the application executable. With this approach your application can + perform XML Schema validation without depending on any external + schema files. For more information on how to achieve this refer to + the <code>embedded</code> example in the <code>cxx/tree/</code> + directory in the <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <p>When the XML parser cannot locate a schema for the + XML document, the validation fails and XML document + elements and attributes for which schema definitions could + not be located are reported in the diagnostics. For + example, if we remove the <code>noNamespaceSchemaLocation</code> + attribute in <code>people.xml</code> from the previous chapter, + then we will get the following diagnostics if we try to parse + this file with validation enabled:</p> + + <pre class="terminal"> +people.xml:2:63 error: no declaration found for element 'people' +people.xml:4:18 error: no declaration found for element 'person' +people.xml:4:18 error: attribute 'id' is not declared for element 'person' +people.xml:5:17 error: no declaration found for element 'first-name' +people.xml:6:18 error: no declaration found for element 'middle-name' +people.xml:7:16 error: no declaration found for element 'last-name' +people.xml:8:13 error: no declaration found for element 'gender' +people.xml:9:10 error: no declaration found for element 'age' + </pre> + + <h2><a name="5.2">5.2 Error Handling</a></h2> + + <p>The parsing functions offer a number of ways to handle error conditions + with the C++ exceptions being the most commonly used mechanism. All + C++/Tree exceptions derive from common base <code>xml_schema::exception</code> + which in turn derives from <code>std::exception</code>. The easiest + way to uniformly handle all possible C++/Tree exceptions and print + detailed information about the error is to catch and print + <code>xml_schema::exception</code>, as shown in the following + example:</p> + + <pre class="c++"> +try +{ + unique_ptr<people_t> p (people ("people.xml")); +} +catch (const xml_schema::exception& e) +{ + cerr << e << endl; +} + </pre> + + <p>Each individual C++/Tree exception also allows you to obtain + error details programmatically. For example, the + <code>xml_schema::parsing</code> exception is thrown when + the XML parsing and validation in the underlying XML parser + fails. It encapsulates various diagnostics information + such as the file name, line and column numbers, as well as the + error or warning message for each entry. For more information + about this and other exceptions that can be thrown during + parsing, refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#3.3">Section + 3.3, "Error Handling"</a> in the C++/Tree Mapping + User Manual.</p> + + <p>Note that if you are parsing <code>std::istream</code> on which + exceptions are not enabled, then you will need to check the + stream state after the call to the parsing function in order + to detect any possible stream failures, for example:</p> + + <pre class="c++"> +std::ifstream ifs ("people.xml"); + +if (ifs.fail ()) +{ + cerr << "people.xml: unable to open" << endl; + return 1; +} + +unique_ptr<people_t> p (people (ifs, "people.xml")); + +if (ifs.fail ()) +{ + cerr << "people.xml: read error" << endl; + return 1; +} + </pre> + + <p>The above example can be rewritten to use exceptions as + shown below:</p> + + <pre class="c++"> +try +{ + std::ifstream ifs; + ifs.exceptions (std::ifstream::badbit | std::ifstream::failbit); + ifs.open ("people.xml"); + + unique_ptr<people_t> p (people (ifs, "people.xml")); +} +catch (const std::ifstream::failure&) +{ + cerr << "people.xml: unable to open or read error" << endl; + return 1; +} + </pre> + + + <!-- Chapater 6 --> + + + <h1><a name="6">6 Serialization</a></h1> + + <p>We have already seen how to serialize an object model back to XML + in this guide before. In this chapter we will discuss the + serialization topic in more detail.</p> + + <p>By default, the C++/Tree mapping provides a total of 8 overloaded + serialization functions. They differ in the output methods used to write + XML as well as the error reporting mechanisms. It is also possible to + generate types for root elements instead of parsing and serialization + functions. This may be useful if your XML vocabulary has multiple + root elements. For more information on element types refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.9">Section + 2.9, "Mapping for Global Elements"</a> in the C++/Tree Mapping User + Manual.</p> + + + <p>In this section we will discuss the most commonly + used version of serialization functions. For a comprehensive description + of serialization refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#4">Chapter + 4, "Serialization"</a> in the C++/Tree Mapping User Manual. For the + <code>people</code> global element from our person record vocabulary, + we will concentrate on the following serialization function:</p> + + <pre class="c++"> +void +people (std::ostream& os, + const people_t& x, + const xml_schema::namespace_infomap& map = + xml_schema::namespace_infomap (), + const std::string& encoding = "UTF-8", + xml_schema::flags f = 0); + </pre> + + <p>This function serializes the object model passed as the second + argument to the standard output stream passed as the first + argument. The third argument is a namespace information map + which we will discuss in more detail in the next section. + The fourth argument is a character encoding that the resulting + XML document should be in. Possible valid values for this + argument are "US-ASCII", "ISO8859-1", "UTF-8", "UTF-16BE", + "UTF-16LE", "UCS-4BE", and "UCS-4LE". Finally, the flags + argument allows fine-tuning of the serialization process. + The following example shows how we can use the above serialization + function:</p> + + <pre class="c++"> +people_t& p = ... + +xml_schema::namespace_infomap map; +map[""].schema = "people.xsd"; + +// Serialize to stdout. +// +people (std::cout, p, map); + +// Serialize to a file. +// +std::ofstream ofs ("people.xml"); +people (ofs, p, map); + +// Serialize to a string. +// +std::ostringstream oss; +people (oss, p, map); +std::string xml (oss.str ()); + </pre> + + + <h2><a name="6.1">6.1 Namespace and Schema Information</a></h2> + + <p>While XML serialization can be done just from the object + model alone, it is often desirable to assign meaningful + prefixes to XML namespaces used in the vocabulary as + well as to provide the schema location information. + This is accomplished by passing the namespace information + map to the serialization function. The key in this map is + a namespace prefix that should be assigned to an XML namespace + specified in the <code>name</code> variable of the + map value. You can also assign an optional schema location for + this namespace in the <code>schema</code> variable. Based + on each key-value entry in this map, the serialization + function adds two attributes to the resulting XML document: + the namespace-prefix mapping attribute and schema location + attribute. The empty prefix indicates that the namespace + should be mapped without a prefix. For example, the following + map:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].name = "http://www.example.com/example"; +map[""].schema = "example.xsd"; + +map["x"].name = "http://www.w3.org/XML/1998/namespace"; +map["x"].schema = "xml.xsd"; + </pre> + + <p>Results in the following XML document:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<example + xmlns="http://www.example.com/example" + xmlns:x="http://www.w3.org/XML/1998/namespace" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.example.com/example example.xsd + http://www.w3.org/XML/1998/namespace xml.xsd"> + </pre> + + <p>The empty namespace indicates that the vocabulary has no target + namespace. For example, the following map results in only the + <code>noNamespaceSchemaLocation</code> attribute being added:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].name = ""; +map[""].schema = "example.xsd"; + </pre> + + <h2><a name="6.2">6.2 Error Handling</a></h2> + + <p>Similar to the parsing functions, the serialization functions offer a + number of ways to handle error conditions with the C++ exceptions being + the most commonly used mechanisms. As with parsing, the easiest way to + uniformly handle all possible serialization exceptions and print + detailed information about the error is to catch and print + <code>xml_schema::exception</code>:</p> + + <pre class="c++"> +try +{ + people_t& p = ... + + xml_schema::namespace_infomap map; + map[""].schema = "people.xsd"; + + people (std::cout, p, map)); +} +catch (const xml_schema::exception& e) +{ + cerr << e << endl; +} + </pre> + + <p>The most commonly encountered serialization exception is + <code>xml_schema::serialization</code>. It is thrown + when the XML serialization in the underlying XML writer + fails. It encapsulates various diagnostics information + such as the file name, line and column numbers, as well as the + error or warning message for each entry. For more information + about this and other exceptions that can be thrown during + serialization, refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#4.4">Section + 4.4, "Error Handling"</a> in the C++/Tree Mapping + User Manual.</p> + + <p>Note that if you are serializing to <code>std::ostream</code> on + which exceptions are not enabled, then you will need to check the + stream state after the call to the serialization function in order + to detect any possible stream failures, for example:</p> + + <pre class="c++"> +std::ofstream ofs ("people.xml"); + +if (ofs.fail ()) +{ + cerr << "people.xml: unable to open" << endl; + return 1; +} + +people (ofs, p, map)); + +if (ofs.fail ()) +{ + cerr << "people.xml: write error" << endl; + return 1; +} + </pre> + + <p>The above example can be rewritten to use exceptions as + shown below:</p> + + <pre class="c++"> +try +{ + std::ofstream ofs; + ofs.exceptions (std::ofstream::badbit | std::ofstream::failbit); + ofs.open ("people.xml"); + + people (ofs, p, map)); +} +catch (const std::ofstream::failure&) +{ + cerr << "people.xml: unable to open or write error" << endl; + return 1; +} + </pre> + + </div> +</div> + +</body> +</html> diff --git a/doc/cxx/tree/guide/index.xhtml.in b/doc/cxx/tree/guide/index.xhtml.in new file mode 100644 index 0000000..2f7f1e2 --- /dev/null +++ b/doc/cxx/tree/guide/index.xhtml.in @@ -0,0 +1,2736 @@ +<?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>C++/Tree Mapping Getting Started Guide</title> + + <meta name="copyright" content="© @copyright@"/> + <meta name="keywords" content="xsd,xml,schema,c++,mapping,data,binding,parsing,serialization,validation"/> + <meta name="description" content="C++/Tree 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 { + 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; + } + + /* 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; + } + + /* 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; + } +</style> + + +</head> + +<body> +<div id="container"> + <div id="content"> + + <div class="noprint"> + + <div id="titlepage"> + <div class="title" id="first-title">C++/Tree Mapping</div> + <div class="title" id="second-title">Getting Started Guide</div> + + <p>Copyright © @copyright@.</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href="https://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="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/index.xhtml">XHTML</a>, + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/cxx-tree-guide.pdf">PDF</a>, and + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/cxx-tree-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">Selecting Naming Convention</a></td></tr> + <tr><th>2.7</th><td><a href="#2.7">Generating Documentation</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">Overall Mapping Configuration</a> + <table class="toc"> + <tr><th>3.1</th><td><a href="#3.1">C++ Standard</a></td></tr> + <tr><th>3.2</th><td><a href="#3.2">Character Type and Encoding</a></td></tr> + <tr><th>3.3</th><td><a href="#3.3">Support for Polymorphism </a></td></tr> + <tr><th>3.4</th><td><a href="#3.4">Namespace Mapping</a></td></tr> + <tr><th>3.5</th><td><a href="#3.5">Thread Safety</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">Attribute and Element Cardinalities</a></td></tr> + <tr><th>4.2</th><td><a href="#4.2">Accessing the Object Model</a></td></tr> + <tr><th>4.3</th><td><a href="#4.3">Modifying the Object Model</a></td></tr> + <tr><th>4.4</th><td><a href="#4.4">Creating the Object Model from Scratch</a></td></tr> + <tr><th>4.5</th><td><a href="#4.5">Mapping for the Built-in XML Schema Types</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>5</th><td><a href="#5">Parsing</a> + <table class="toc"> + <tr><th>5.1</th><td><a href="#5.1">XML Schema Validation and Searching</a></td></tr> + <tr><th>5.2</th><td><a href="#5.2">Error Handling</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>6</th><td><a href="#6">Serialization</a> + <table class="toc"> + <tr><th>6.1</th><td><a href="#6.1">Namespace and Schema Information</a></td></tr> + <tr><th>6.2</th><td><a href="#6.2">Error Handling</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++/Tree programming model and allow you to efficiently evaluate + XSD against your project's technical requirements. As such, this + document is intended for C++ developers and software architects + who are looking for an XML processing solution. For a more in-depth + description of the C++/Tree mapping refer to the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/">C++/Tree + Mapping User Manual</a>.</p> + + <p>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="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/">C++/Tree + Mapping User Manual</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/Customization_guide">C++/Tree + Mapping Customization Guide</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree + Mapping Frequently Asked Questions (FAQ)</a></li> + + <li><a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a></li> + + <li>The <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + contains a collection of examples and a README file with an overview + of each example.</li> + + <li>The <code>README</code> file in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + explains how to build the examples.</li> + + <li>The <a href="https://www.codesynthesis.com/mailman/listinfo/xsd-users">xsd-users</a> + mailing list is the place to ask technical questions about XSD and the C++/Parser mapping. + Furthermore, the <a href="https://www.codesynthesis.com/pipermail/xsd-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 and the C++/Tree mapping. XSD is a + cross-platform W3C XML Schema to C++ data binding compiler. C++/Tree + is a W3C XML Schema to C++ mapping that represents the data stored + in XML as a statically-typed, vocabulary-specific 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++/Tree 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 as well as XML parsing and + serialization code.</p> + + <p>Besides the core features, C++/Tree provide a number of additional + mapping elements that can be useful in some applications. These + include serialization and extraction to/from formats others than + XML, such as unstructured text (useful for debugging) and binary + representations such as XDR and CDR for high-speed data processing + as well as automatic documentation generation. The C++/Tree mapping + also provides a wide range of mechanisms for controlling and + customizing the generated code.</p> + + <p>A typical application that uses C++/Tree for XML processing usually + 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.</p> + + <p>The next chapter presents a simple application that performs these + three steps. The following chapters show how to use the C++/Tree + 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) have a number of drawbacks that + make them less suitable for creating robust and maintainable + 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 because the data is represented as text.</li> + + <li>Resulting applications are hard to debug, change, and + maintain.</li> + </ul> + + <p>In contrast, statically-typed, vocabulary-specific object model + produced by the C++/Tree mapping allows you to operate in your + domain terms instead of the generic elements, attributes, and + text. 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++/Tree 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>Compatibility.</b> Sequences of elements are represented in + the object model as containers conforming to the standard C++ + sequence requirements. This makes it possible to use standard + C++ algorithms on the object representation and frees you from + learning yet another container interface, as is the case with + DOM.</li> + + <li><b>Efficiency.</b> If the application makes repetitive use + of the data extracted from XML, then the C++/Tree 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. Furthermore, the runtime memory + usage is 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.</li> + </ul> + + + <!-- Hello World Parser --> + + + <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 XSD-generated + C++/Tree object model. The code presented in this chapter is + based on the <code>hello</code> example which can be found in + the <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package.</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_t"> + <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_t"/> + +</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_t</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. We can also update our <code>hello.xml</code> to include the + information about the schema so that XML parsers can validate + our document:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="hello.xsd"> + + <greeting>Hello</greeting> + + <name>sun</name> + <name>moon</name> + <name>world</name> + +</hello> + </pre> + + + <p>The next step is to compile the schema to generate the object + model and parsing functions.</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 compiler from a terminal (UNIX) or + a command prompt (Windows): + </p> + + <pre class="terminal"> +$ xsd cxx-tree hello.xsd + </pre> + + <p>The XSD compiler produces two C++ files: <code>hello.hxx</code> and + <code>hello.cxx</code>. The following code fragment is taken from + <code>hello.hxx</code>; it should give you an idea about what gets + generated: + </p> + + <pre class="c++"> +class hello_t +{ +public: + // greeting + // + typedef xml_schema::string greeting_type; + + const greeting_type& + greeting () const; + + greeting_type& + greeting (); + + void + greeting (const greeting_type& x); + + // name + // + typedef xml_schema::string name_type; + typedef xsd::sequence<name_type> name_sequence; + typedef name_sequence::iterator name_iterator; + typedef name_sequence::const_iterator name_const_iterator; + + const name_sequence& + name () const; + + name_sequence& + name (); + + void + name (const name_sequence& s); + + // Constructor. + // + hello_t (const greeting_type&); + + ... + +}; + +std::unique_ptr<hello_t> +hello (const std::string& uri); + +std::unique_ptr<hello_t> +hello (std::istream&); + </pre> + + <p>The <code>hello_t</code> C++ class corresponds to the + <code>hello_t</code> XML Schema type. For each element + in this type a set of C++ type definitions as well as + accessor and modifier functions are generated inside the + <code>hello_t</code> class. Note that the type definitions + and member functions for the <code>greeting</code> and + <code>name</code> elements are different because of the + cardinality differences between these two elements + (<code>greeting</code> is a required single element and + <code>name</code> is a sequence of elements).</p> + + <p>The <code>xml_schema::string</code> type used in the type + definitions is a C++ class provided by the XSD runtime + that corresponds to built-in XML Schema type + <code>string</code>. The <code>xml_schema::string</code> + is based on <code>std::string</code> and can be used as + such. Similarly, the <code>sequence</code> class template + that is used in the <code>name_sequence</code> type + definition is based on and has the same interface as + <code>std::vector</code>. The mapping between the built-in + XML Schema types and C++ types is described in more detail in + <a href="#4.5">Section 4.5, "Mapping for the Built-in XML Schema + Types"</a>. The <code>hello_t</code> class also includes a + constructor with an initializer for the required + <code>greeting</code> element as its argument.</p> + + <p>The <code>hello</code> overloaded global functions correspond + to the <code>hello</code> global element in XML Schema. A + global element in XML Schema is a valid document root. + By default XSD generated a set of parsing functions for each + global element defined in XML Schema (this can be overridden + with the <code>--root-element-*</code> options). Parsing + functions return a dynamically allocated object model as an + automatic pointer. The actual pointer used depends on the + C++ standard selected. For C++11 it is <code>std::unique_ptr</code> + as shown above. For C++98 it is <code>std::auto_ptr</code>. + For example, if we modify our XSD compiler invocation to + select C++98:</p> + + <pre class="terminal"> +$ xsd cxx-tree --std c++98 hello.xsd + </pre> + + <p>Then the parsing function signatures will become:</p> + + <pre class="c++"> +std::auto_ptr<hello_t> +hello (const std::string& uri); + +std::auto_ptr<hello_t> +hello (std::istream&); + </pre> + + <p>For more information on parsing functions see <a href="#5">Chapter 5, + "Parsing"</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" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + unique_ptr<hello_t> h (hello (argv[1])); + + for (hello_t::name_const_iterator i (h->name ().begin ()); + i != h->name ().end (); + ++i) + { + cerr << h->greeting () << ", " << *i << "!" << endl; + } + } + catch (const xml_schema::exception& e) + { + cerr << e << endl; + return 1; + } +} + </pre> + + <p>The first part of our application calls one of the parsing + functions to parser an XML file specified in the command line. + We then use the returned object model to iterate over names + and print a greeting line for each of them. Finally, we + catch and print the <code>xml_schema::exception</code> + exception in case something goes wrong. This exception + is the root of the exception hierarchy used by the + XSD-generated code. + </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 a UNIX + system this can be done with the following commands: + </p> + + <pre class="terminal"> +$ c++ -std=c++11 -I.../libxsd -c driver.cxx hello.cxx +$ c++ -std=c++11 -o driver driver.o hello.o -lxerces-c +$ ./driver hello.xml +Hello, sun! +Hello, moon! +Hello, world! + </pre> + + <p>Here <code>.../libxsd</code> represents the path to the + <a href="https://cppget.org/libxsd">libxsd</a> package root + directory. Note also that we are required to link our + application with the Xerces-C++ library because the generated + code uses it as the underlying XML parser.</p> + + <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. By default XSD does + not produce serialization code. We will need to request + it with the <code>--generate-serialization</code> options:</p> + + <pre class="terminal"> +$ xsd cxx-tree --generate-serialization hello.xsd + </pre> + + <p>If we now examine the generated <code>hello.hxx</code> file, + we will find a set of overloaded serialization functions, + including the following version:</p> + + <pre class="c++"> +void +hello (std::ostream&, + const hello_t&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap ()); + + </pre> + + <p>Just like with parsing functions, XSD generates serialization + functions for each global element unless instructed otherwise + with one of the <code>--root-element-*</code> options. For more + information on serialization functions see <a href="#6">Chapter 6, + "Serialization"</a>.</p> + + <p>We 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" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + unique_ptr<hello_t> h (hello (argv[1])); + + // 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. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "hello.xsd"; + + hello (cout, *h, map); + } + catch (const xml_schema::exception& e) + { + cerr << e << 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 serializes the object model back to XML by calling + the serialization function.</p> + + <p>The first argument we pass to the serialization function is + <code>cout</code> which results in the XML being written to + the standard output 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 instead of <code>cout</code>. The second argument is the + object model we want to serialize. The final argument is an optional + namespace information map for our vocabulary. It captures information + such as namespaces, namespace prefixes to which they should be mapped, + and schemas associated with these namespaces. If we don't provide + this argument then generic namespace prefixes (<code>p1</code>, + <code>p2</code>, etc.) will be automatically assigned to XML namespaces + and no schema information will be added to the resulting document + (see <a href="#6">Chapter 6, "Serialization"</a> for details). + In our case, the prefix (map key) and namespace name are empty + because our vocabulary does not use XML namespaces.</p> + + <p>If we now compile and run this application we will see the + output as shown in the following listing:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="hello.xsd"> + + <greeting>Hi</greeting> + + <name>sun</name> + <name>moon</name> + <name>world</name> + <name>mars</name> + +</hello> + </pre> + + <p>We can also create and serialize an object model from scratch + as shown in the following example:</p> + + <pre class="c++"> +#include <iostream> +#include <fstream> +#include "hello.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + hello_t h ("Hi"); + + hello_t::name_sequence& ns (h.name ()); + + ns.push_back ("Jane"); + ns.push_back ("John"); + + // Serialize the object model to XML. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "hello.xsd"; + + std::ofstream ofs (argv[1]); + hello (ofs, h, map); + } + catch (const xml_schema::exception& e) + { + cerr << e << endl; + return 1; + } +} + </pre> + + <p>In this example we used the generated constructor to create + an instance of type <code>hello_t</code>. To reduce typing, + we obtained a reference to the name sequence which we then + used to add a few names. The serialization part is identical + to the previous example except this time we are writing to + a file. If we compile and run this program, it produces the + following XML file:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="hello.xsd"> + + <greeting>Hi</greeting> + + <name>Jane</name> + <name>John</name> + +</hello> + </pre> + + <h2><a name="2.6">2.6 Selecting Naming Convention</a></h2> + + <p>By default XSD uses the so-called K&R (Kernighan and Ritchie) + identifier naming convention in the generated code. In this + convention both type and function names are in lower case and + words are separated by underscores. If your application code or + schemas use a different notation, you may want to change the + naming convention used in the generated code for consistency. + XSD supports a set of widely-used naming conventions + that you can select with the <code>--type-naming</code> and + <code>--function-naming</code> options. You can also further + refine one of the predefined conventions or create a completely + custom naming scheme by using the <code>--*-regex</code> options.</p> + + <p>As an example, let's assume that our "Hello World" application + uses the so-called upper-camel-case naming convention for types + (that is, each word in a type name is capitalized) and the K&R + convention for function names. Since K&R is the default + convention for both type and function names, we only need to + change the type naming scheme:</p> + + <pre class="terminal"> +$ xsd cxx-tree --type-naming ucc hello.xsd + </pre> + + <p>The <code>ucc</code> argument to the <code>--type-naming</code> + options stands for upper-camel-case. If we now examine the + generated <code>hello.hxx</code>, we will see the following + changes compared to the declarations shown in the previous + sections:</p> + + <pre class="c++"> +class Hello_t +{ +public: + // greeting + // + typedef xml_schema::String GreetingType; + + const GreetingType& + greeting () const; + + GreetingType& + greeting (); + + void + greeting (const GreetingType& x); + + // name + // + typedef xml_schema::String NameType; + typedef xsd::sequence<NameType> NameSequence; + typedef NameSequence::iterator NameIterator; + typedef NameSequence::const_iterator NameConstIterator; + + const NameSequence& + name () const; + + NameSequence& + name (); + + void + name (const NameSequence& s); + + // Constructor. + // + Hello_t (const GreetingType&); + + ... + +}; + +std::unique_ptr<Hello_t> +hello (const std::string& uri); + +std::unique_ptr<Hello_t> +hello (std::istream&); + </pre> + + <p>Notice that the type names in the <code>xml_schema</code> namespace, + for example <code>xml_schema::String</code>, now also use the + upper-camel-case naming convention. The only thing that we may + be unhappy about in the above code is the <code>_t</code> + suffix in <code>Hello_t</code>. If we are not in a position + to change the schema, we can <em>touch-up</em> the <code>ucc</code> + convention with a custom translation rule using the + <code>--type-regex</code> option:</p> + + <pre class="terminal"> +$ xsd cxx-tree --type-naming ucc --type-regex '/ (.+)_t/\u$1/' hello.xsd + </pre> + + <p>This results in the following changes to the generated code:</p> + + <pre class="c++"> +class Hello +{ +public: + // greeting + // + typedef xml_schema::String GreetingType; + + const GreetingType& + greeting () const; + + GreetingType& + greeting (); + + void + greeting (const GreetingType& x); + + // name + // + typedef xml_schema::String NameType; + typedef xsd::sequence<NameType> NameSequence; + typedef NameSequence::iterator NameIterator; + typedef NameSequence::const_iterator NameConstIterator; + + const NameSequence& + name () const; + + NameSequence& + name (); + + void + name (const NameSequence& s); + + // Constructor. + // + Hello (const GreetingType&); + + ... + +}; + +std::unique_ptr<Hello> +hello (const std::string& uri); + +std::unique_ptr<Hello> +hello (std::istream&); + </pre> + + <p>For more detailed information on the <code>--type-naming</code>, + <code>--function-naming</code>, <code>--type-regex</code>, and + other <code>--*-regex</code> options refer to the NAMING + CONVENTION section in the <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>.</p> + + <h2><a name="2.7">2.7 Generating Documentation</a></h2> + + <p>While our object model is quite simple, real-world vocabularies + can be quite complex with hundreds of types, elements, and + attributes. For such vocabularies figuring out which types + provide which member functions by studying the generated + source code or schemas can be a daunting task. To provide + application developers with a more accessible way of + understanding the generated object models, the XSD compiler + can be instructed to produce source code with documentation + comments in the Doxygen format. Then the source code can be + processed with the <a href="http://www.doxygen.org">Doxygen</a> + documentation system to extract this information and produce + documentation in various formats. + </p> + + <p>In this section we will see how to generate documentation + for our "Hello World" vocabulary. To showcase the full power + of the XSD documentation facilities, we will first document + our schema. The XSD compiler will then transfer + this information from the schema to the generated code and + then to the object model documentation. Note that the + documentation in the schema is not required for XSD to + generate useful documentation. Below you will find + our <code>hello.xsd</code> with added documentation:</p> + + <pre class="xml"> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:complexType name="hello_t"> + + <xs:annotation> + <xs:documentation> + The hello_t type consists of a greeting phrase and a + collection of names to which this greeting applies. + </xs:documentation> + </xs:annotation> + + <xs:sequence> + + <xs:element name="greeting" type="xs:string"> + <xs:annotation> + <xs:documentation> + The greeting element contains the greeting phrase + for this hello object. + </xs:documentation> + </xs:annotation> + </xs:element> + + <xs:element name="name" type="xs:string" maxOccurs="unbounded"> + <xs:annotation> + <xs:documentation> + The name elements contains names to be greeted. + </xs:documentation> + </xs:annotation> + </xs:element> + + </xs:sequence> + </xs:complexType> + + <xs:element name="hello" type="hello_t"> + <xs:annotation> + <xs:documentation> + The hello element is a root of the Hello XML vocabulary. + Every conforming document should start with this element. + </xs:documentation> + </xs:annotation> + </xs:element> + +</xs:schema> + </pre> + + <p>The first step in obtaining the documentation is to recompile + our schema with the <code>--generate-doxygen</code> option:</p> + + <pre class="terminal"> +$ xsd cxx-tree --generate-serialization --generate-doxygen hello.xsd + </pre> + + <p>Now the generated <code>hello.hxx</code> file contains comments + in the Doxygen format. The next step is to process this file + with the Doxygen documentation system. If your project does + not use Doxygen then you first need to create a configuration + file for your project:</p> + + <pre class="terminal"> +$ doxygen -g hello.doxygen + </pre> + + <p>You only need to perform this step once. Now we can generate + the documentation by executing the following command in the + directory with the generated source code:</p> + + <pre class="terminal"> +$ doxygen hello.doxygen + </pre> + + <p>While the generated documentation can be useful as is, we can + go one step further and link (using the Doxygen tags mechanism) + the documentation for our object model with the documentation + for the XSD runtime library which defines C++ classes for the + built-in XML Schema types. This way we can seamlessly browse + between documentation for the <code>hello_t</code> class which + is generated by the XSD compiler and the <code>xml_schema::string</code> + class which is defined in the XSD runtime library. The Doxygen + configuration file for the XSD runtime is provided with the XSD + distribution.</p> + + <p>You can view the result of the steps described in this section + on the <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/hello/html/annotated.html">Hello + Example Documentation</a> page.</p> + + <!-- Chapater 3 --> + + + <h1><a name="3">3 Overall Mapping Configuration</a></h1> + + <p>The C++/Tree mapping has a number of configuration parameters that + determine the overall properties and behavior of the generated code. + Configuration parameters are specified with the XSD command line + options. This chapter describes configuration aspects that are most + commonly encountered by application developers. These include: the + C++ standard, the character type that is used by the generated code, + handling of vocabularies that use XML Schema polymorphism, XML Schema + to C++ namespace mapping, and thread safety. For more ways to configure + the generated code refer to the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>. + </p> + + <h2><a name="3.1">3.1 C++ Standard</a></h2> + + <p>The C++/Tree mapping provides support for ISO/IEC C++ 2011 (C++11) + and ISO/IEC C++ 1998/2003 (C++98). To select the C++ standard for the + generated code we use the <code>--std</code> XSD compiler command + line option. While the majority of the examples in this guide use + C++11, the document explains the C++11/98 usage difference and so + they can easily be converted to C++98.</p> + + <h2><a name="3.2">3.2 Character Type and Encoding</a></h2> + + <p>The C++/Tree mapping has built-in support for two character types: + <code>char</code> and <code>wchar_t</code>. You can select the + character type with the <code>--char-type</code> command line + option. The default character type is <code>char</code>. The + character type affects all string and string-based types that + are used in the mapping. These include the string-based built-in + XML Schema types, exception types, stream types, etc.</p> + + <p>Another aspect of the mapping that depends on the character type + is character encoding. For the <code>char</code> character type + the default encoding is UTF-8. Other supported encodings are + ISO-8859-1, Xerces-C++ Local Code Page (LPC), as well as + custom encodings. You can select which encoding should be used + in the object model with the <code>--char-encoding</code> command + line option.</p> + + <p>For the <code>wchar_t</code> character type the encoding is + automatically selected between UTF-16 and UTF-32/UCS-4 depending + on the size of the <code>wchar_t</code> type. On some platforms + (for example, Windows with Visual C++ and AIX with IBM XL C++) + <code>wchar_t</code> is 2 bytes long. For these platforms the + encoding is UTF-16. On other platforms <code>wchar_t</code> is 4 bytes + long and UTF-32/UCS-4 is used.</p> + + <p>Note also that the character encoding that is used in the object model + is independent of the encodings used in input and output XML. In fact, + all three (object mode, input XML, and output XML) can have different + encodings.</p> + + <h2><a name="3.3">3.3 Support for Polymorphism</a></h2> + + <p>By default XSD 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 compile + your schemas with the <code>--generate-polymorphic</code> option + to produce polymorphism-aware code. For more information on + working with polymorphic object models, refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.11">Section 2.11, + "Mapping for <code>xsi:type</code> and Substitution Groups"</a> in + the C++/Tree Mapping User Manual.</p> + + <h2><a name="3.4">3.4 Namespace Mapping</a></h2> + + <p>XSD 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.</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 namespace URI <code>https://www.codesynthesis.com/my</code> to + C++ namespace <code>cs::my</code>, we can use the following option:</p> + + <pre class="terminal"> +--namespace-map https://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:</p> + + <pre class="terminal"> +--namespace-map =cs + </pre> + + <h2><a name="3.5">3.5 Thread Safety</a></h2> + + <p>XSD-generated code is thread-safe in the sense that you can + use different instantiations of the object model in several + threads concurrently. This is possible due to the generated + code not relying on any writable global variables. If you need + to share the same object between several threads then you will + need to provide some form of synchronization. One approach would + be to use the generated code customization mechanisms to embed + synchronization primitives into the generated C++ classes. For more + information on generated code customization refer to the + <a href="http://wiki.codesynthesis.com/Tree/Customization_guide">C++/Tree + Mapping Customization Guide</a>.</p> + + <p>If you also would like to call parsing and/or serialization + functions from several threads potentially concurrently, then + you will need to make sure the Xerces-C++ runtime is initialized + and terminated only once. The easiest way to do this is to + initialize/terminate Xerces-C++ from <code>main()</code> when + there are no threads yet/anymore:</p> + + <pre class="c++"> +#include <xercesc/util/PlatformUtils.hpp> + +int +main () +{ + xercesc::XMLPlatformUtils::Initialize (); + + { + // Start/terminate threads and parse/serialize here. + } + + xercesc::XMLPlatformUtils::Terminate (); +} + </pre> + + <p>Because you initialize the Xerces-C++ runtime yourself you should + also pass the <code>xml_schema::flags::dont_initialize</code> flag + to parsing and serialization functions. See <a href="#5">Chapter 5, + "Parsing"</a> and <a href="#6">Chapter 6, "Serialization"</a> for + more information.</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 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 elements that comprise an + object model class as well as how to create, access, and modify + object models.</p> + + <p>In this and subsequent chapters 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_t"> + <xs:restriction base="xs:string"> + <xs:enumeration value="male"/> + <xs:enumeration value="female"/> + </xs:restriction> + </xs:simpleType> + + <xs:complexType name="person_t"> + <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_t"/> + <xs:element name="age" type="xs:short"/> + </xs:sequence> + <xs:attribute name="id" type="xs:unsignedInt" use="required"/> + </xs:complexType> + + <xs:complexType name="people_t"> + <xs:sequence> + <xs:element name="person" type="person_t" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="people" type="people_t"/> + +</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 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <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 compiler results + in three generated C++ classes: <code>gender_t</code>, + <code>person_t</code>, and <code>people_t</code>. + The <code>gender_t</code> class is modelled after the C++ + <code>enum</code> type. Its definition is presented below:</p> + + <pre class="c++"> +class gender_t: public xml_schema::string +{ +public: + enum value + { + male, + female + }; + + gender_t (value); + gender_t (const xml_schema::string&); + + gender_t& + operator= (value); + + operator value () const; +}; + </pre> + + <p>The following listing shows how we can use this type:</p> + + <pre class="c++"> +gender_t m (gender_t::male); +gender_t f ("female"); + +if (m == "female" || f == gender_t::male) +{ + ... +} + +switch (m) +{ +case gender_t::male: + { + ... + } +case gender_t::female: + { + ... + } +} + </pre> + + <p>The other two classes will be examined in detail in the subsequent + sections.</p> + + <h2><a name="4.1">4.1 Attribute and Element Cardinalities</a></h2> + + <p>As we have seen in the previous chapters, XSD generates a different + set of type definitions and member functions for elements with + different cardinalities. The C++/Tree 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 required attributes. In our + example, the <code>first-name</code>, <code>last-name</code>, + <code>gender</code>, and <code>age</code> elements as well as + the <code>id</code> attribute belong to this cardinality class. + The following code fragment shows type definitions as well as the + accessor and modifier functions that are generated for the + <code>gender</code> element in the <code>person_t</code> class:</p> + + <pre class="c++"> +class person_t +{ + // gender + // + typedef gender_t gender_type; + + const gender_type& + gender () const; + + gender_type& + gender (); + + void + gender (const gender_type&); +}; + </pre> + + <p>The <code>gender_type</code> type is an alias for the element's type. + 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.</p> + + <p>The <em>optional</em> cardinality class covers all elements that + can occur zero or one time as well as optional attributes. In our + example, the <code>middle-name</code> element belongs to this + cardinality class. The following code fragment shows the type + definitions as well as the accessor and modifier functions that + are generated for this element in the <code>person_t</code> class:</p> + + <pre class="c++"> +class person_t +{ + // middle-name + // + typedef xml_schema::string middle_name_type; + typedef xsd::optional<middle_name_type> middle_name_optional; + + const middle_name_optional& + middle_name () const; + + middle_name_optional& + middle_name (); + + void + middle_name (const middle_name_type&); + + void + middle_name (const middle_name_optional&); +}; + </pre> + + <p>As with the <code>gender</code> element, <code>middle_name_type</code> + is an alias for the element's type. The <code>middle_name_optional</code> + type is a container for the element's optional value. It can be queried + for the presence of the value using the <code>present()</code> function. + The value itself can be retrieved using the <code>get()</code> + accessor and set using the <code>set()</code> modifier. The container + can be reverted to the value not present state with the call to the + <code>reset()</code> function. The following example shows how we + can use this container:</p> + + <pre class="c++"> +person_t::middle_name_optional n ("John"); + +if (n.present ()) +{ + cout << n.get () << endl; +} + +n.set ("Jane"); +n.reset (); + </pre> + + + <p>Unlike the <em>one</em> cardinality class, the accessor functions + for the <em>optional</em> class return read-only (constant) and + read-write references to the container instead of the element's + value directly. The modifier functions set the new value for the + element.</p> + + <p>Finally, the <em>sequence</em> cardinality class covers all elements + that can occur more than once. In our example, the + <code>person</code> element in the <code>people_t</code> type + belongs to this cardinality class. The following code fragment shows + the type definitions as well as the accessor and modifier functions + that are generated for this element in the <code>people_t</code> + class:</p> + + <pre class="c++"> +class people_t +{ + // person + // + typedef person_t person_type; + typedef xsd::sequence<person_type> person_sequence; + typedef person_sequence::iterator person_iterator; + typedef person_sequence::const_iterator person_const_iterator; + + const person_sequence& + person () const; + + person_sequence& + person (); + + void + person (const person_sequence&); +}; + </pre> + + <p>Identical to the other cardinality classes, <code>person_type</code> + is an alias for the element's type. The <code>person_sequence</code> + type is a sequence container for the element's values. It is based + on and has the same interface as <code>std::vector</code> and + therefore can be used in similar ways. The <code>person_iterator</code> + and <code>person_const_iterator</code> types are read-only + (constant) and read-write iterators for the <code>person_sequence</code> + container.</p> + + <p>Similar to the <em>optional</em> cardinality class, the + accessor functions for the <em>sequence</em> class return + read-only (constant) and read-write references to the sequence + container. The modifier functions copies the entries from + the passed sequence.</p> + + <p>C++/Tree is a "flattening" mapping in a sense that many levels of + nested compositors (<code>choice</code> and <code>sequence</code>), + all potentially with their own cardinalities, are in the end mapped + to a flat set of elements with one of the three cardinality classes + discussed above. While this results in a simple and easy to use API + for most types, in certain cases, the order of elements in the actual + XML documents is not preserved once parsed into the object model. To + overcome this limitation we can mark certain schema types, for which + content order is not sufficiently preserved, as ordered. For more + information on this functionality refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.8.4">Section + 2.8.4, "Element Order"</a> in the C++/Tree Mapping User Manual.</p> + + <p>For complex schemas with many levels of nested compositors + (<code>choice</code> and <code>sequence</code>) it can also + be hard to deduce the cardinality class of a particular element. + The generated Doxygen documentation can greatly help with + this task. For each element and attribute the documentation + clearly identifies its cardinality class. Alternatively, you + can study the generated header files to find out the cardinality + class of a particular attribute or element.</p> + + <p>In the next sections we will examine how to access and modify + information stored in an object model using accessor and modifier + functions described in this section.</p> + + <h2><a name="4.2">4.2 Accessing the Object Model</a></h2> + + <p>In this section we will learn how to get to the information + stored in the object model for our person records vocabulary. + The following application accesses and prints the contents + of the <code>people.xml</code> file:</p> + + <pre class="c++"> +#include <iostream> +#include "people.hxx" + +using namespace std; + +int +main () +{ + unique_ptr<people_t> ppl (people ("people.xml")); + + // Iterate over individual person records. + // + people_t::person_sequence& ps (ppl->person ()); + + for (people_t::person_iterator i (ps.begin ()); i != ps.end (); ++i) + { + person_t& 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 ().get () << " "; + + cout << p.last_name () << endl; + + // Print gender, age, and id which are all required. + // + cout << "gender: " << p.gender () << 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 <code>people_t</code>) 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 element + <code>middle-name</code> we first check if the value is present + and only then call <code>get()</code> 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 potentially + expensive copy. This is generally a good rule to follow when + creating high-performance 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.3">4.3 Modifying the Object Model</a></h2> + + <p>In this section we will learn 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 <iostream> +#include "people.hxx" + +using namespace std; + +int +main () +{ + unique_ptr<people_t> ppl (people ("people.xml")); + + // Iterate over individual person records and increment + // the age. + // + people_t::person_sequence& ps (ppl->person ()); + + for (people_t::person_iterator i (ps.begin ()); i != ps.end (); ++i) + { + // Alternative way: i->age ()++; + // + i->age (i->age () + 1); + } + + // Add middle-name to the first record and remove it from + // the second. + // + person_t& john (ps[0]); + person_t& jane (ps[1]); + + john.middle_name ("Mary"); + jane.middle_name ().reset (); + + // Add another John record. + // + ps.push_back (john); + + // Serialize the modified object model to XML. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "people.xsd"; + + people (cout, *ppl, map); +} + </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 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <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.4">4.4 Creating the Object Model from Scratch</a></h2> + + <p>In this section we will learn 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" + +using namespace std; + +int +main () +{ + people_t ppl; + people_t::person_sequence& ps (ppl.person ()); + + // Add the John Doe record. + // + ps.push_back ( + person_t ("John", // first-name + "Doe", // last-name + gender_t::male, // gender + 32, // age + 1)); + + // Add the Jane Doe record. + // + ps.push_back ( + person_t ("Jane", // first-name + "Doe", // last-name + gender_t::female, // gender + 28, // age + 2)); // id + + // Add middle name to the Jane Doe record. + // + person_t& jane (ps.back ()); + jane.middle_name ("Mary"); + + // Serialize the object model to XML. + // + xml_schema::namespace_infomap map; + map[""].name = ""; + map[""].schema = "people.xsd"; + + people (cout, ppl, map); +} + </pre> + + <p>The only new part in the above application is the calls + to the <code>people_t</code> and <code>person_t</code> + constructors. As a general rule, for each C++ class + XSD generates a constructor with initializers + for each element and attribute belonging to the <em>one</em> + cardinality class. For our vocabulary, the following + constructors are generated:</p> + + <pre class="c++"> +class person_t +{ + person_t (const first_name_type&, + const last_name_type&, + const gender_type&, + const age_type&, + const id_type&); +}; + +class people_t +{ + people_t (); +}; + </pre> + + <p>Note also that we set the <code>middle-name</code> element + on the Jane Doe record by obtaining a reference to that record + in the object model and setting the <code>middle-name</code> + value on it. This is a general rule that should be followed + in order to obtain the best performance: if possible, + direct modifications to the object model should be preferred + to modifications on temporaries with subsequent copying. The + following code fragment shows a semantically equivalent but + slightly slower version:</p> + + <pre class="c++"> +// Add the Jane Doe record. +// +person_t jane ("Jane", // first-name + "Doe", // last-name + gender_t::female, // gender + 28, // age + 2); // id + +jane.middle_name ("Mary"); + +ps.push_back (jane); + </pre> + + <p>We can also go one step further to reduce copying and improve + the performance of our application by using the non-copying + <code>push_back()</code> function which assumes ownership + of the passed objects:</p> + + <pre class="c++"> +// Add the Jane Doe record. C++11 version +// +unique_ptr<person_t> jane_p ( + new person_t ("Jane", // first-name + "Doe", // last-name + gender_t::female, // gender + 28, // age + 2)); // id +ps.push_back (std::move (jane_p)); // assumes ownership + +// Add the John Doe record. C++98 version. +// +auto_ptr<person_t> john_p ( + new person_t ("John", // first-name + "Doe", // last-name + gender_t::male, // gender + 32, // age + 1)); +ps.push_back (john_p); // assumes ownership + </pre> + + <p>For more information on the non-copying modifier functions refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.8">Section + 2.8, "Mapping for Local Elements and Attributes"</a> in the C++/Tree Mapping + User Manual. The above application produces the following output:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <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.5">4.5 Mapping for the Built-in XML Schema Types</a></h2> + + <p>Our person record vocabulary uses several built-in XML Schema + types: <code>string</code>, <code>short</code>, and + <code>unsignedInt</code>. Until now we haven't talked about + the mapping of built-in XML Schema types to C++ types and how + to work with them. This section provides an overview + of the built-in types. For more detailed information refer + to <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.5">Section + 2.5, "Mapping for Built-in Data Types"</a> in the C++/Tree Mapping + User Manual.</p> + + <p>In XML Schema, built-in types are defined in the XML Schema namespace. + By default, the C++/Tree mapping maps this namespace 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:</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 long</code></td> + </tr> + <tr> + <td><code>unsignedLong</code></td> + <td><code>unsigned_long</code></td> + <td><code>unsigned long long</code></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 long</code></td> + </tr> + <tr> + <td><code>nonPositiveInteger</code></td> + <td><code>non_positive_integer</code></td> + <td><code>long long</code></td> + </tr> + <tr> + <td><code>nonNegativeInteger</code></td> + <td><code>non_negative_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>positiveInteger</code></td> + <td><code>positive_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>negativeInteger</code></td> + <td><code>negative_integer</code></td> + <td><code>long 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>type derived from <code>std::basic_string</code></td> + </tr> + <tr> + <td><code>normalizedString</code></td> + <td><code>normalized_string</code></td> + <td>type derived from <code>string</code></td> + </tr> + <tr> + <td><code>token</code></td> + <td><code>token</code></td> + <td>type derived from <code>normalized_string</code></td> + </tr> + <tr> + <td><code>Name</code></td> + <td><code>name</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKEN</code></td> + <td><code>nmtoken</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKENS</code></td> + <td><code>nmtokens</code></td> + <td>type derived from <code>sequence<nmtoken></code></td> + </tr> + <tr> + <td><code>NCName</code></td> + <td><code>ncname</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>language</code></td> + <td><code>language</code></td> + <td>type derived from <code>token</code></td> + </tr> + + <tr> + <th colspan="3">qualified name</th> + </tr> + <tr> + <td><code>QName</code></td> + <td><code>qname</code></td> + <td><code>xml_schema::qname</code></td> + </tr> + + <tr> + <th colspan="3">ID/IDREF types</th> + </tr> + <tr> + <td><code>ID</code></td> + <td><code>id</code></td> + <td>type derived from <code>ncname</code></td> + </tr> + <tr> + <td><code>IDREF</code></td> + <td><code>idref</code></td> + <td>type derived from <code>ncname</code></td> + </tr> + <tr> + <td><code>IDREFS</code></td> + <td><code>idrefs</code></td> + <td>type derived from <code>sequence<idref></code></td> + </tr> + + <tr> + <th colspan="3">URI types</th> + </tr> + <tr> + <td><code>anyURI</code></td> + <td><code>uri</code></td> + <td>type derived from <code>std::basic_string</code></td> + </tr> + + <tr> + <th colspan="3">binary types</th> + </tr> + <tr> + <td><code>base64Binary</code></td> + <td><code>base64_binary</code></td> + <td><code>xml_schema::base64_binary</code></td> + </tr> + <tr> + <td><code>hexBinary</code></td> + <td><code>hex_binary</code></td> + <td><code>xml_schema::hex_binary</code></td> + </tr> + + <tr> + <th colspan="3">date/time types</th> + </tr> + <tr> + <td><code>date</code></td> + <td><code>date</code></td> + <td><code>xml_schema::date</code></td> + </tr> + <tr> + <td><code>dateTime</code></td> + <td><code>date_time</code></td> + <td><code>xml_schema::date_time</code></td> + </tr> + <tr> + <td><code>duration</code></td> + <td><code>duration</code></td> + <td><code>xml_schema::duration</code></td> + </tr> + <tr> + <td><code>gDay</code></td> + <td><code>gday</code></td> + <td><code>xml_schema::gday</code></td> + </tr> + <tr> + <td><code>gMonth</code></td> + <td><code>gmonth</code></td> + <td><code>xml_schema::gmonth</code></td> + </tr> + <tr> + <td><code>gMonthDay</code></td> + <td><code>gmonth_day</code></td> + <td><code>xml_schema::gmonth_day</code></td> + </tr> + <tr> + <td><code>gYear</code></td> + <td><code>gyear</code></td> + <td><code>xml_schema::gyear</code></td> + </tr> + <tr> + <td><code>gYearMonth</code></td> + <td><code>gyear_month</code></td> + <td><code>xml_schema::gyear_month</code></td> + </tr> + <tr> + <td><code>time</code></td> + <td><code>time</code></td> + <td><code>xml_schema::time</code></td> + </tr> + + <tr> + <th colspan="3">entity types</th> + </tr> + <tr> + <td><code>ENTITY</code></td> + <td><code>entity</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>ENTITIES</code></td> + <td><code>entities</code></td> + <td>type derived from <code>sequence<entity></code></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 C++ types that are derived + from either <code>std::string</code> or + <code>std::wstring</code>, depending on the character + type selected. For access and modification purposes these + types can be treated as <code>std::string</code>. 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. As a result, + these types are implemented from scratch in the XSD runtime. + For more information on their interfaces refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.5">Section + 2.5, "Mapping for Built-in Data Types"</a> in the C++/Tree Mapping + User Manual.</p> + + + <!-- Chapater 5 --> + + + <h1><a name="5">5 Parsing</a></h1> + + <p>We have already seen how to parse XML to an object model in this guide + before. In this chapter we will discuss the parsing topic in more + detail.</p> + + <p>By default, the C++/Tree mapping provides a total of 14 overloaded + parsing functions. They differ in the input methods used to + read XML as well as the error reporting mechanisms. It is also possible + to generate types for root elements instead of parsing and serialization + functions. This may be useful if your XML vocabulary has multiple + root elements. For more information on element types refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.9">Section + 2.9, "Mapping for Global Elements"</a> in the C++/Tree Mapping User + Manual.</p> + + + <p>In this section we will discuss the most commonly used versions of + the parsing functions. For a comprehensive description of parsing + refer to <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#3">Chapter + 3, "Parsing"</a> in the C++/Tree Mapping User Manual. For the <code>people</code> + global element from our person record vocabulary, we will concentrate + on the following three parsing functions:</p> + + <pre class="c++"> +std::[unique|auto]_ptr<people_t> +people (const std::string& uri, + xml_schema::flags f = 0, + const xml_schema::properties& p = xml_schema::properties ()); + +std::[unique|auto]_ptr<people_t> +people (std::istream& is, + xml_schema::flags f = 0, + const xml_schema::properties& p = xml_schema::properties ()); + +std::[unique|auto]_ptr<people_t> +people (std::istream& is, + const std::string& resource_id, + xml_schema::flags f = 0, + const xml_schema::properties& p = ::xml_schema::properties ()); + </pre> + + <p>The first function parses a local file or a URI. We have already + used this parsing function in the previous chapters. The second + and third functions read XML from a standard input stream. The + last function also requires a resource id. This id is used to + identify the XML document being parser in diagnostics messages + as well as to resolve relative paths to other documents (for example, + schemas) that might be referenced from the XML document.</p> + + <p>The last two arguments to all three parsing functions are parsing + flags and properties. The flags argument provides a number of ways + to fine-tune the parsing process. The properties argument allows + to pass additional information to the parsing functions. We will + use these two arguments in <a href="#5.1">Section 5.1, "XML Schema + Validation and Searching"</a> below. All three functions return + the object model as either <code>std::unique_ptr</code> (C++11) or + <code>std::auto_ptr</code> (C++98), depending on the C++ standard + selected (<code>--std</code> XSD compiler option). The following + example shows how we can use the above parsing functions:</p> + + <pre class="c++"> +using std::unique_ptr; + +// Parse a local file or URI. +// +unique_ptr<people_t> p1 (people ("people.xml")); +unique_ptr<people_t> p2 (people ("http://example.com/people.xml")); + +// Parse a local file via ifstream. +// +std::ifstream ifs ("people.xml"); +unique_ptr<people_t> p3 (people (ifs, "people.xml")); + +// Parse an XML string. +// +std::string str ("..."); // XML in a string. +std::istringstream iss (str); +unique_ptr<people_t> p4 (people (iss)); + </pre> + + + <h2><a name="5.1">5.1 XML Schema Validation and Searching</a></h2> + + <p>The C++/Tree mapping relies on the underlying Xerces-C++ XML + parser for full XML document validation. The XML Schema + validation is enabled by default and can be disabled by + passing the <code>xml_schema::flags::dont_validate</code> + flag to the parsing functions, for example:</p> + + <pre class="c++"> +unique_ptr<people_t> p ( + people ("people.xml", xml_schema::flags::dont_validate)); + </pre> + + <p>Even when XML Schema validation is disabled, the generated + code still performs a number of checks to prevent + construction of an inconsistent object model (for example, an + object model with missing required attributes or elements).</p> + + <p>When XML Schema validation is enabled, the XML parser needs + to locate a schema to validate against. There are several + methods to provide the schema location information to the + parser. The easiest and most commonly used method is to + specify schema locations in the XML document itself + with the <code>schemaLocation</code> or + <code>noNamespaceSchemaLocation</code> attributes, for example:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd" + xsi:schemaLocation="http://www.w3.org/XML/1998/namespace xml.xsd"> + </pre> + + <p>As you might have noticed, we used this method in all the sample XML + documents presented in this guide up until now. Note that the + schema locations specified with these two attributes are relative + to the document's path unless they are absolute URIs (that is + start with <code>http://</code>, <code>file://</code>, etc.). + In particular, if you specify just file names as your schema + locations, as we did above, then the schemas should reside in + the same directory as the XML document itself.</p> + + <p>Another method of providing the schema location information + is via the <code>xml_schema::properties</code> argument, as + shown in the following example:</p> + + <pre class="c++"> +xml_schema::properties props; +props.no_namespace_schema_location ("people.xsd"); +props.schema_location ("http://www.w3.org/XML/1998/namespace", "xml.xsd"); + +unique_ptr<people_t> p (people ("people.xml", 0, props)); + </pre> + + <p>The schema locations provided with this method overrides + those specified in the XML document. As with the previous + method, the schema locations specified this way are + relative to the document's path unless they are absolute URIs. + In particular, if you want to use local schemas that are + not related to the document being parsed, then you will + need to use the <code>file://</code> URI. The following + example shows how to use schemas that reside in the current + working directory:</p> + + <pre class="c++"> +#include <unistd.h> // getcwd +#include <limits.h> // PATH_MAX + +char cwd[PATH_MAX]; +if (getcwd (cwd, PATH_MAX) == 0) +{ + // Buffer too small? +} + +xml_schema::properties props; + +props.no_namespace_schema_location ( + "file:///" + std::string (cwd) + "/people.xsd"); + +props.schema_location ( + "http://www.w3.org/XML/1998/namespace", + "file:///" + std::string (cwd) + "/xml.xsd"); + +unique_ptr<people_t> p (people ("people.xml", 0, props)); + </pre> + + <p>A third method is the most useful if you are planning to parse + several XML documents of the same vocabulary. In that case + it may be beneficial to pre-parse and cache the schemas in + the XML parser which can then be used to parse all documents + without re-parsing the schemas. For more information on + this method refer to the <code>caching</code> example in the + <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package. + It is also possible to convert the schemas into a pre-compiled + binary representation and embed this representation directly into + the application executable. With this approach your application can + perform XML Schema validation without depending on any external + schema files. For more information on how to achieve this refer to + the <code>embedded</code> example in the <code>cxx/tree/</code> + directory in the <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <p>When the XML parser cannot locate a schema for the + XML document, the validation fails and XML document + elements and attributes for which schema definitions could + not be located are reported in the diagnostics. For + example, if we remove the <code>noNamespaceSchemaLocation</code> + attribute in <code>people.xml</code> from the previous chapter, + then we will get the following diagnostics if we try to parse + this file with validation enabled:</p> + + <pre class="terminal"> +people.xml:2:63 error: no declaration found for element 'people' +people.xml:4:18 error: no declaration found for element 'person' +people.xml:4:18 error: attribute 'id' is not declared for element 'person' +people.xml:5:17 error: no declaration found for element 'first-name' +people.xml:6:18 error: no declaration found for element 'middle-name' +people.xml:7:16 error: no declaration found for element 'last-name' +people.xml:8:13 error: no declaration found for element 'gender' +people.xml:9:10 error: no declaration found for element 'age' + </pre> + + <h2><a name="5.2">5.2 Error Handling</a></h2> + + <p>The parsing functions offer a number of ways to handle error conditions + with the C++ exceptions being the most commonly used mechanism. All + C++/Tree exceptions derive from common base <code>xml_schema::exception</code> + which in turn derives from <code>std::exception</code>. The easiest + way to uniformly handle all possible C++/Tree exceptions and print + detailed information about the error is to catch and print + <code>xml_schema::exception</code>, as shown in the following + example:</p> + + <pre class="c++"> +try +{ + unique_ptr<people_t> p (people ("people.xml")); +} +catch (const xml_schema::exception& e) +{ + cerr << e << endl; +} + </pre> + + <p>Each individual C++/Tree exception also allows you to obtain + error details programmatically. For example, the + <code>xml_schema::parsing</code> exception is thrown when + the XML parsing and validation in the underlying XML parser + fails. It encapsulates various diagnostics information + such as the file name, line and column numbers, as well as the + error or warning message for each entry. For more information + about this and other exceptions that can be thrown during + parsing, refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#3.3">Section + 3.3, "Error Handling"</a> in the C++/Tree Mapping + User Manual.</p> + + <p>Note that if you are parsing <code>std::istream</code> on which + exceptions are not enabled, then you will need to check the + stream state after the call to the parsing function in order + to detect any possible stream failures, for example:</p> + + <pre class="c++"> +std::ifstream ifs ("people.xml"); + +if (ifs.fail ()) +{ + cerr << "people.xml: unable to open" << endl; + return 1; +} + +unique_ptr<people_t> p (people (ifs, "people.xml")); + +if (ifs.fail ()) +{ + cerr << "people.xml: read error" << endl; + return 1; +} + </pre> + + <p>The above example can be rewritten to use exceptions as + shown below:</p> + + <pre class="c++"> +try +{ + std::ifstream ifs; + ifs.exceptions (std::ifstream::badbit | std::ifstream::failbit); + ifs.open ("people.xml"); + + unique_ptr<people_t> p (people (ifs, "people.xml")); +} +catch (const std::ifstream::failure&) +{ + cerr << "people.xml: unable to open or read error" << endl; + return 1; +} + </pre> + + + <!-- Chapater 6 --> + + + <h1><a name="6">6 Serialization</a></h1> + + <p>We have already seen how to serialize an object model back to XML + in this guide before. In this chapter we will discuss the + serialization topic in more detail.</p> + + <p>By default, the C++/Tree mapping provides a total of 8 overloaded + serialization functions. They differ in the output methods used to write + XML as well as the error reporting mechanisms. It is also possible to + generate types for root elements instead of parsing and serialization + functions. This may be useful if your XML vocabulary has multiple + root elements. For more information on element types refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.9">Section + 2.9, "Mapping for Global Elements"</a> in the C++/Tree Mapping User + Manual.</p> + + + <p>In this section we will discuss the most commonly + used version of serialization functions. For a comprehensive description + of serialization refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#4">Chapter + 4, "Serialization"</a> in the C++/Tree Mapping User Manual. For the + <code>people</code> global element from our person record vocabulary, + we will concentrate on the following serialization function:</p> + + <pre class="c++"> +void +people (std::ostream& os, + const people_t& x, + const xml_schema::namespace_infomap& map = + xml_schema::namespace_infomap (), + const std::string& encoding = "UTF-8", + xml_schema::flags f = 0); + </pre> + + <p>This function serializes the object model passed as the second + argument to the standard output stream passed as the first + argument. The third argument is a namespace information map + which we will discuss in more detail in the next section. + The fourth argument is a character encoding that the resulting + XML document should be in. Possible valid values for this + argument are "US-ASCII", "ISO8859-1", "UTF-8", "UTF-16BE", + "UTF-16LE", "UCS-4BE", and "UCS-4LE". Finally, the flags + argument allows fine-tuning of the serialization process. + The following example shows how we can use the above serialization + function:</p> + + <pre class="c++"> +people_t& p = ... + +xml_schema::namespace_infomap map; +map[""].schema = "people.xsd"; + +// Serialize to stdout. +// +people (std::cout, p, map); + +// Serialize to a file. +// +std::ofstream ofs ("people.xml"); +people (ofs, p, map); + +// Serialize to a string. +// +std::ostringstream oss; +people (oss, p, map); +std::string xml (oss.str ()); + </pre> + + + <h2><a name="6.1">6.1 Namespace and Schema Information</a></h2> + + <p>While XML serialization can be done just from the object + model alone, it is often desirable to assign meaningful + prefixes to XML namespaces used in the vocabulary as + well as to provide the schema location information. + This is accomplished by passing the namespace information + map to the serialization function. The key in this map is + a namespace prefix that should be assigned to an XML namespace + specified in the <code>name</code> variable of the + map value. You can also assign an optional schema location for + this namespace in the <code>schema</code> variable. Based + on each key-value entry in this map, the serialization + function adds two attributes to the resulting XML document: + the namespace-prefix mapping attribute and schema location + attribute. The empty prefix indicates that the namespace + should be mapped without a prefix. For example, the following + map:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].name = "http://www.example.com/example"; +map[""].schema = "example.xsd"; + +map["x"].name = "http://www.w3.org/XML/1998/namespace"; +map["x"].schema = "xml.xsd"; + </pre> + + <p>Results in the following XML document:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<example + xmlns="http://www.example.com/example" + xmlns:x="http://www.w3.org/XML/1998/namespace" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.example.com/example example.xsd + http://www.w3.org/XML/1998/namespace xml.xsd"> + </pre> + + <p>The empty namespace indicates that the vocabulary has no target + namespace. For example, the following map results in only the + <code>noNamespaceSchemaLocation</code> attribute being added:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].name = ""; +map[""].schema = "example.xsd"; + </pre> + + <h2><a name="6.2">6.2 Error Handling</a></h2> + + <p>Similar to the parsing functions, the serialization functions offer a + number of ways to handle error conditions with the C++ exceptions being + the most commonly used mechanisms. As with parsing, the easiest way to + uniformly handle all possible serialization exceptions and print + detailed information about the error is to catch and print + <code>xml_schema::exception</code>:</p> + + <pre class="c++"> +try +{ + people_t& p = ... + + xml_schema::namespace_infomap map; + map[""].schema = "people.xsd"; + + people (std::cout, p, map)); +} +catch (const xml_schema::exception& e) +{ + cerr << e << endl; +} + </pre> + + <p>The most commonly encountered serialization exception is + <code>xml_schema::serialization</code>. It is thrown + when the XML serialization in the underlying XML writer + fails. It encapsulates various diagnostics information + such as the file name, line and column numbers, as well as the + error or warning message for each entry. For more information + about this and other exceptions that can be thrown during + serialization, refer to + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#4.4">Section + 4.4, "Error Handling"</a> in the C++/Tree Mapping + User Manual.</p> + + <p>Note that if you are serializing to <code>std::ostream</code> on + which exceptions are not enabled, then you will need to check the + stream state after the call to the serialization function in order + to detect any possible stream failures, for example:</p> + + <pre class="c++"> +std::ofstream ofs ("people.xml"); + +if (ofs.fail ()) +{ + cerr << "people.xml: unable to open" << endl; + return 1; +} + +people (ofs, p, map)); + +if (ofs.fail ()) +{ + cerr << "people.xml: write error" << endl; + return 1; +} + </pre> + + <p>The above example can be rewritten to use exceptions as + shown below:</p> + + <pre class="c++"> +try +{ + std::ofstream ofs; + ofs.exceptions (std::ofstream::badbit | std::ofstream::failbit); + ofs.open ("people.xml"); + + people (ofs, p, map)); +} +catch (const std::ofstream::failure&) +{ + cerr << "people.xml: unable to open or write error" << endl; + return 1; +} + </pre> + + </div> +</div> + +</body> +</html> diff --git a/doc/cxx/tree/manual/index.xhtml b/doc/cxx/tree/manual/index.xhtml new file mode 100644 index 0000000..f455bff --- /dev/null +++ b/doc/cxx/tree/manual/index.xhtml @@ -0,0 +1,6826 @@ +<?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>C++/Tree Mapping User Manual</title> + + <meta name="copyright" content="© 2005-2023 Code Synthesis"/> + <meta name="keywords" content="xsd,xml,schema,c++,mapping,data,binding,tree,serialization,guide,manual,examples"/> + <meta name="description" content="C++/Tree Mapping User Manual"/> + <meta name="revision" content="4.1.0"/> + + <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%; + } + + h2 { + font-weight : bold; + font-size : 150%; + + padding-top : 0.8em; + } + + h3 { + font-size : 130%; + 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; + padding: 1em 0 2em 0; + } + + /* Lists */ + ul.list li { + padding-top : 0.3em; + padding-bottom : 0.3em; + } + + + /* 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; + } + + + /* default-fixed */ + #default-fixed { + margin: 2em 0 2em 0; + + border-collapse : collapse; + border : 1px solid; + border-color : #000000; + + font-size : 11px; + line-height : 14px; + } + + #default-fixed th, #default-fixed td { + border: 1px solid; + padding : 0.9em 0.9em 0.7em 0.9em; + } + + #default-fixed th { + background : #cde8f6; + } + + #default-fixed td { + text-align: center; + } + + + /* */ + 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; + } +</style> + + +</head> + +<body> +<div id="container"> + <div id="content"> + + <div class="noprint"> + + <div id="titlepage"> + <div id="title">C++/Tree Mapping User Manual</div> + + <p>Copyright © 2005-2023 Code Synthesis.</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href="https://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="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/index.xhtml">XHTML</a>, + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.pdf">PDF</a>, and + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.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></td> + </tr> + + <tr> + <th>2</th><td><a href="#2">C++/Tree Mapping</a> + <table class="toc"> + <tr> + <th>2.1</th><td><a href="#2.1">Preliminary Information</a> + <table class="toc"> + <tr><th>2.1.1</th><td><a href="#2.1.1">C++ Standard</a></td></tr> + <tr><th>2.1.2</th><td><a href="#2.1.2">Identifiers</a></td></tr> + <tr><th>2.1.3</th><td><a href="#2.1.3">Character Type and Encoding</a></td></tr> + <tr><th>2.1.4</th><td><a href="#2.1.4">XML Schema Namespace</a></td></tr> + <tr><th>2.1.5</th><td><a href="#2.1.5">Anonymous Types</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.2</th><td><a href="#2.2">Error Handling</a> + <table class="toc"> + <tr><th>2.2.1</th><td><a href="#2.2.1"><code>xml_schema::duplicate_id</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.3</th><td><a href="#2.3">Mapping for <code>import</code> and <code>include</code></a> + <table class="toc"> + <tr><th>2.3.1</th><td><a href="#2.3.1">Import</a></td></tr> + <tr><th>2.3.2</th><td><a href="#2.3.2">Inclusion with Target Namespace</a></td></tr> + <tr><th>2.3.3</th><td><a href="#2.3.3">Inclusion without Target Namespace</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.4</th><td><a href="#2.4">Mapping for Namespaces</a></td> + </tr> + <tr> + <th>2.5</th><td><a href="#2.5">Mapping for Built-in Data Types</a> + <table class="toc"> + <tr><th>2.5.1</th><td><a href="#2.5.1">Inheritance from Built-in Data Types</a></td></tr> + <tr><th>2.5.2</th><td><a href="#2.5.2">Mapping for <code>anyType</code></a></td></tr> + <tr><th>2.5.3</th><td><a href="#2.5.3">Mapping for <code>anySimpleType</code></a></td></tr> + <tr><th>2.5.4</th><td><a href="#2.5.4">Mapping for <code>QName</code></a></td></tr> + <tr><th>2.5.5</th><td><a href="#2.5.5">Mapping for <code>IDREF</code></a></td></tr> + <tr><th>2.5.6</th><td><a href="#2.5.6">Mapping for <code>base64Binary</code> and <code>hexBinary</code></a></td></tr> + <tr><th>2.5.7</th><td><a href="#2.5.7">Time Zone Representation</a></td></tr> + <tr><th>2.5.8</th><td><a href="#2.5.8">Mapping for <code>date</code></a></td></tr> + <tr><th>2.5.9</th><td><a href="#2.5.9">Mapping for <code>dateTime</code></a></td></tr> + <tr><th>2.5.10</th><td><a href="#2.5.10">Mapping for <code>duration</code></a></td></tr> + <tr><th>2.5.11</th><td><a href="#2.5.11">Mapping for <code>gDay</code></a></td></tr> + <tr><th>2.5.12</th><td><a href="#2.5.12">Mapping for <code>gMonth</code></a></td></tr> + <tr><th>2.5.13</th><td><a href="#2.5.13">Mapping for <code>gMonthDay</code></a></td></tr> + <tr><th>2.5.14</th><td><a href="#2.5.14">Mapping for <code>gYear</code></a></td></tr> + <tr><th>2.5.15</th><td><a href="#2.5.15">Mapping for <code>gYearMonth</code></a></td></tr> + <tr><th>2.5.16</th><td><a href="#2.5.16">Mapping for <code>time</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.6</th><td><a href="#2.6">Mapping for Simple Types</a> + <table class="toc"> + <tr><th>2.6.1</th><td><a href="#2.6.1">Mapping for Derivation by Restriction</a></td></tr> + <tr><th>2.6.2</th><td><a href="#2.6.2">Mapping for Enumerations</a></td></tr> + <tr><th>2.6.3</th><td><a href="#2.6.3">Mapping for Derivation by List</a></td></tr> + <tr><th>2.6.4</th><td><a href="#2.6.4">Mapping for Derivation by Union</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.7</th><td><a href="#2.7">Mapping for Complex Types</a> + <table class="toc"> + <tr><th>2.7.1</th><td><a href="#2.7.1">Mapping for Derivation by Extension</a></td></tr> + <tr><th>2.7.2</th><td><a href="#2.7.2">Mapping for Derivation by Restriction</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.8</th><td><a href="#2.8">Mapping for Local Elements and Attributes</a> + <table class="toc"> + <tr><th>2.8.1</th><td><a href="#2.8.1">Mapping for Members with the One Cardinality Class</a></td></tr> + <tr><th>2.8.2</th><td><a href="#2.8.2">Mapping for Members with the Optional Cardinality Class</a></td></tr> + <tr><th>2.8.3</th><td><a href="#2.8.3">Mapping for Members with the Sequence Cardinality Class</a></td></tr> + <tr><th>2.8.4</th><td><a href="#2.8.4">Element Order</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.9</th><td><a href="#2.9">Mapping for Global Elements</a> + <table class="toc"> + <tr><th>2.9.1</th><td><a href="#2.9.1">Element Types</a></td></tr> + <tr><th>2.9.2</th><td><a href="#2.9.2">Element Map</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.10</th><td><a href="#2.10">Mapping for Global Attributes</a></td> + </tr> + <tr> + <th>2.11</th><td><a href="#2.11">Mapping for <code>xsi:type</code> and Substitution Groups</a></td> + </tr> + <tr> + <th>2.12</th><td><a href="#2.12">Mapping for <code>any</code> and <code>anyAttribute</code></a> + <table class="toc"> + <tr><th>2.12.1</th><td><a href="#2.12.1">Mapping for <code>any</code> with the One Cardinality Class</a></td></tr> + <tr><th>2.12.2</th><td><a href="#2.12.2">Mapping for <code>any</code> with the Optional Cardinality Class</a></td></tr> + <tr><th>2.12.3</th><td><a href="#2.12.3">Mapping for <code>any</code> with the Sequence Cardinality Class</a></td></tr> + <tr><th>2.12.4</th><td><a href="#2.12.4">Element Wildcard Order</a></td></tr> + <tr><th>2.12.5</th><td><a href="#2.12.5">Mapping for <code>anyAttribute</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.13</th><td><a href="#2.13">Mapping for Mixed Content Models</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">Parsing</a> + <table class="toc"> + <tr> + <th>3.1</th><td><a href="#3.1">Initializing the Xerces-C++ Runtime</a></td> + </tr> + <tr> + <th>3.2</th><td><a href="#3.2">Flags and Properties</a></td> + </tr> + <tr> + <th>3.3</th><td><a href="#3.3">Error Handling</a> + <table class="toc"> + <tr><th>3.3.1</th><td><a href="#3.3.1"><code>xml_schema::parsing</code></a></td></tr> + <tr><th>3.3.2</th><td><a href="#3.3.2"><code>xml_schema::expected_element</code></a></td></tr> + <tr><th>3.3.3</th><td><a href="#3.3.3"><code>xml_schema::unexpected_element</code></a></td></tr> + <tr><th>3.3.4</th><td><a href="#3.3.4"><code>xml_schema::expected_attribute</code></a></td></tr> + <tr><th>3.3.5</th><td><a href="#3.3.5"><code>xml_schema::unexpected_enumerator</code></a></td></tr> + <tr><th>3.3.6</th><td><a href="#3.3.6"><code>xml_schema::expected_text_content</code></a></td></tr> + <tr><th>3.3.7</th><td><a href="#3.3.7"><code>xml_schema::no_type_info</code></a></td></tr> + <tr><th>3.3.8</th><td><a href="#3.3.8"><code>xml_schema::not_derived</code></a></td></tr> + <tr><th>3.3.9</th><td><a href="#3.3.9"><code>xml_schema::not_prefix_mapping</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>3.4</th><td><a href="#3.4">Reading from a Local File or URI</a></td> + </tr> + <tr> + <th>3.5</th><td><a href="#3.5">Reading from <code>std::istream</code></a></td> + </tr> + <tr> + <th>3.6</th><td><a href="#3.6">Reading from <code>xercesc::InputSource</code></a></td> + </tr> + <tr> + <th>3.7</th><td><a href="#3.7">Reading from DOM</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th>4</th><td><a href="#4">Serialization</a> + <table class="toc"> + <tr> + <th>4.1</th><td><a href="#4.1">Initializing the Xerces-C++ Runtime</a></td> + </tr> + <tr> + <th>4.2</th><td><a href="#4.2">Namespace Infomap and Character Encoding</a></td> + </tr> + <tr> + <th>4.3</th><td><a href="#4.3">Flags</a></td> + </tr> + <tr> + <th>4.4</th><td><a href="#4.4">Error Handling</a> + <table class="toc"> + <tr><th>4.4.1</th><td><a href="#4.4.1"><code>xml_schema::serialization</code></a></td></tr> + <tr><th>4.4.2</th><td><a href="#4.4.2"><code>xml_schema::unexpected_element</code></a></td></tr> + <tr><th>4.4.3</th><td><a href="#4.4.3"><code>xml_schema::no_type_info</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>4.5</th><td><a href="#4.5">Serializing to <code>std::ostream</code></a></td> + </tr> + <tr> + <th>4.6</th><td><a href="#4.6">Serializing to <code>xercesc::XMLFormatTarget</code></a></td> + </tr> + <tr> + <th>4.7</th><td><a href="#4.7">Serializing to DOM</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th>5</th><td><a href="#5">Additional Functionality</a> + <table class="toc"> + <tr> + <th>5.1</th><td><a href="#5.1">DOM Association</a></td> + </tr> + <tr> + <th>5.2</th><td><a href="#5.2">Binary Serialization</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th></th><td><a href="#A">Appendix A — Default and Fixed Values</a></td> + </tr> + + </table> + </div> + + <h1><a name="0">Preface</a></h1> + + <h2><a name="0.1">About This Document</a></h2> + + <p>This document describes the mapping of W3C XML Schema + to the C++ programming language as implemented by + <a href="https://www.codesynthesis.com/products/xsd">CodeSynthesis + XSD</a> - an XML Schema to C++ data binding compiler. The mapping + represents information stored in XML instance documents as a + statically-typed, tree-like in-memory data structure and is + called C++/Tree. + </p> + + <p>Revision 4.1.0<br/> <!-- Remember to change revision in other places --> + This revision of the manual describes the C++/Tree + mapping as implemented by CodeSynthesis XSD version 4.1.0. + </p> + + <p>This document is available in the following formats: + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/index.xhtml">XHTML</a>, + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.pdf">PDF</a>, and + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.ps">PostScript</a>.</p> + + <h2><a name="0.2">More Information</a></h2> + + <p>Beyond this manual, you may also find the following sources of + information useful:</p> + + <ul class="list"> + <li><a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/">C++/Tree + Mapping Getting Started Guide</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/Customization_guide">C++/Tree + Mapping Customization Guide</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree + Mapping Frequently Asked Questions (FAQ)</a></li> + + <li><a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a></li> + + <li>The <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + contains a collection of examples and a README file with an overview + of each example.</li> + + <li>The <code>README</code> file in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + explains how to build the examples.</li> + + <li>The <a href="https://www.codesynthesis.com/mailman/listinfo/xsd-users">xsd-users</a> + mailing list is a place to ask questions. Furthermore the + <a href="https://www.codesynthesis.com/pipermail/xsd-users/">archives</a> + may already have answers to some of your questions.</li> + </ul> + + + <h1><a name="1">1 Introduction</a></h1> + + <p>C++/Tree is a W3C XML Schema to C++ mapping that represents the + data stored in XML as a statically-typed, vocabulary-specific + object model. Based on a formal description of an XML vocabulary + (schema), the C++/Tree mapping produces a tree-like data structure + suitable for in-memory processing as well as XML parsing and + serialization code.</p> + + <p>A typical application that processes XML documents usually + performs the following three steps: it first reads (parses) an XML + instance document to an object model, it then performs + some useful computations on that model which may involve + modification of the model, and finally it may write (serialize) + the modified object model back to XML. + </p> + + <p>The C++/Tree mapping consists of C++ types that represent the + given vocabulary (<a href="#2">Chapter 2, "C++/Tree Mapping"</a>), + a set of parsing functions that convert XML documents to + a tree-like in-memory data structure (<a href="#3">Chapter 3, + "Parsing"</a>), and a set of serialization functions that convert + the object model back to XML (<a href="#4">Chapter 4, + "Serialization"</a>). Furthermore, the mapping provides a number + of additional features, such as DOM association and binary + serialization, that can be useful in some applications + (<a href="#5">Chapter 5, "Additional Functionality"</a>). + </p> + + + <!-- Chapter 2 --> + + + <h1><a name="2">2 C++/Tree Mapping</a></h1> + + <h2><a name="2.1">2.1 Preliminary Information</a></h2> + + <h3><a name="2.1.1">2.1.1 C++ Standard</a></h3> + + <p>The C++/Tree mapping provides support for ISO/IEC C++ 2011 (C++11) + and ISO/IEC C++ 1998/2003 (C++98). To select the C++ standard for the + generated code we use the <code>--std</code> XSD compiler command + line option. While the majority of the examples in this guide use + C++11, the document explains the C++11/98 usage difference and so + they can easily be converted to C++98.</p> + + <h3><a name="2.1.2">2.1.2 Identifiers</a></h3> + + <p>XML Schema names may happen to be reserved C++ keywords or contain + characters that are illegal in C++ identifiers. To avoid C++ compilation + problems, such names are changed (escaped) when mapped to C++. If an + XML Schema name is a C++ keyword, the "_" suffix is added to it. All + character of an XML Schema name that are not allowed in C++ identifiers + are replaced with "_". + </p> + + <p>For example, XML Schema name <code>try</code> will be mapped to + C++ identifier <code>try_</code>. Similarly, XML Schema name + <code>strange.na-me</code> will be mapped to C++ identifier + <code>strange_na_me</code>. + </p> + + <p>Furthermore, conflicts between type names and function names in the + same scope are resolved using name escaping. Such conflicts include + both a global element (which is mapped to a set of parsing and/or + serialization functions or element types, see <a href="#2.9">Section + 2.9, "Mapping for Global Elements"</a>) and a global type sharing the + same name as well as a local element or attribute inside a type having + the same name as the type itself.</p> + + <p>For example, if we had a global type <code>catalog</code> + and a global element with the same name then the type would be + mapped to a C++ class with name <code>catalog</code> while the + parsing functions corresponding to the global element would have + their names escaped as <code>catalog_</code>. + </p> + + <p>By default the mapping uses the so-called K&R (Kernighan and + Ritchie) identifier naming convention which is also used throughout + this manual. In this convention both type and function names are in + lower case and words are separated by underscores. If your application + code or schemas use a different notation, you may want to change the + naming convention used by the mapping for consistency. + The compiler supports a set of widely-used naming conventions + that you can select with the <code>--type-naming</code> and + <code>--function-naming</code> options. You can also further + refine one of the predefined conventions or create a completely + custom naming scheme by using the <code>--*-regex</code> options. + For more detailed information on these options refer to the NAMING + CONVENTION section in the <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>.</p> + + <h3><a name="2.1.3">2.1.3 Character Type and Encoding</a></h3> + + <p>The code that implements the mapping, depending on the + <code>--char-type</code> option, is generated using either + <code>char</code> or <code>wchar_t</code> as the character + type. In this document code samples use symbol <code>C</code> + to refer to the character type you have selected when translating + your schemas, for example <code>std::basic_string<C></code>. + </p> + + <p>Another aspect of the mapping that depends on the character type + is character encoding. For the <code>char</code> character type + the default encoding is UTF-8. Other supported encodings are + ISO-8859-1, Xerces-C++ Local Code Page (LPC), as well as + custom encodings and can be selected with the + <code>--char-encoding</code> command line option.</p> + + <p>For the <code>wchar_t</code> character type the encoding is + automatically selected between UTF-16 and UTF-32/UCS-4 depending + on the size of the <code>wchar_t</code> type. On some platforms + (for example, Windows with Visual C++ and AIX with IBM XL C++) + <code>wchar_t</code> is 2 bytes long. For these platforms the + encoding is UTF-16. On other platforms <code>wchar_t</code> is 4 bytes + long and UTF-32/UCS-4 is used.</p> + + <h3><a name="2.1.4">2.1.4 XML Schema Namespace</a></h3> + + <p>The mapping relies on some predefined types, classes, and functions + that are logically defined in the XML Schema namespace reserved for + the XML Schema language (<code>http://www.w3.org/2001/XMLSchema</code>). + By default, this namespace is mapped to C++ namespace + <code>xml_schema</code>. It is automatically accessible + from a C++ compilation unit that includes a header file generated + from an XML Schema definition. + </p> + + <p>Note that, if desired, the default mapping of this namespace can be + changed as described in <a href="#2.4">Section 2.4, "Mapping for + Namespaces"</a>. + </p> + + + <h3><a name="2.1.5">2.1.5 Anonymous Types</a></h3> + + <p>For the purpose of code generation, anonymous types defined in + XML Schema are automatically assigned names that are derived + from enclosing attributes and elements. Otherwise, such types + follows standard mapping rules for simple and complex type + definitions (see <a href="#2.6">Section 2.6, "Mapping for Simple Types"</a> + and <a href="#2.7">Section 2.7, "Mapping for Complex Types"</a>). + For example, in the following schema fragment: + </p> + + <pre class="xml"> +<element name="object"> + <complexType> + ... + </complexType> +</element> + </pre> + + <p>The anonymous type defined inside element <code>object</code> will + be given name <code>object</code>. The compiler has a number of + options that control the process of anonymous type naming. For more + information refer to the <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>.</p> + + + <h2><a name="2.2">2.2 Error Handling</a></h2> + + <p>The mapping uses the C++ exception handling mechanism as a primary way + of reporting error conditions. All exceptions that are specified in + this mapping derive from <code>xml_schema::exception</code> which + itself is derived from <code>std::exception</code>: + </p> + + <pre class="c++"> +struct exception: virtual std::exception +{ + friend + std::basic_ostream<C>& + operator<< (std::basic_ostream<C>& os, const exception& e) + { + e.print (os); + return os; + } + +protected: + virtual void + print (std::basic_ostream<C>&) const = 0; +}; + </pre> + + <p>The exception hierarchy supports "virtual" <code>operator<<</code> + which allows you to obtain diagnostics corresponding to the thrown + exception using the base exception interface. For example:</p> + + <pre class="c++"> +try +{ + ... +} +catch (const xml_schema::exception& e) +{ + cerr << e << endl; +} + </pre> + + <p>The following sub-sections describe exceptions thrown by the + types that constitute the object model. + <a href="#3.3">Section 3.3, "Error Handling"</a> of + <a href="#3">Chapter 3, "Parsing"</a> describes exceptions + and error handling mechanisms specific to the parsing functions. + <a href="#4.4">Section 4.4, "Error Handling"</a> of + <a href="#4">Chapter 4, "Serialization"</a> describes exceptions + and error handling mechanisms specific to the serialization functions. + </p> + + + <h3><a name="2.2.1">2.2.1 <code>xml_schema::duplicate_id</code></a></h3> + + <pre class="c++"> +struct duplicate_id: virtual exception +{ + duplicate_id (const std::basic_string<C>& id); + + const std::basic_string<C>& + id () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::duplicate_id</code> is thrown when + a conflicting instance of <code>xml_schema::id</code> (see + <a href="#2.5">Section 2.5, "Mapping for Built-in Data Types"</a>) + is added to a tree. The offending ID value can be obtained using + the <code>id</code> function. + </p> + + <h2><a name="2.3">2.3 Mapping for <code>import</code> and <code>include</code></a></h2> + + <h3><a name="2.3.1">2.3.1 Import</a></h3> + + <p>The XML Schema <code>import</code> element is mapped to the C++ + Preprocessor <code>#include</code> directive. The value of + the <code>schemaLocation</code> attribute is used to derive + the name of the header file that appears in the <code>#include</code> + directive. For instance: + </p> + + <pre class="xml"> +<import namespace="https://www.codesynthesis.com/test" + schemaLocation="test.xsd"/> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +#include "test.hxx" + </pre> + + <p>Note that you will need to compile imported schemas separately + in order to produce corresponding header files.</p> + + <h3><a name="2.3.2">2.3.2 Inclusion with Target Namespace</a></h3> + + <p>The XML Schema <code>include</code> element which refers to a schema + with a target namespace or appears in a schema without a target namespace + follows the same mapping rules as the <code>import</code> element, + see <a href="#2.3.1">Section 2.3.1, "Import"</a>. + </p> + + <h3><a name="2.3.3">2.3.3 Inclusion without Target Namespace</a></h3> + + <p>For the XML Schema <code>include</code> element which refers to a schema + without a target namespace and appears in a schema with a target + namespace (such inclusion sometimes called "chameleon inclusion"), + declarations and definitions from the included schema are generated + in-line in the namespace of the including schema as if they were + declared and defined there verbatim. For example, consider the + following two schemas: + </p> + + <pre class="xml"> +<-- common.xsd --> +<schema> + <complexType name="type"> + ... + </complexType> +</schema> + +<-- test.xsd --> +<schema targetNamespace="https://www.codesynthesis.com/test"> + <include schemaLocation="common.xsd"/> +</schema> + </pre> + + <p>The fragment of interest from the generated header file for + <code>text.xsd</code> would look like this:</p> + + <pre class="c++"> +// test.hxx +namespace test +{ + class type + { + ... + }; +} + </pre> + + <h2><a name="2.4">2.4 Mapping for Namespaces</a></h2> + + <p>An XML Schema namespace is mapped to one or more nested C++ + namespaces. XML Schema namespaces are identified by URIs. + 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 instance: + </p> + + <pre class="xml"> +<schema targetNamespace="https://www.codesynthesis.com/system/test"> + ... +</schema> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +namespace system +{ + namespace test + { + ... + } +} + </pre> + + <p>The default mapping of namespace URIs to C++ namespace names can be + altered using the <code>--namespace-map</code> and + <code>--namespace-regex</code> options. See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information. + </p> + + <h2><a name="2.5">2.5 Mapping for Built-in Data Types</a></h2> + + <p>The mapping of XML Schema built-in data types to C++ types is + summarized in the table below.</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">anyType and anySimpleType types</th> + </tr> + <tr> + <td><code>anyType</code></td> + <td><code>type</code></td> + <td><a href="#2.5.2">Section 2.5.2, "Mapping for <code>anyType</code>"</a></td> + </tr> + <tr> + <td><code>anySimpleType</code></td> + <td><code>simple_type</code></td> + <td><a href="#2.5.3">Section 2.5.3, "Mapping for <code>anySimpleType</code>"</a></td> + </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 long</code></td> + </tr> + <tr> + <td><code>unsignedLong</code></td> + <td><code>unsigned_long</code></td> + <td><code>unsigned long long</code></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 long</code></td> + </tr> + <tr> + <td><code>nonPositiveInteger</code></td> + <td><code>non_positive_integer</code></td> + <td><code>long long</code></td> + </tr> + <tr> + <td><code>nonNegativeInteger</code></td> + <td><code>non_negative_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>positiveInteger</code></td> + <td><code>positive_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>negativeInteger</code></td> + <td><code>negative_integer</code></td> + <td><code>long 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>type derived from <code>std::basic_string</code></td> + </tr> + <tr> + <td><code>normalizedString</code></td> + <td><code>normalized_string</code></td> + <td>type derived from <code>string</code></td> + </tr> + <tr> + <td><code>token</code></td> + <td><code>token</code></td> + <td>type derived from <code>normalized_string</code></td> + </tr> + <tr> + <td><code>Name</code></td> + <td><code>name</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKEN</code></td> + <td><code>nmtoken</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKENS</code></td> + <td><code>nmtokens</code></td> + <td>type derived from <code>sequence<nmtoken></code></td> + </tr> + <tr> + <td><code>NCName</code></td> + <td><code>ncname</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>language</code></td> + <td><code>language</code></td> + <td>type derived from <code>token</code></td> + </tr> + + <tr> + <th colspan="3">qualified name</th> + </tr> + <tr> + <td><code>QName</code></td> + <td><code>qname</code></td> + <td><a href="#2.5.4">Section 2.5.4, "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>type derived from <code>ncname</code></td> + </tr> + <tr> + <td><code>IDREF</code></td> + <td><code>idref</code></td> + <td><a href="#2.5.5">Section 2.5.5, "Mapping for <code>IDREF</code>"</a></td> + </tr> + <tr> + <td><code>IDREFS</code></td> + <td><code>idrefs</code></td> + <td>type derived from <code>sequence<idref></code></td> + </tr> + + <tr> + <th colspan="3">URI types</th> + </tr> + <tr> + <td><code>anyURI</code></td> + <td><code>uri</code></td> + <td>type derived from <code>std::basic_string</code></td> + </tr> + + <tr> + <th colspan="3">binary types</th> + </tr> + <tr> + <td><code>base64Binary</code></td> + <td><code>base64_binary</code></td> + <td rowspan="2"><a href="#2.5.6">Section 2.5.6, "Mapping for + <code>base64Binary</code> and <code>hexBinary</code>"</a></td> + </tr> + <tr> + <td><code>hexBinary</code></td> + <td><code>hex_binary</code></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="#2.5.8">Section 2.5.8, "Mapping for + <code>date</code>"</a></td> + </tr> + <tr> + <td><code>dateTime</code></td> + <td><code>date_time</code></td> + <td><a href="#2.5.9">Section 2.5.9, "Mapping for + <code>dateTime</code>"</a></td> + </tr> + <tr> + <td><code>duration</code></td> + <td><code>duration</code></td> + <td><a href="#2.5.10">Section 2.5.10, "Mapping for + <code>duration</code>"</a></td> + </tr> + <tr> + <td><code>gDay</code></td> + <td><code>gday</code></td> + <td><a href="#2.5.11">Section 2.5.11, "Mapping for + <code>gDay</code>"</a></td> + </tr> + <tr> + <td><code>gMonth</code></td> + <td><code>gmonth</code></td> + <td><a href="#2.5.12">Section 2.5.12, "Mapping for + <code>gMonth</code>"</a></td> + </tr> + <tr> + <td><code>gMonthDay</code></td> + <td><code>gmonth_day</code></td> + <td><a href="#2.5.13">Section 2.5.13, "Mapping for + <code>gMonthDay</code>"</a></td> + </tr> + <tr> + <td><code>gYear</code></td> + <td><code>gyear</code></td> + <td><a href="#2.5.14">Section 2.5.14, "Mapping for + <code>gYear</code>"</a></td> + </tr> + <tr> + <td><code>gYearMonth</code></td> + <td><code>gyear_month</code></td> + <td><a href="#2.5.15">Section 2.5.15, "Mapping for + <code>gYearMonth</code>"</a></td> + </tr> + <tr> + <td><code>time</code></td> + <td><code>time</code></td> + <td><a href="#2.5.16">Section 2.5.16, "Mapping for + <code>time</code>"</a></td> + </tr> + + <tr> + <th colspan="3">entity types</th> + </tr> + <tr> + <td><code>ENTITY</code></td> + <td><code>entity</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>ENTITIES</code></td> + <td><code>entities</code></td> + <td>type derived from <code>sequence<entity></code></td> + </tr> + </table> + + <p>All XML Schema built-in types are mapped to C++ classes that are + derived from the <code>xml_schema::simple_type</code> class except + where the mapping is to a fundamental C++ type.</p> + + <p>The <code>sequence</code> class template is defined in an + implementation-specific namespace. It conforms to the + sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences"). + Practically, this means that you can treat such a sequence + as if it was <code>std::vector</code>. One notable extension + to the standard interface that is available only for + sequences of non-fundamental C++ types is the addition of + the overloaded <code>push_back</code> and <code>insert</code> + member functions which instead of the constant reference + to the element type accept automatic pointer (<code>std::unique_ptr</code> + or <code>std::auto_ptr</code>, depending on the C++ standard + selected) to the element type. These functions assume ownership + of the pointed to object and reset the passed automatic pointer. + </p> + + <h3><a name="2.5.1">2.5.1 Inheritance from Built-in Data Types</a></h3> + + <p>In cases where the mapping calls for an inheritance from a built-in + type which is mapped to a fundamental C++ type, a proxy type is + used instead of the fundamental C++ type (C++ does not allow + inheritance from fundamental types). For instance:</p> + + <pre class="xml"> +<simpleType name="my_int"> + <restriction base="int"/> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class my_int: public fundamental_base<int> +{ + ... +}; + </pre> + + <p>The <code>fundamental_base</code> class template provides a close + emulation (though not exact) of a fundamental C++ type. + It is defined in an implementation-specific namespace and has the + following interface:</p> + + <pre class="c++"> +template <typename X> +class fundamental_base: public simple_type +{ +public: + fundamental_base (); + fundamental_base (X) + fundamental_base (const fundamental_base&) + +public: + fundamental_base& + operator= (const X&); + +public: + operator const X & () const; + operator X& (); + + template <typename Y> + operator Y () const; + + template <typename Y> + operator Y (); +}; + </pre> + + <h3><a name="2.5.2">2.5.2 Mapping for <code>anyType</code></a></h3> + + <p>The XML Schema <code>anyType</code> built-in data type is mapped to the + <code>xml_schema::type</code> C++ class:</p> + + <pre class="c++"> +class type +{ +public: + virtual + ~type (); + + type (); + type (const type&); + + type& + operator= (const type&); + + virtual type* + _clone () const; + + // anyType DOM content. + // +public: + typedef element_optional dom_content_optional; + + const dom_content_optional& + dom_content () const; + + dom_content_optional& + dom_content (); + + void + dom_content (const xercesc::DOMElement&); + + void + dom_content (xercesc::DOMElement*); + + void + dom_content (const dom_content_optional&); + + const xercesc::DOMDocument& + dom_content_document () const; + + xercesc::DOMDocument& + dom_content_document (); + + bool + null_content () const; + + // DOM association. + // +public: + const xercesc::DOMNode* + _node () const; + + xercesc::DOMNode* + _node (); +}; + </pre> + + <p>When <code>xml_schema::type</code> is used to create an instance + (as opposed to being a base of a derived type), it represents + the XML Schema <code>anyType</code> type. <code>anyType</code> + allows any attributes and any content in any order. In the + C++/Tree mapping this content can be represented as a DOM + fragment, similar to XML Schema wildcards (<a href="#2.12">Section + 2.12, "Mapping for <code>any</code> and + <code>anyAttribute</code>"</a>).</p> + + <p>To enable automatic extraction of <code>anyType</code> content + during parsing, the <code>--generate-any-type</code> option must be + specified. Because the DOM API is used to access such content, the + Xerces-C++ runtime should be initialized by the application prior to + parsing and should remain initialized for the lifetime of objects + with the DOM content. For more information on the Xerces-C++ runtime + initialization see <a href="#3.1">Section 3.1, "Initializing the + Xerces-C++ Runtime"</a>.</p> + + <p>The DOM content is stored as the optional DOM element container + and the DOM content accessors and modifiers presented above are + identical to those generated for an optional element wildcard. + Refer to <a href="#2.12.2">Section 2.12.2, "Mapping for <code>any</code> + with the Optional Cardinality Class"</a> for details on their + semantics.</p> + + <p>The <code>dom_content_document()</code> function returns the + DOM document used to store the raw XML content corresponding + to the <code>anyType</code> instance. It is equivalent to the + <code>dom_document()</code> function generated for types + with wildcards.</p> + + <p>The <code>null_content()</code> accessor is an optimization function + that allows us to check for the lack of content without actually + creating its empty representation, that is, empty DOM document for + <code>anyType</code> or empty string for <code>anySimpleType</code> + (see the following section for details on <code>anySimpleType</code>).</p> + + <p>For more information on DOM association refer to + <a href="#5.1">Section 5.1, "DOM Association"</a>.</p> + + <h3><a name="2.5.3">2.5.3 Mapping for <code>anySimpleType</code></a></h3> + + <p>The XML Schema <code>anySimpleType</code> built-in data type is mapped + to the <code>xml_schema::simple_type</code> C++ class:</p> + + <pre class="c++"> +class simple_type: public type +{ +public: + simple_type (); + simple_type (const C*); + simple_type (const std::basic_string<C>&); + + simple_type (const simple_type&); + + simple_type& + operator= (const simple_type&); + + virtual simple_type* + _clone () const; + + // anySimpleType text content. + // +public: + const std::basic_string<C>& + text_content () const; + + std::basic_string<C>& + text_content (); + + void + text_content (const std::basic_string<C>&); +}; + </pre> + + <p>When <code>xml_schema::simple_type</code> is used to create an instance + (as opposed to being a base of a derived type), it represents + the XML Schema <code>anySimpleType</code> type. <code>anySimpleType</code> + allows any simple content. In the C++/Tree mapping this content can + be represented as a string and accessed or modified with the + <code>text_content()</code> functions shown above.</p> + + <h3><a name="2.5.4">2.5.4 Mapping for <code>QName</code></a></h3> + + <p>The XML Schema <code>QName</code> built-in data type is mapped to the + <code>xml_schema::qname</code> C++ class:</p> + + <pre class="c++"> +class qname: public simple_type +{ +public: + qname (const ncname&); + qname (const uri&, const ncname&); + qname (const qname&); + +public: + qname& + operator= (const qname&); + +public: + virtual qname* + _clone () const; + +public: + bool + qualified () const; + + const uri& + namespace_ () const; + + const ncname& + name () const; +}; + </pre> + + <p>The <code>qualified</code> accessor function can be used to determine + if the name is qualified.</p> + + <h3><a name="2.5.5">2.5.5 Mapping for <code>IDREF</code></a></h3> + + <p>The XML Schema <code>IDREF</code> built-in data type is mapped to the + <code>xml_schema::idref</code> C++ class. This class implements the + smart pointer C++ idiom:</p> + + <pre class="c++"> +class idref: public ncname +{ +public: + idref (const C* s); + idref (const C* s, std::size_t n); + idref (std::size_t n, C c); + idref (const std::basic_string<C>&); + idref (const std::basic_string<C>&, + std::size_t pos, + std::size_t n = npos); + +public: + idref (const idref&); + +public: + virtual idref* + _clone () const; + +public: + idref& + operator= (C c); + + idref& + operator= (const C* s); + + idref& + operator= (const std::basic_string<C>&) + + idref& + operator= (const idref&); + +public: + const type* + operator-> () const; + + type* + operator-> (); + + const type& + operator* () const; + + type& + operator* (); + + const type* + get () const; + + type* + get (); + + // Conversion to bool. + // +public: + typedef void (idref::*bool_convertible)(); + operator bool_convertible () const; +}; + </pre> + + <p>The object, <code>idref</code> instance refers to, is the immediate + container of the matching <code>id</code> instance. For example, + with the following instance document and schema: + </p> + + + <pre class="xml"> +<!-- test.xml --> +<root> + <object id="obj-1" text="hello"/> + <reference>obj-1</reference> +</root> + +<!-- test.xsd --> +<schema> + <complexType name="object_type"> + <attribute name="id" type="ID"/> + <attribute name="text" type="string"/> + </complexType> + + <complexType name="root_type"> + <sequence> + <element name="object" type="object_type"/> + <element name="reference" type="IDREF"/> + </sequence> + </complexType> + + <element name="root" type="root_type"/> +</schema> + </pre> + + <p>The <code>ref</code> instance in the code below will refer to + an object of type <code>object_type</code>:</p> + + <pre class="c++"> +root_type& root = ...; +xml_schema::idref& ref (root.reference ()); +object_type& obj (dynamic_cast<object_type&> (*ref)); +cout << obj.text () << endl; + </pre> + + <p>The smart pointer interface of the <code>idref</code> class always + returns a pointer or reference to <code>xml_schema::type</code>. + This means that you will need to manually cast such pointer or + reference to its real (dynamic) type before you can use it (unless + all you need is the base interface provided by + <code>xml_schema::type</code>). As a special extension to the XML + Schema language, the mapping supports static typing of <code>idref</code> + references by employing the <code>refType</code> extension attribute. + The following example illustrates this mechanism: + </p> + + <pre class="xml"> +<!-- test.xsd --> +<schema + xmlns:xse="https://www.codesynthesis.com/xmlns/xml-schema-extension"> + + ... + + <element name="reference" type="IDREF" xse:refType="object_type"/> + + ... + +</schema> + </pre> + + <p>With this modification we do not need to do manual casting anymore: + </p> + + <pre class="c++"> +root_type& root = ...; +root_type::reference_type& ref (root.reference ()); +object_type& obj (*ref); +cout << ref->text () << endl; + </pre> + + + <h3><a name="2.5.6">2.5.6 Mapping for <code>base64Binary</code> and + <code>hexBinary</code></a></h3> + + <p>The XML Schema <code>base64Binary</code> and <code>hexBinary</code> + built-in data types are mapped to the + <code>xml_schema::base64_binary</code> and + <code>xml_schema::hex_binary</code> C++ classes, respectively. The + <code>base64_binary</code> and <code>hex_binary</code> classes + support a simple buffer abstraction by inheriting from the + <code>xml_schema::buffer</code> class: + </p> + + <pre class="c++"> +class bounds: public virtual exception +{ +public: + virtual const char* + what () const throw (); +}; + +class buffer +{ +public: + typedef std::size_t size_t; + +public: + buffer (size_t size = 0); + buffer (size_t size, size_t capacity); + buffer (const void* data, size_t size); + buffer (const void* data, size_t size, size_t capacity); + buffer (void* data, + size_t size, + size_t capacity, + bool assume_ownership); + +public: + buffer (const buffer&); + + buffer& + operator= (const buffer&); + + 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 (); +}; + </pre> + + <p>The last overloaded constructor reuses an existing data buffer instead + of making a copy. If the <code>assume_ownership</code> argument is + <code>true</code>, the instance assumes ownership of the + memory block pointed to by the <code>data</code> argument and will + eventually release it by calling <code>operator delete</code>. The + <code>capacity</code> and <code>size</code> modifier functions return + <code>true</code> if the underlying buffer has moved. + </p> + + <p>The <code>bounds</code> exception is thrown if the constructor + arguments violate the <code>(size <= capacity)</code> + constraint.</p> + + <p>The <code>base64_binary</code> and <code>hex_binary</code> classes + support the <code>buffer</code> interface and perform automatic + decoding/encoding from/to the Base64 and Hex formats, respectively: + </p> + + <pre class="c++"> +class base64_binary: public simple_type, public buffer +{ +public: + base64_binary (size_t size = 0); + base64_binary (size_t size, size_t capacity); + base64_binary (const void* data, size_t size); + base64_binary (const void* data, size_t size, size_t capacity); + base64_binary (void* data, + size_t size, + size_t capacity, + bool assume_ownership); + +public: + base64_binary (const base64_binary&); + + base64_binary& + operator= (const base64_binary&); + + virtual base64_binary* + _clone () const; + +public: + std::basic_string<C> + encode () const; +}; + </pre> + + <pre class="c++"> +class hex_binary: public simple_type, public buffer +{ +public: + hex_binary (size_t size = 0); + hex_binary (size_t size, size_t capacity); + hex_binary (const void* data, size_t size); + hex_binary (const void* data, size_t size, size_t capacity); + hex_binary (void* data, + size_t size, + size_t capacity, + bool assume_ownership); + +public: + hex_binary (const hex_binary&); + + hex_binary& + operator= (const hex_binary&); + + virtual hex_binary* + _clone () const; + +public: + std::basic_string<C> + encode () const; +}; + </pre> + + + <h2><a name="2.5.7">2.5.7 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>xml_schema::time_zone</code> base class is used to represent + this information:</p> + + <pre class="c++"> +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 <em>not specified</em> + state. If the time zone offset is negative then both hours and + minutes components are represented as negative integers.</p> + + + <h2><a name="2.5.8">2.5.8 Mapping for <code>date</code></a></h2> + + <p>The XML Schema <code>date</code> built-in data type is mapped to the + <code>xml_schema::date</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class date: public simple_type, public time_zone +{ +public: + date (int year, unsigned short month, unsigned short day); + date (int year, unsigned short month, unsigned short day, + short zone_hours, short zone_minutes); + +public: + date (const date&); + + date& + operator= (const date&); + + virtual date* + _clone () const; + +public: + 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="2.5.9">2.5.9 Mapping for <code>dateTime</code></a></h2> + + <p>The XML Schema <code>dateTime</code> built-in data type is mapped to the + <code>xml_schema::date_time</code> C++ 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="#2.5.7">Section + 2.5.7, "Time Zone Representation"</a>.</p> + + <pre class="c++"> +class date_time: public simple_type, public time_zone +{ +public: + 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); +public: + date_time (const date_time&); + + date_time& + operator= (const date_time&); + + virtual date_time* + _clone () const; + +public: + 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="2.5.10">2.5.10 Mapping for <code>duration</code></a></h2> + + <p>The XML Schema <code>duration</code> built-in data type is mapped to the + <code>xml_schema::duration</code> C++ 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++"> +class duration: public simple_type +{ +public: + duration (bool negative, + unsigned int years, unsigned int months, unsigned int days, + unsigned int hours, unsigned int minutes, double seconds); +public: + duration (const duration&); + + duration& + operator= (const duration&); + + virtual duration* + _clone () const; + +public: + 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="2.5.11">2.5.11 Mapping for <code>gDay</code></a></h2> + + <p>The XML Schema <code>gDay</code> built-in data type is mapped to the + <code>xml_schema::gday</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gday: public simple_type, public time_zone +{ +public: + explicit + gday (unsigned short day); + gday (unsigned short day, short zone_hours, short zone_minutes); + +public: + gday (const gday&); + + gday& + operator= (const gday&); + + virtual gday* + _clone () const; + +public: + unsigned short + day () const; + + void + day (unsigned short); +}; + +bool +operator== (const gday&, const gday&); + +bool +operator!= (const gday&, const gday&); + </pre> + + + <h2><a name="2.5.12">2.5.12 Mapping for <code>gMonth</code></a></h2> + + <p>The XML Schema <code>gMonth</code> built-in data type is mapped to the + <code>xml_schema::gmonth</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gmonth: public simple_type, public time_zone +{ +public: + explicit + gmonth (unsigned short month); + gmonth (unsigned short month, + short zone_hours, short zone_minutes); + +public: + gmonth (const gmonth&); + + gmonth& + operator= (const gmonth&); + + virtual gmonth* + _clone () const; + +public: + unsigned short + month () const; + + void + month (unsigned short); +}; + +bool +operator== (const gmonth&, const gmonth&); + +bool +operator!= (const gmonth&, const gmonth&); + </pre> + + + <h2><a name="2.5.13">2.5.13 Mapping for <code>gMonthDay</code></a></h2> + + <p>The XML Schema <code>gMonthDay</code> built-in data type is mapped to the + <code>xml_schema::gmonth_day</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gmonth_day: public simple_type, public time_zone +{ +public: + gmonth_day (unsigned short month, unsigned short day); + gmonth_day (unsigned short month, unsigned short day, + short zone_hours, short zone_minutes); + +public: + gmonth_day (const gmonth_day&); + + gmonth_day& + operator= (const gmonth_day&); + + virtual gmonth_day* + _clone () const; + +public: + 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="2.5.14">2.5.14 Mapping for <code>gYear</code></a></h2> + + <p>The XML Schema <code>gYear</code> built-in data type is mapped to the + <code>xml_schema::gyear</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone Representation"</a>.</p> + + <pre class="c++"> +class gyear: public simple_type, public time_zone +{ +public: + explicit + gyear (int year); + gyear (int year, short zone_hours, short zone_minutes); + +public: + gyear (const gyear&); + + gyear& + operator= (const gyear&); + + virtual gyear* + _clone () const; + +public: + int + year () const; + + void + year (int); +}; + +bool +operator== (const gyear&, const gyear&); + +bool +operator!= (const gyear&, const gyear&); + </pre> + + + <h2><a name="2.5.15">2.5.15 Mapping for <code>gYearMonth</code></a></h2> + + <p>The XML Schema <code>gYearMonth</code> built-in data type is mapped to + the <code>xml_schema::gyear_month</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gyear_month: public simple_type, public time_zone +{ +public: + gyear_month (int year, unsigned short month); + gyear_month (int year, unsigned short month, + short zone_hours, short zone_minutes); +public: + gyear_month (const gyear_month&); + + gyear_month& + operator= (const gyear_month&); + + virtual gyear_month* + _clone () const; + +public: + 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="2.5.16">2.5.16 Mapping for <code>time</code></a></h2> + + <p>The XML Schema <code>time</code> built-in data type is mapped to + the <code>xml_schema::time</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone Representation"</a>.</p> + + <pre class="c++"> +class time: public simple_type, public time_zone +{ +public: + time (unsigned short hours, unsigned short minutes, double seconds); + time (unsigned short hours, unsigned short minutes, double seconds, + short zone_hours, short zone_minutes); + +public: + time (const time&); + + time& + operator= (const time&); + + virtual time* + _clone () const; + +public: + 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> + + + <!-- Mapping for Simple Types --> + + <h2><a name="2.6">2.6 Mapping for Simple Types</a></h2> + + <p>An XML Schema simple type is mapped to a C++ class with the same + name as the simple type. The class defines a public copy constructor, + a public copy assignment operator, and a public virtual + <code>_clone</code> function. The <code>_clone</code> function is + declared <code>const</code>, does not take any arguments, and returns + a pointer to a complete copy of the instance allocated in the free + store. The <code>_clone</code> function shall be used to make copies + when static type and dynamic type of the instance may differ (see + <a href="#2.11">Section 2.11, "Mapping for <code>xsi:type</code> + and Substitution Groups"</a>). For instance:</p> + + <pre class="xml"> +<simpleType name="object"> + ... +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: ... +{ +public: + object (const object&); + +public: + object& + operator= (const object&); + +public: + virtual object* + _clone () const; + + ... + +}; + </pre> + + <p>The base class specification and the rest of the class definition + depend on the type of derivation used to define the simple type. </p> + + + <h3><a name="2.6.1">2.6.1 Mapping for Derivation by Restriction</a></h3> + + <p>XML Schema derivation by restriction is mapped to C++ public + inheritance. The base type of the restriction becomes the base + type for the resulting C++ class. In addition to the members described + in <a href="#2.6">Section 2.6, "Mapping for Simple Types"</a>, the + resulting C++ class defines a public constructor with the base type + as its single argument. For instance:</p> + + <pre class="xml"> +<simpleType name="object"> + <restriction base="base"> + ... + </restriction> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public base +{ +public: + object (const base&); + object (const object&); + +public: + object& + operator= (const object&); + +public: + virtual object* + _clone () const; +}; + </pre> + + + <h3><a name="2.6.2">2.6.2 Mapping for Enumerations</a></h3> + +<p>XML Schema restriction by enumeration is mapped to a C++ class + with semantics similar to C++ <code>enum</code>. Each XML Schema + enumeration element is mapped to a C++ enumerator with the + name derived from the <code>value</code> attribute and defined + in the class scope. In addition to the members + described in <a href="#2.6">Section 2.6, "Mapping for Simple Types"</a>, + the resulting C++ class defines a public constructor that can be called + with one of the enumerators as its single argument, a public constructor + that can be called with enumeration's base value as its single + argument, a public assignment operator that can be used to assign the + value of one of the enumerators, and a public implicit conversion + operator to the underlying C++ enum type.</p> + +<p>Furthermore, for string-based enumeration types, the resulting C++ + class defines a public constructor with a single argument of type + <code>const C*</code> and a public constructor with a single + argument of type <code>const std::basic_string<C>&</code>. + For instance:</p> + + <pre class="xml"> +<simpleType name="color"> + <restriction base="string"> + <enumeration value="red"/> + <enumeration value="green"/> + <enumeration value="blue"/> + </restriction> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class color: public xml_schema::string +{ +public: + enum value + { + red, + green, + blue + }; + +public: + color (value); + color (const C*); + color (const std::basic_string<C>&); + color (const xml_schema::string&); + color (const color&); + +public: + color& + operator= (value); + + color& + operator= (const color&); + +public: + virtual color* + _clone () const; + +public: + operator value () const; +}; + </pre> + + <h3><a name="2.6.3">2.6.3 Mapping for Derivation by List</a></h3> + + <p>XML Schema derivation by list is mapped to C++ public + inheritance from <code>xml_schema::simple_type</code> + (<a href="#2.5.3">Section 2.5.3, "Mapping for + <code>anySimpleType</code>"</a>) and a suitable sequence type. + The list item type becomes the element type of the sequence. + In addition to the members described in <a href="#2.6">Section 2.6, + "Mapping for Simple Types"</a>, the resulting C++ class defines + a public default constructor, a public constructor + with the first argument of type <code>size_type</code> and + the second argument of list item type that creates + a list object with the specified number of copies of the specified + element value, and a public constructor with the two arguments + of an input iterator type that creates a list object from an + iterator range. For instance: + </p> + + <pre class="xml"> +<simpleType name="int_list"> + <list itemType="int"/> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class int_list: public simple_type, + public sequence<int> +{ +public: + int_list (); + int_list (size_type n, int x); + + template <typename I> + int_list (const I& begin, const I& end); + int_list (const int_list&); + +public: + int_list& + operator= (const int_list&); + +public: + virtual int_list* + _clone () const; +}; + </pre> + + <p>The <code>sequence</code> class template is defined in an + implementation-specific namespace. It conforms to the + sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences"). + Practically, this means that you can treat such a sequence + as if it was <code>std::vector</code>. One notable extension + to the standard interface that is available only for + sequences of non-fundamental C++ types is the addition of + the overloaded <code>push_back</code> and <code>insert</code> + member functions which instead of the constant reference + to the element type accept automatic pointer (<code>std::unique_ptr</code> + or <code>std::auto_ptr</code>, depending on the C++ standard + selected) to the element type. These functions assume ownership + of the pointed to object and reset the passed automatic pointer. + </p> + + <h3><a name="2.6.4">2.6.4 Mapping for Derivation by Union</a></h3> + + <p>XML Schema derivation by union is mapped to C++ public + inheritance from <code>xml_schema::simple_type</code> + (<a href="#2.5.3">Section 2.5.3, "Mapping for + <code>anySimpleType</code>"</a>) and <code>std::basic_string<C></code>. + In addition to the members described in <a href="#2.6">Section 2.6, + "Mapping for Simple Types"</a>, the resulting C++ class defines a + public constructor with a single argument of type <code>const C*</code> + and a public constructor with a single argument of type + <code>const std::basic_string<C>&</code>. For instance: + </p> + + <pre class="xml"> +<simpleType name="int_string_union"> + <xsd:union memberTypes="xsd:int xsd:string"/> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class int_string_union: public simple_type, + public std::basic_string<C> +{ +public: + int_string_union (const C*); + int_string_union (const std::basic_string<C>&); + int_string_union (const int_string_union&); + +public: + int_string_union& + operator= (const int_string_union&); + +public: + virtual int_string_union* + _clone () const; +}; + </pre> + + <h2><a name="2.7">2.7 Mapping for Complex Types</a></h2> + + <p>An XML Schema complex type is mapped to a C++ class with the same + name as the complex type. The class defines a public copy constructor, + a public copy assignment operator, and a public virtual + <code>_clone</code> function. The <code>_clone</code> function is + declared <code>const</code>, does not take any arguments, and returns + a pointer to a complete copy of the instance allocated in the free + store. The <code>_clone</code> function shall be used to make copies + when static type and dynamic type of the instance may differ (see + <a href="#2.11">Section 2.11, "Mapping for <code>xsi:type</code> + and Substitution Groups"</a>).</p> + + <p>Additionally, the resulting C++ class + defines two public constructors that take an initializer for each + member of the complex type and all its base types that belongs to + the One cardinality class (see <a href="#2.8">Section 2.8, "Mapping + for Local Elements and Attributes"</a>). In the first constructor, + the arguments are passed as constant references and the newly created + instance is initialized with copies of the passed objects. In the + second constructor, arguments that are complex types (that is, + they themselves contain elements or attributes) are passed as + either <code>std::unique_ptr</code> (C++11) or <code>std::auto_ptr</code> + (C++98), depending on the C++ standard selected. In this case the newly + created instance is directly initialized with and assumes ownership + of the pointed to objects and the <code>std::[unique|auto]_ptr</code> + arguments are reset to <code>0</code>. For instance:</p> + + <pre class="xml"> +<complexType name="complex"> + <sequence> + <element name="a" type="int"/> + <element name="b" type="string"/> + </sequence> +</complexType> + +<complexType name="object"> + <sequence> + <element name="s-one" type="boolean"/> + <element name="c-one" type="complex"/> + <element name="optional" type="int" minOccurs="0"/> + <element name="sequence" type="string" maxOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class complex: public xml_schema::type +{ +public: + object (const int& a, const xml_schema::string& b); + object (const complex&); + +public: + object& + operator= (const complex&); + +public: + virtual complex* + _clone () const; + + ... + +}; + +class object: public xml_schema::type +{ +public: + object (const bool& s_one, const complex& c_one); + object (const bool& s_one, std::[unique|auto]_ptr<complex> c_one); + object (const object&); + +public: + object& + operator= (const object&); + +public: + virtual object* + _clone () const; + + ... + +}; + </pre> + + <p>Notice that the generated <code>complex</code> class does not + have the second (<code>std::[unique|auto]_ptr</code>) version of the + constructor since all its required members are of simple types.</p> + + <p>If an XML Schema complex type has an ultimate base which is an XML + Schema simple type then the resulting C++ class also defines a public + constructor that takes an initializer for the base type as well as + for each member of the complex type and all its base types that + belongs to the One cardinality class. For instance:</p> + + <pre class="xml"> +<complexType name="object"> + <simpleContent> + <extension base="date"> + <attribute name="lang" type="language" use="required"/> + </extension> + </simpleContent> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::string +{ +public: + object (const xml_schema::language& lang); + + object (const xml_schema::date& base, + const xml_schema::language& lang); + + ... + +}; + </pre> + + <p>Furthermore, for string-based XML Schema complex types, the resulting C++ + class also defines two public constructors with the first arguments + of type <code>const C*</code> and <code>std::basic_string<C>&</code>, + respectively, followed by arguments for each member of the complex + type and all its base types that belongs to the One cardinality + class. For enumeration-based complex types the resulting C++ + class also defines a public constructor with the first arguments + of the underlying enum type followed by arguments for each member + of the complex type and all its base types that belongs to the One + cardinality class. For instance:</p> + + <pre class="xml"> +<simpleType name="color"> + <restriction base="string"> + <enumeration value="red"/> + <enumeration value="green"/> + <enumeration value="blue"/> + </restriction> +</simpleType> + +<complexType name="object"> + <simpleContent> + <extension base="color"> + <attribute name="lang" type="language" use="required"/> + </extension> + </simpleContent> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class color: public xml_schema::string +{ +public: + enum value + { + red, + green, + blue + }; + +public: + color (value); + color (const C*); + color (const std::basic_string<C>&); + + ... + +}; + +class object: color +{ +public: + object (const color& base, + const xml_schema::language& lang); + + object (const color::value& base, + const xml_schema::language& lang); + + object (const C* base, + const xml_schema::language& lang); + + object (const std::basic_string<C>& base, + const xml_schema::language& lang); + + ... + +}; + </pre> + + <p>Additional constructors can be requested with the + <code>--generate-default-ctor</code> and + <code>--generate-from-base-ctor</code> options. See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for details.</p> + + <p>If an XML Schema complex type is not explicitly derived from any type, + the resulting C++ class is derived from <code>xml_schema::type</code>. + In cases where an XML Schema complex type is defined using derivation + by extension or restriction, the resulting C++ base class specification + depends on the type of derivation and is described in the subsequent + sections. + </p> + + <p>The mapping for elements and attributes that are defined in a complex + type is described in <a href="#2.8">Section 2.8, "Mapping for Local + Elements and Attributes"</a>. + </p> + + <h3><a name="2.7.1">2.7.1 Mapping for Derivation by Extension</a></h3> + + <p>XML Schema derivation by extension is mapped to C++ public + inheritance. The base type of the extension becomes the base + type for the resulting C++ class. + </p> + + <h3><a name="2.7.2">2.7.2 Mapping for Derivation by Restriction</a></h3> + + <p>XML Schema derivation by restriction is mapped to C++ public + inheritance. The base type of the restriction becomes the base + type for the resulting C++ class. XML Schema elements and + attributes defined within restriction do not result in any + definitions in the resulting C++ class. Instead, corresponding + (unrestricted) definitions are inherited from the base class. + In the future versions of this mapping, such elements and + attributes may result in redefinitions of accessors and + modifiers to reflect their restricted semantics. + </p> + + <!-- 2.8 Mapping for Local Elements and Attributes --> + + <h2><a name="2.8">2.8 Mapping for Local Elements and Attributes</a></h2> + + <p>XML Schema element and attribute definitions are called local + if they appear within a complex type definition, an element group + definition, or an attribute group definitions. + </p> + + <p>Local XML Schema element and attribute definitions have the same + C++ mapping. Therefore, in this section, local elements and + attributes are collectively called members. + </p> + + <p>While there are many different member cardinality combinations + (determined by the <code>use</code> attribute for attributes and + the <code>minOccurs</code> and <code>maxOccurs</code> attributes + for elements), the mapping divides all possible cardinality + combinations into three cardinality classes: + </p> + + <dl> + <dt><i>one</i></dt> + <dd>attributes: <code>use == "required"</code></dd> + <dd>attributes: <code>use == "optional"</code> and has default or fixed value</dd> + <dd>elements: <code>minOccurs == "1"</code> and <code>maxOccurs == "1"</code></dd> + + <dt><i>optional</i></dt> + <dd>attributes: <code>use == "optional"</code> and doesn't have default or fixed value</dd> + <dd>elements: <code>minOccurs == "0"</code> and <code>maxOccurs == "1"</code></dd> + + <dt><i>sequence</i></dt> + <dd>elements: <code>maxOccurs > "1"</code></dd> + </dl> + + <p>An optional attribute with a default or fixed value acquires this value + if the attribute hasn't been specified in an instance document (see + <a href="#A">Appendix A, "Default and Fixed Values"</a>). This + mapping places such optional attributes to the One cardinality + class.</p> + + <p>A member is mapped to a set of public type definitions + (<code>typedef</code>s) and a set of public accessor and modifier + functions. Type definitions have names derived from the member's + name. The accessor and modifier functions have the same name as the + member. For example: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + typedef xml_schema::string member_type; + + const member_type& + member () const; + + ... + +}; + </pre> + + <p>In addition, if a member has a default or fixed value, a static + accessor function is generated that returns this value. For + example:</p> + +<pre class="xml"> +<complexType name="object"> + <attribute name="data" type="string" default="test"/> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + typedef xml_schema::string data_type; + + const data_type& + data () const; + + static const data_type& + data_default_value (); + + ... + +}; + </pre> + + <p>Names and semantics of type definitions for the member as well + as signatures of the accessor and modifier functions depend on + the member's cardinality class and are described in the following + sub-sections. + </p> + + + <h3><a name="2.8.1">2.8.1 Mapping for Members with the One Cardinality Class</a></h3> + + <p>For the One cardinality class, the type definitions consist of + an alias for the member's type with the name created by appending + the <code>_type</code> suffix to the member's name. + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + member and can be used for read-only access. The non-constant + version returns an unrestricted reference to the member and can + be used for read-write access. + </p> + + <p>The first modifier function expects an argument of type reference to + constant of the member's type. It makes a deep copy of its argument. + Except for member's types that are mapped to fundamental C++ types, + the second modifier function is provided that expects an argument + of type automatic pointer (<code>std::unique_ptr</code> or + <code>std::auto_ptr</code>, depending on the C++ standard selected) + to the member's type. It assumes ownership of the pointed to object + and resets the passed automatic pointer. For instance:</p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef xml_schema::string member_type; + + // Accessors. + // + const member_type& + member () const; + + member_type& + member (); + + // Modifiers. + // + void + member (const member_type&); + + void + member (std::[unique|auto]_ptr<member_type>); + ... + +}; + </pre> + + <p>In addition, if requested by specifying the <code>--generate-detach</code> + option and only for members of non-fundamental C++ types, the mapping + provides a detach function that returns an automatic pointer to the + member's type, for example:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + ... + + std::[unique|auto]_ptr<member_type> + detach_member (); + ... + +}; + </pre> + + <p>This function detaches the value from the tree leaving the member + value uninitialized. Accessing such an uninitialized value prior to + re-initializing it results in undefined behavior.</p> + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o) +{ + using xml_schema::string; + + string s (o.member ()); // get + object::member_type& sr (o.member ()); // get + + o.member ("hello"); // set, deep copy + o.member () = "hello"; // set, deep copy + + // C++11 version. + // + std::unique_ptr<string> p (new string ("hello")); + o.member (std::move (p)); // set, assumes ownership + p = o.detach_member (); // detach, member is uninitialized + o.member (std::move (p)); // re-attach + + // C++98 version. + // + std::auto_ptr<string> p (new string ("hello")); + o.member (p); // set, assumes ownership + p = o.detach_member (); // detach, member is uninitialized + o.member (p); // re-attach +} + </pre> + + +<h3><a name="2.8.2">2.8.2 Mapping for Members with the Optional Cardinality Class</a></h3> + + <p>For the Optional cardinality class, the type definitions consist of + an alias for the member's type with the name created by appending + the <code>_type</code> suffix to the member's name and an alias for + the container type with the name created by appending the + <code>_optional</code> suffix to the member's name. + </p> + + <p>Unlike accessor functions for the One cardinality class, accessor + functions for the Optional cardinality class return references to + corresponding containers rather than directly to members. The + accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to + the container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container + and can be used for read-write access. + </p> + + <p>The modifier functions are overloaded for the member's + type and the container type. The first modifier function + expects an argument of type reference to constant of the + member's type. It makes a deep copy of its argument. + Except for member's types that are mapped to fundamental C++ types, + the second modifier function is provided that expects an argument + of type automatic pointer (<code>std::unique_ptr</code> or + <code>std::auto_ptr</code>, depending on the C++ standard selected) + to the member's type. It assumes ownership of the pointed to object + and resets the passed automatic pointer. The last modifier function + expects an argument of type reference to constant of the container + type. It makes a deep copy of its argument. For instance: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string" minOccurs="0"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef xml_schema::string member_type; + typedef optional<member_type> member_optional; + + // Accessors. + // + const member_optional& + member () const; + + member_optional& + member (); + + // Modifiers. + // + void + member (const member_type&); + + void + member (std::[unique|auto]_ptr<member_type>); + + void + member (const member_optional&); + + ... + +}; + </pre> + + + <p>The <code>optional</code> class template is defined in an + implementation-specific namespace and has the following + interface. The <code>[unique|auto]_ptr</code>-based constructor + and modifier function are only available if the template + argument is not a fundamental C++ type. + </p> + + <pre class="c++"> +template <typename X> +class optional +{ +public: + optional (); + + // Makes a deep copy. + // + explicit + optional (const X&); + + // Assumes ownership. + // + explicit + optional (std::[unique|auto]_ptr<X>); + + optional (const optional&); + +public: + optional& + operator= (const X&); + + optional& + operator= (const optional&); + + // Pointer-like interface. + // +public: + const X* + operator-> () const; + + X* + operator-> (); + + const X& + operator* () const; + + X& + operator* (); + + typedef void (optional::*bool_convertible) (); + operator bool_convertible () const; + + // Get/set interface. + // +public: + bool + present () const; + + const X& + get () const; + + X& + get (); + + // Makes a deep copy. + // + void + set (const X&); + + // Assumes ownership. + // + void + set (std::[unique|auto]_ptr<X>); + + // Detach and return the contained value. + // + std::[unique|auto]_ptr<X> + detach (); + + void + reset (); +}; + +template <typename X> +bool +operator== (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator!= (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator< (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator> (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator<= (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator>= (const optional<X>&, const optional<X>&); + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o) +{ + using xml_schema::string; + + if (o.member ().present ()) // test + { + string& s (o.member ().get ()); // get + o.member ("hello"); // set, deep copy + o.member ().set ("hello"); // set, deep copy + o.member ().reset (); // reset + } + + // Same as above but using pointer notation: + // + if (o.member ()) // test + { + string& s (*o.member ()); // get + o.member ("hello"); // set, deep copy + *o.member () = "hello"; // set, deep copy + o.member ().reset (); // reset + } + + // C++11 version. + // + std::unique_ptr<string> p (new string ("hello")); + o.member (std::move (p)); // set, assumes ownership + + p.reset (new string ("hello")); + o.member ().set (std::move (p)); // set, assumes ownership + + p = o.member ().detach (); // detach, member is reset + o.member ().set (std::move (p)); // re-attach + + // C++98 version. + // + std::auto_ptr<string> p (new string ("hello")); + o.member (p); // set, assumes ownership + + p = new string ("hello"); + o.member ().set (p); // set, assumes ownership + + p = o.member ().detach (); // detach, member is reset + o.member ().set (p); // re-attach +} + </pre> + + + <h3><a name="2.8.3">2.8.3 Mapping for Members with the Sequence Cardinality Class</a></h3> + + <p>For the Sequence cardinality class, the type definitions consist of an + alias for the member's type with the name created by appending + the <code>_type</code> suffix to the member's name, an alias of + the container type with the name created by appending the + <code>_sequence</code> suffix to the member's name, an alias of + the iterator type with the name created by appending the + <code>_iterator</code> suffix to the member's name, and an alias + of the constant iterator type with the name created by appending the + <code>_const_iterator</code> suffix to the member's name. + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container and can + be used for read-write access. + </p> + + <p>The modifier function expects an argument of type reference to + constant of the container type. The modifier function + makes a deep copy of its argument. For instance: + </p> + + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string" minOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef xml_schema::string member_type; + typedef sequence<member_type> member_sequence; + typedef member_sequence::iterator member_iterator; + typedef member_sequence::const_iterator member_const_iterator; + + // Accessors. + // + const member_sequence& + member () const; + + member_sequence& + member (); + + // Modifier. + // + void + member (const member_sequence&); + + ... + +}; + </pre> + + <p>The <code>sequence</code> class template is defined in an + implementation-specific namespace. It conforms to the + sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences"). + Practically, this means that you can treat such a sequence + as if it was <code>std::vector</code>. Two notable extensions + to the standard interface that are available only for + sequences of non-fundamental C++ types are the addition of + the overloaded <code>push_back</code> and <code>insert</code> + as well as the <code>detach_back</code> and <code>detach</code> + member functions. The additional <code>push_back</code> and + <code>insert</code> functions accept an automatic pointer + (<code>std::unique_ptr</code> or <code>std::auto_ptr</code>, + depending on the C++ standard selected) to the + element type instead of the constant reference. They assume + ownership of the pointed to object and reset the passed + automatic pointer. The <code>detach_back</code> and + <code>detach</code> functions detach the element + value from the sequence container and, by default, remove + the element from the sequence. These additional functions + have the following signatures:</p> + + <pre class="c++"> +template <typename X> +class sequence +{ +public: + ... + + void + push_back (std::[unique|auto]_ptr<X>) + + iterator + insert (iterator position, std::[unique|auto]_ptr<X>) + + std::[unique|auto]_ptr<X> + detach_back (bool pop = true); + + iterator + detach (iterator position, + std::[unique|auto]_ptr<X>& result, + bool erase = true) + + ... +} + </pre> + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o) +{ + using xml_schema::string; + + object::member_sequence& s (o.member ()); + + // Iteration. + // + for (object::member_iterator i (s.begin ()); i != s.end (); ++i) + { + string& value (*i); + } + + // Modification. + // + s.push_back ("hello"); // deep copy + + // C++11 version. + // + std::unique_ptr<string> p (new string ("hello")); + s.push_back (std::move (p)); // assumes ownership + p = s.detach_back (); // detach and pop + s.push_back (std::move (p)); // re-append + + // C++98 version. + // + std::auto_ptr<string> p (new string ("hello")); + s.push_back (p); // assumes ownership + p = s.detach_back (); // detach and pop + s.push_back (p); // re-append + + // Setting a new container. + // + object::member_sequence n; + n.push_back ("one"); + n.push_back ("two"); + o.member (n); // deep copy +} + </pre> + + <h3><a name="2.8.4">2.8.4 Element Order</a></h3> + + <p>C++/Tree is a "flattening" mapping in a sense that many levels of + nested compositors (<code>choice</code> and <code>sequence</code>), + all potentially with their own cardinalities, are in the end mapped + to a flat set of elements with one of the three cardinality classes + discussed in the previous sections. While this results in a simple + and easy to use API for most types, in certain cases, the order of + elements in the actual XML documents is not preserved once parsed + into the object model. And sometimes such order has + application-specific significance. As an example, consider a schema + that defines a batch of bank transactions:</p> + + <pre class="xml"> +<complexType name="withdraw"> + <sequence> + <element name="account" type="unsignedInt"/> + <element name="amount" type="unsignedInt"/> + </sequence> +</complexType> + +<complexType name="deposit"> + <sequence> + <element name="account" type="unsignedInt"/> + <element name="amount" type="unsignedInt"/> + </sequence> +</complexType> + +<complexType name="batch"> + <choice minOccurs="0" maxOccurs="unbounded"> + <element name="withdraw" type="withdraw"/> + <element name="deposit" type="deposit"/> + </choice> +</complexType> + </pre> + + <p>The batch can contain any number of transactions in any order + but the order of transactions in each actual batch is significant. + For instance, consider what could happen if we reorder the + transactions and apply all the withdrawals before deposits.</p> + + <p>For the <code>batch</code> schema type defined above the default + C++/Tree mapping will produce a C++ class that contains a pair of + sequence containers, one for each of the two elements. While this + will capture the content (transactions), the order of this content + as it appears in XML will be lost. Also, if we try to serialize the + batch we just loaded back to XML, all the withdrawal transactions + will appear before deposits.</p> + + <p>To overcome this limitation of a flattening mapping, C++/Tree + allows us to mark certain XML Schema types, for which content + order is important, as ordered.</p> + + <p>There are several command line options that control which + schema types are treated as ordered. To make an individual + type ordered, we use the <code>--ordered-type</code> option, + for example:</p> + + <pre class="term"> +--ordered-type batch + </pre> + + <p>To automatically treat all the types that are derived from an ordered + type also ordered, we use the <code>--ordered-type-derived</code> + option. This is primarily useful if you would like to iterate + over the complete hierarchy's content using the content order + sequence (discussed below).</p> + + <p>Ordered types are also useful for handling mixed content. To + automatically mark all the types with mixed content as ordered + we use the <code>--ordered-type-mixed</code> option. For more + information on handling mixed content see <a href="#2.13">Section + 2.13, "Mapping for Mixed Content Models"</a>.</p> + + <p>Finally, we can mark all the types in the schema we are + compiling with the <code>--ordered-type-all</code> option. + You should only resort to this option if all the types in + your schema truly suffer from the loss of content + order since, as we will discuss shortly, ordered types + require extra effort to access and, especially, modify. + See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information on + these options.</p> + + <p>Once a type is marked ordered, C++/Tree alters its mapping + in several ways. Firstly, for each local element, element + wildcard (<a href="#2.12.4">Section 2.12.4, "Element Wildcard + Order"</a>), and mixed content text (<a href="#2.13">Section + 2.13, "Mapping for Mixed Content Models"</a>) in this type, a + content id constant is generated. Secondly, an addition sequence + is added to the class that captures the content order. Here + is how the mapping of our <code>batch</code> class changes + once we make it ordered:</p> + + <pre class="c++"> +class batch: public xml_schema::type +{ +public: + // withdraw + // + typedef withdraw withdraw_type; + typedef sequence<withdraw_type> withdraw_sequence; + typedef withdraw_sequence::iterator withdraw_iterator; + typedef withdraw_sequence::const_iterator withdraw_const_iterator; + + static const std::size_t withdraw_id = 1; + + const withdraw_sequence& + withdraw () const; + + withdraw_sequence& + withdraw (); + + void + withdraw (const withdraw_sequence&); + + // deposit + // + typedef deposit deposit_type; + typedef sequence<deposit_type> deposit_sequence; + typedef deposit_sequence::iterator deposit_iterator; + typedef deposit_sequence::const_iterator deposit_const_iterator; + + static const std::size_t deposit_id = 2; + + const deposit_sequence& + deposit () const; + + deposit_sequence& + deposit (); + + void + deposit (const deposit_sequence&); + + // content_order + // + typedef xml_schema::content_order content_order_type; + typedef std::vector<content_order_type> content_order_sequence; + typedef content_order_sequence::iterator content_order_iterator; + typedef content_order_sequence::const_iterator content_order_const_iterator; + + const content_order_sequence& + content_order () const; + + content_order_sequence& + content_order (); + + void + content_order (const content_order_sequence&); + + ... +}; + </pre> + + <p>Notice the <code>withdraw_id</code> and <code>deposit_id</code> + content ids as well as the extra <code>content_order</code> + sequence that does not correspond to any element in the + schema definition. The other changes to the mapping for ordered + types has to do with XML parsing and serialization code. During + parsing the content order is captured in the <code>content_order</code> + sequence while during serialization this sequence is used to + determine the order in which content is serialized. The + <code>content_order</code> sequence is also copied during + copy construction and assigned during copy assignment. It is also + taken into account during comparison.</p> + + <p>The entry type of the <code>content_order</code> sequence is the + <code>xml_schema::content_order</code> type that has the following + interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + struct content_order + { + content_order (std::size_t id, std::size_t index = 0); + + std::size_t id; + std::size_t index; + }; + + bool + operator== (const content_order&, const content_order&); + + bool + operator!= (const content_order&, const content_order&); + + bool + operator< (const content_order&, const content_order&); +} + </pre> + + <p>The <code>content_order</code> sequence describes the order of + content (elements, including wildcards, as well as mixed content + text). Each entry in this sequence consists of the content id + (for example, <code>withdraw_id</code> or <code>deposit_id</code> + in our case) as well as, for elements of the sequence cardinality + class, an index into the corresponding sequence container (the + index is unused for the one and optional cardinality classes). + For example, in our case, if the content id is <code>withdraw_id</code>, + then the index will point into the <code>withdraw</code> element + sequence.</p> + + <p>With all this information we can now examine how to iterate over + transaction in the batch in content order:</p> + + <pre class="c++"> +batch& b = ... + +for (batch::content_order_const_iterator i (b.content_order ().begin ()); + i != b.content_order ().end (); + ++i) +{ + switch (i->id) + { + case batch::withdraw_id: + { + const withdraw& t (b.withdraw ()[i->index]); + cerr << t.account () << " withdraw " << t.amount () << endl; + break; + } + case batch::deposit_id: + { + const deposit& t (b.deposit ()[i->index]); + cerr << t.account () << " deposit " << t.amount () << endl; + break; + } + default: + { + assert (false); // Unknown content id. + } + } +} + </pre> + + <p>If we serialized our batch back to XML, we would also see that the + order of transactions in the output is exactly the same as in the + input rather than all the withdrawals first followed by all the + deposits.</p> + + <p>The most complex aspect of working with ordered types is + modifications. Now we not only need to change the content, + but also remember to update the order information corresponding + to this change. As a first example, we add a deposit transaction + to the batch:</p> + + <pre class="c++"> +using xml_schema::content_order; + +batch::deposit_sequence& d (b.deposit ()); +batch::withdraw_sequence& w (b.withdraw ()); +batch::content_order_sequence& co (b.content_order ()); + +d.push_back (deposit (123456789, 100000)); +co.push_back (content_order (batch::deposit_id, d.size () - 1)); + </pre> + + <p>In the above example we first added the content (deposit + transaction) and then updated the content order information + by adding an entry with <code>deposit_id</code> content + id and the index of the just added deposit transaction.</p> + + <p>Removing the last transaction can be easy if we know which + transaction (deposit or withdrawal) is last:</p> + + <pre class="c++"> +d.pop_back (); +co.pop_back (); + </pre> + + <p>If, however, we do not know which transaction is last, then + things get a bit more complicated:</p> + + <pre class="c++"> +switch (co.back ().id) +{ +case batch::withdraw_id: + { + d.pop_back (); + break; + } +case batch::deposit_id: + { + w.pop_back (); + break; + } +} + +co.pop_back (); + </pre> + + <p>The following example shows how to add a transaction at the + beginning of the batch:</p> + + <pre class="c++"> +w.push_back (withdraw (123456789, 100000)); +co.insert (co.begin (), + content_order (batch::withdraw_id, w.size () - 1)); + </pre> + + <p>Note also that when we merely modify the content of one + of the elements in place, we do not need to update its + order since it doesn't change. For example, here is how + we can change the amount in the first withdrawal:</p> + + <pre class="c++"> +w[0].amount (10000); + </pre> + + <p>For the complete working code shown in this section refer to the + <code>order/element</code> example in the + <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <p>If both the base and derived types are ordered, then the + content order sequence is only added to the base and the content + ids are unique within the whole hierarchy. In this case + the content order sequence for the derived type contains + ordering information for both base and derived content.</p> + + <p>In some applications we may need to perform more complex + content processing. For example, in our case, we may need + to remove all the withdrawal transactions. The default + container, <code>std::vector</code>, is not particularly + suitable for such operations. What may be required by + some applications is a multi-index container that not + only allows us to iterate in content order similar to + <code>std::vector</code> but also search by the content + id as well as the content id and index pair.</p> + + <p>While C++/Tree does not provide this functionality by + default, it allows us to specify a custom container + type for content order with the <code>--order-container</code> + command line option. The only requirement from the + generated code side for such a container is to provide + the <code>vector</code>-like <code>push_back()</code>, + <code>size()</code>, and const iteration interfaces.</p> + + <p>As an example, here is how we can use the Boost Multi-Index + container for content order. First we create the + <code>content-order-container.hxx</code> header with the + following definition:</p> + + <pre class="c++"> +#ifndef CONTENT_ORDER_CONTAINER +#define CONTENT_ORDER_CONTAINER + +#include <cstddef> // std::size_t + +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/multi_index/identity.hpp> +#include <boost/multi_index/ordered_index.hpp> +#include <boost/multi_index/random_access_index.hpp> + +struct by_id {}; +struct by_id_index {}; + +template <typename T> +using content_order_container = + boost::multi_index::multi_index_container< + T, + boost::multi_index::indexed_by< + boost::multi_index::random_access<>, + boost::multi_index::ordered_unique< + boost::multi_index::tag<by_id_index>, + boost::multi_index::identity<T> + >, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag<by_id>, + boost::multi_index::member<T, std::size_t, &T::id> + > + > + >; + +#endif + </pre> + + <p>Next we add the following two XSD compiler options to include + this header into every generated header file and to use the + custom container type (see the XSD compiler command line manual + for more information on shell quoting for the first option):</p> + + <pre class="term"> +--hxx-prologue '#include "content-order-container.hxx"' +--order-container content_order_container + </pre> + + <p>With these changes we can now use the multi-index functionality, + for example, to search for a specific content id:</p> + + <pre class="c++"> +typedef batch::content_order_sequence::index<by_id>::type id_set; +typedef id_set::iterator id_iterator; + +const id_set& ids (b.content_order ().get<by_id> ()); + +std::pair<id_iterator, id_iterator> r ( + ids.equal_range (std::size_t (batch::deposit_id)); + +for (id_iterator i (r.first); i != r.second; ++i) +{ + const deposit& t (b.deposit ()[i->index]); + cerr << t.account () << " deposit " << t.amount () << endl; +} + </pre> + + <h2><a name="2.9">2.9 Mapping for Global Elements</a></h2> + + <p>An XML Schema element definition is called global if it appears + directly under the <code>schema</code> element. + A global element is a valid root of an instance document. By + default, a global element is mapped to a set of overloaded + parsing and, optionally, serialization functions with the + same name as the element. It is also possible to generate types + for root elements instead of parsing and serialization functions. + This is primarily useful to distinguish object models with the + same root type but with different root elements. See + <a href="#2.9.1">Section 2.9.1, "Element Types"</a> for details. + It is also possible to request the generation of an element map + which allows uniform parsing and serialization of multiple root + elements. See <a href="#2.9.2">Section 2.9.2, "Element Map"</a> + for details. + </p> + + <p>The parsing functions read XML instance documents and return + corresponding object models as an automatic pointer + (<code>std::unique_ptr</code> or <code>std::auto_ptr</code>, + depending on the C++ standard selected). Their signatures + have the following pattern (<code>type</code> denotes + element's type and <code>name</code> denotes element's + name): + </p> + + <pre class="c++"> +std::[unique|auto]_ptr<type> +name (....); + </pre> + + <p>The process of parsing, including the exact signatures of the parsing + functions, is the subject of <a href="#3">Chapter 3, "Parsing"</a>. + </p> + + <p>The serialization functions write object models back to XML instance + documents. Their signatures have the following pattern: + </p> + + <pre class="c++"> +void +name (<stream type>&, const type&, ....); + </pre> + + <p>The process of serialization, including the exact signatures of the + serialization functions, is the subject of <a href="#4">Chapter 4, + "Serialization"</a>. + </p> + + + <h3><a name="2.9.1">2.9.1 Element Types</a></h3> + + <p>The generation of element types is requested with the + <code>--generate-element-type</code> option. With this option + each global element is mapped to a C++ class with the + same name as the element. Such a class is derived from + <code>xml_schema::element_type</code> and contains the same set + of type definitions, constructors, and member function as would a + type containing a single element with the One cardinality class + named <code>"value"</code>. In addition, the element type also + contains a set of member functions for accessing the element + name and namespace as well as its value in a uniform manner. + For example:</p> + + <pre class="xml"> +<complexType name="type"> + <sequence> + ... + </sequence> +</complexType> + +<element name="root" type="type"/> + </pre> + +<p>is mapped to:</p> + + <pre class="c++"> +class type +{ + ... +}; + +class root: public xml_schema::element_type +{ +public: + // Element value. + // + typedef type value_type; + + const value_type& + value () const; + + value_type& + value (); + + void + value (const value_type&); + + void + value (std::[unique|auto]_ptr<value_type>); + + // Constructors. + // + root (const value_type&); + + root (std::[unique|auto]_ptr<value_type>); + + root (const xercesc::DOMElement&, xml_schema::flags = 0); + + root (const root&, xml_schema::flags = 0); + + virtual root* + _clone (xml_schema::flags = 0) const; + + // Element name and namespace. + // + static const std::string& + name (); + + static const std::string& + namespace_ (); + + virtual const std::string& + _name () const; + + virtual const std::string& + _namespace () const; + + // Element value as xml_schema::type. + // + virtual const xml_schema::type* + _value () const; + + virtual xml_schema::type* + _value (); +}; + +void +operator<< (xercesc::DOMElement&, const root&); + </pre> + + <p>The <code>xml_schema::element_type</code> class is a common + base type for all element types and is defined as follows:</p> + + <pre class="c++"> +namespace xml_schema +{ + class element_type + { + public: + virtual + ~element_type (); + + virtual element_type* + _clone (flags f = 0) const = 0; + + virtual const std::basic_string<C>& + _name () const = 0; + + virtual const std::basic_string<C>& + _namespace () const = 0; + + virtual xml_schema::type* + _value () = 0; + + virtual const xml_schema::type* + _value () const = 0; + }; +} + </pre> + + <p>The <code>_value()</code> member function returns a pointer to + the element value or 0 if the element is of a fundamental C++ + type and therefore is not derived from <code>xml_schema::type</code>. + </p> + + <p>Unlike parsing and serialization functions, element types + are only capable of parsing and serializing from/to a + <code>DOMElement</code> object. This means that the application + will need to perform its own XML-to-DOM parsing and DOM-to-XML + serialization. The following section describes a mechanism + provided by the mapping to uniformly parse and serialize + multiple root elements.</p> + + + <h3><a name="2.9.2">2.9.2 Element Map</a></h3> + + <p>When element types are generated for root elements it is also + possible to request the generation of an element map with the + <code>--generate-element-map</code> option. The element map + allows uniform parsing and serialization of multiple root + elements via the common <code>xml_schema::element_type</code> + base type. The <code>xml_schema::element_map</code> class is + defined as follows:</p> + + <pre class="c++"> +namespace xml_schema +{ + class element_map + { + public: + static std::[unique|auto]_ptr<xml_schema::element_type> + parse (const xercesc::DOMElement&, flags = 0); + + static void + serialize (xercesc::DOMElement&, const element_type&); + }; +} + </pre> + + <p>The <code>parse()</code> function creates the corresponding + element type object based on the element name and namespace + and returns it as an automatic pointer (<code>std::unique_ptr</code> + or <code>std::auto_ptr</code>, depending on the C++ standard + selected) to <code>xml_schema::element_type</code>. + The <code>serialize()</code> function serializes the passed element + object to <code>DOMElement</code>. Note that in case of + <code>serialize()</code>, the <code>DOMElement</code> object + should have the correct name and namespace. If no element type is + available for an element, both functions throw the + <code>xml_schema::no_element_info</code> exception:</p> + + <pre class="c++"> +struct no_element_info: virtual exception +{ + no_element_info (const std::basic_string<C>& element_name, + const std::basic_string<C>& element_namespace); + + const std::basic_string<C>& + element_name () const; + + const std::basic_string<C>& + element_namespace () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The application can discover the actual type of the element + object returned by <code>parse()</code> either using + <code>dynamic_cast</code> or by comparing element names and + namespaces. The following code fragments illustrate how the + element map can be used:</p> + + <pre class="c++"> +// Parsing. +// +DOMElement& e = ... // Parse XML to DOM. + +unique_ptr<xml_schema::element_type> r ( + xml_schema::element_map::parse (e)); + +if (root1 r1 = dynamic_cast<root1*> (r.get ())) +{ + ... +} +else if (r->_name == root2::name () && + r->_namespace () == root2::namespace_ ()) +{ + root2& r2 (static_cast<root2&> (*r)); + + ... +} + </pre> + + <pre class="c++"> +// Serialization. +// +xml_schema::element_type& r = ... + +string name (r._name ()); +string ns (r._namespace ()); + +DOMDocument& doc = ... // Create a new DOMDocument with name and ns. +DOMElement& e (*doc->getDocumentElement ()); + +xml_schema::element_map::serialize (e, r); + +// Serialize DOMDocument to XML. + </pre> + + <!-- --> + + <h2><a name="2.10">2.10 Mapping for Global Attributes</a></h2> + + <p>An XML Schema attribute definition is called global if it appears + directly under the <code>schema</code> element. A global + attribute does not have any mapping. + </p> + + <!-- + When it is referenced from + a local attribute definition (using the <code>ref</code> attribute) + it is treated as a local attribute (see Section 2.8, "Mapping for + Local Elements and Attributes"). + --> + + <h2><a name="2.11">2.11 Mapping for <code>xsi:type</code> and Substitution + Groups</a></h2> + + <p>The mapping provides optional support for the XML Schema polymorphism + features (<code>xsi:type</code> and substitution groups) which can + be requested with the <code>--generate-polymorphic</code> option. + When used, the dynamic type of a member may be different from + its static type. Consider the following schema definition and + instance document: + </p> + + <pre class="xml"> +<!-- test.xsd --> +<schema> + <complexType name="base"> + <attribute name="text" type="string"/> + </complexType> + + <complexType name="derived"> + <complexContent> + <extension base="base"> + <attribute name="extra-text" type="string"/> + </extension> + </complexContent> + </complexType> + + <complexType name="root_type"> + <sequence> + <element name="item" type="base" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <element name="root" type="root_type"/> +</schema> + +<!-- test.xml --> +<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <item text="hello"/> + <item text="hello" extra-text="world" xsi:type="derived"/> +</root> + </pre> + + <p>In the resulting object model, the container for + the <code>root::item</code> member will have two elements: + the first element's type will be <code>base</code> while + the second element's (dynamic) type will be + <code>derived</code>. This can be discovered using the + <code>dynamic_cast</code> operator as shown in the following + example: + </p> + + <pre class="c++"> +void +f (root& r) +{ + for (root::item_const_iterator i (r.item ().begin ()); + i != r.item ().end () + ++i) + { + if (derived* d = dynamic_cast<derived*> (&(*i))) + { + // derived + } + else + { + // base + } + } +} + </pre> + + <p>The <code>_clone</code> virtual function should be used instead of + copy constructors to make copies of members that might use + polymorphism: + </p> + + <pre class="c++"> +void +f (root& r) +{ + for (root::item_const_iterator i (r.item ().begin ()); + i != r.item ().end () + ++i) + { + std::unique_ptr<base> c (i->_clone ()); + } +} + </pre> + + <p>The mapping 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 mapping + 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>You can also indicate that all types should be treated as polymorphic + with the <code>--polymorphic-type-all</code>. However, this may result + in slower generated code with a greater footprint.</p> + + + <!-- Mapping for any and anyAttribute --> + + + <h2><a name="2.12">2.12 Mapping for <code>any</code> and <code>anyAttribute</code></a></h2> + + <p>For the XML Schema <code>any</code> and <code>anyAttribute</code> + wildcards an optional mapping can be requested with the + <code>--generate-wildcard</code> option. The mapping represents + the content matched by wildcards as DOM fragments. Because the + DOM API is used to access such content, the Xerces-C++ runtime + should be initialized by the application prior to parsing and + should remain initialized for the lifetime of objects with + the wildcard content. For more information on the Xerces-C++ + runtime initialization see <a href="#3.1">Section 3.1, + "Initializing the Xerces-C++ Runtime"</a>. + </p> + + <p>The mapping for <code>any</code> is similar to the mapping for + local elements (see <a href="#2.8">Section 2.8, "Mapping for Local + Elements and Attributes"</a>) except that the type used in the + wildcard mapping is <code>xercesc::DOMElement</code>. As with local + elements, the mapping divides all possible cardinality combinations + into three cardinality classes: <i>one</i>, <i>optional</i>, and + <i>sequence</i>. + </p> + + <p>The mapping for <code>anyAttribute</code> represents the attributes + matched by this wildcard as a set of <code>xercesc::DOMAttr</code> + objects with a key being the attribute's name and namespace.</p> + + <p>Similar to local elements and attributes, the <code>any</code> and + <code>anyAttribute</code> wildcards are mapped to a set of public type + definitions (typedefs) and a set of public accessor and modifier + functions. Type definitions have names derived from <code>"any"</code> + for the <code>any</code> wildcard and <code>"any_attribute"</code> + for the <code>anyAttribute</code> wildcard. The accessor and modifier + functions are named <code>"any"</code> for the <code>any</code> wildcard + and <code>"any_attribute"</code> for the <code>anyAttribute</code> + wildcard. Subsequent wildcards in the same type have escaped names + such as <code>"any1"</code> or <code>"any_attribute1"</code>. + </p> + + <p>Because Xerces-C++ DOM nodes always belong to a <code>DOMDocument</code>, + each type with a wildcard has an associated <code>DOMDocument</code> + object. The reference to this object can be obtained using the accessor + function called <code>dom_document</code>. The access to the document + object from the application code may be necessary to create or modify + the wildcard content. For example: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other"/> + </sequence> + <anyAttribute namespace="##other"/> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // any + // + const xercesc::DOMElement& + any () const; + + void + any (const xercesc::DOMElement&); + + ... + + // any_attribute + // + typedef attribute_set any_attribute_set; + typedef any_attribute_set::iterator any_attribute_iterator; + typedef any_attribute_set::const_iterator any_attribute_const_iterator; + + const any_attribute_set& + any_attribute () const; + + any_attribute_set& + any_attribute (); + + ... + + // DOMDocument object for wildcard content. + // + const xercesc::DOMDocument& + dom_document () const; + + xercesc::DOMDocument& + dom_document (); + + ... +}; + </pre> + + + <p>Names and semantics of type definitions for the wildcards as well + as signatures of the accessor and modifier functions depend on the + wildcard type as well as the cardinality class for the <code>any</code> + wildcard. They are described in the following sub-sections. + </p> + + + <h3><a name="2.12.1">2.12.1 Mapping for <code>any</code> with the One Cardinality Class</a></h3> + + <p>For <code>any</code> with the One cardinality class, + there are no type definitions. The accessor functions come in + constant and non-constant versions. The constant accessor function + returns a constant reference to <code>xercesc::DOMElement</code> and + can be used for read-only access. The non-constant version returns + an unrestricted reference to <code>xercesc::DOMElement</code> and can + be used for read-write access. + </p> + + <p>The first modifier function expects an argument of type reference + to constant <code>xercesc::DOMElement</code> and makes a deep copy + of its argument. The second modifier function expects an argument of + type pointer to <code>xercesc::DOMElement</code>. This modifier + function assumes ownership of its argument and expects the element + object to be created using the DOM document associated with this + instance. For example: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Accessors. + // + const xercesc::DOMElement& + any () const; + + xercesc::DOMElement& + any (); + + // Modifiers. + // + void + any (const xercesc::DOMElement&); + + void + any (xercesc::DOMElement*); + + ... + +}; + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMElement& e) +{ + using namespace xercesc; + + DOMElement& e1 (o.any ()); // get + o.any (e) // set, deep copy + DOMDocument& doc (o.dom_document ()); + o.any (doc.createElement (...)); // set, assumes ownership +} + </pre> + + <h3><a name="2.12.2">2.12.2 Mapping for <code>any</code> with the Optional Cardinality Class</a></h3> + + <p>For <code>any</code> with the Optional cardinality class, the type + definitions consist of an alias for the container type with name + <code>any_optional</code> (or <code>any1_optional</code>, etc., for + subsequent wildcards in the type definition). + </p> + + <p>Unlike accessor functions for the One cardinality class, accessor + functions for the Optional cardinality class return references to + corresponding containers rather than directly to <code>DOMElement</code>. + The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to + the container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container + and can be used for read-write access. + </p> + + <p>The modifier functions are overloaded for <code>xercesc::DOMElement</code> + and the container type. The first modifier function expects an argument of + type reference to constant <code>xercesc::DOMElement</code> and + makes a deep copy of its argument. The second modifier function + expects an argument of type pointer to <code>xercesc::DOMElement</code>. + This modifier function assumes ownership of its argument and expects + the element object to be created using the DOM document associated + with this instance. The third modifier function expects an argument + of type reference to constant of the container type and makes a + deep copy of its argument. For instance: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other" minOccurs="0"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef element_optional any_optional; + + // Accessors. + // + const any_optional& + any () const; + + any_optional& + any (); + + // Modifiers. + // + void + any (const xercesc::DOMElement&); + + void + any (xercesc::DOMElement*); + + void + any (const any_optional&); + + ... + +}; + </pre> + + + <p>The <code>element_optional</code> container is a + specialization of the <code>optional</code> class template described + in <a href="#2.8.2">Section 2.8.2, "Mapping for Members with the Optional + Cardinality Class"</a>. Its interface is presented below: + </p> + + <pre class="c++"> +class element_optional +{ +public: + explicit + element_optional (xercesc::DOMDocument&); + + // Makes a deep copy. + // + element_optional (const xercesc::DOMElement&, xercesc::DOMDocument&); + + // Assumes ownership. + // + element_optional (xercesc::DOMElement*, xercesc::DOMDocument&); + + element_optional (const element_optional&, xercesc::DOMDocument&); + +public: + element_optional& + operator= (const xercesc::DOMElement&); + + element_optional& + operator= (const element_optional&); + + // Pointer-like interface. + // +public: + const xercesc::DOMElement* + operator-> () const; + + xercesc::DOMElement* + operator-> (); + + const xercesc::DOMElement& + operator* () const; + + xercesc::DOMElement& + operator* (); + + typedef void (element_optional::*bool_convertible) (); + operator bool_convertible () const; + + // Get/set interface. + // +public: + bool + present () const; + + const xercesc::DOMElement& + get () const; + + xercesc::DOMElement& + get (); + + // Makes a deep copy. + // + void + set (const xercesc::DOMElement&); + + // Assumes ownership. + // + void + set (xercesc::DOMElement*); + + void + reset (); +}; + +bool +operator== (const element_optional&, const element_optional&); + +bool +operator!= (const element_optional&, const element_optional&); + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMElement& e) +{ + using namespace xercesc; + + DOMDocument& doc (o.dom_document ()); + + if (o.any ().present ()) // test + { + DOMElement& e1 (o.any ().get ()); // get + o.any ().set (e); // set, deep copy + o.any ().set (doc.createElement (...)); // set, assumes ownership + o.any ().reset (); // reset + } + + // Same as above but using pointer notation: + // + if (o.member ()) // test + { + DOMElement& e1 (*o.any ()); // get + o.any (e); // set, deep copy + o.any (doc.createElement (...)); // set, assumes ownership + o.any ().reset (); // reset + } +} + </pre> + + + + <h3><a name="2.12.3">2.12.3 Mapping for <code>any</code> with the Sequence Cardinality Class</a></h3> + + <p>For <code>any</code> with the Sequence cardinality class, the type + definitions consist of an alias of the container type with name + <code>any_sequence</code> (or <code>any1_sequence</code>, etc., for + subsequent wildcards in the type definition), an alias of the iterator + type with name <code>any_iterator</code> (or <code>any1_iterator</code>, + etc., for subsequent wildcards in the type definition), and an alias + of the constant iterator type with name <code>any_const_iterator</code> + (or <code>any1_const_iterator</code>, etc., for subsequent wildcards + in the type definition). + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container and can + be used for read-write access. + </p> + + <p>The modifier function expects an argument of type reference to + constant of the container type. The modifier function makes + a deep copy of its argument. For instance: + </p> + + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other" minOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef element_sequence any_sequence; + typedef any_sequence::iterator any_iterator; + typedef any_sequence::const_iterator any_const_iterator; + + // Accessors. + // + const any_sequence& + any () const; + + any_sequence& + any (); + + // Modifier. + // + void + any (const any_sequence&); + + ... + +}; + </pre> + + <p>The <code>element_sequence</code> container is a + specialization of the <code>sequence</code> class template described + in <a href="#2.8.3">Section 2.8.3, "Mapping for Members with the + Sequence Cardinality Class"</a>. Its interface is similar to + the sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences") and is + presented below: + </p> + + <pre class="c++"> +class element_sequence +{ +public: + typedef xercesc::DOMElement value_type; + typedef xercesc::DOMElement* pointer; + typedef const xercesc::DOMElement* const_pointer; + typedef xercesc::DOMElement& reference; + typedef const xercesc::DOMElement& const_reference; + + typedef <implementation-defined> iterator; + typedef <implementation-defined> const_iterator; + typedef <implementation-defined> reverse_iterator; + typedef <implementation-defined> const_reverse_iterator; + + typedef <implementation-defined> size_type; + typedef <implementation-defined> difference_type; + typedef <implementation-defined> allocator_type; + +public: + explicit + element_sequence (xercesc::DOMDocument&); + + // DOMElement cannot be default-constructed. + // + // explicit + // element_sequence (size_type n); + + element_sequence (size_type n, + const xercesc::DOMElement&, + xercesc::DOMDocument&); + + template <typename I> + element_sequence (const I& begin, + const I& end, + xercesc::DOMDocument&); + + element_sequence (const element_sequence&, xercesc::DOMDocument&); + + element_sequence& + operator= (const element_sequence&); + +public: + void + assign (size_type n, const xercesc::DOMElement&); + + template <typename I> + void + assign (const I& begin, const I& end); + +public: + // This version of resize can only be used to shrink the + // sequence because DOMElement cannot be default-constructed. + // + void + resize (size_type); + + void + resize (size_type, const xercesc::DOMElement&); + +public: + size_type + size () const; + + size_type + max_size () const; + + size_type + capacity () const; + + bool + empty () const; + + void + reserve (size_type); + + void + clear (); + +public: + const_iterator + begin () const; + + const_iterator + end () const; + + iterator + begin (); + + iterator + end (); + + const_reverse_iterator + rbegin () const; + + const_reverse_iterator + rend () const + + reverse_iterator + rbegin (); + + reverse_iterator + rend (); + +public: + xercesc::DOMElement& + operator[] (size_type); + + const xercesc::DOMElement& + operator[] (size_type) const; + + xercesc::DOMElement& + at (size_type); + + const xercesc::DOMElement& + at (size_type) const; + + xercesc::DOMElement& + front (); + + const xercesc::DOMElement& + front () const; + + xercesc::DOMElement& + back (); + + const xercesc::DOMElement& + back () const; + +public: + // Makes a deep copy. + // + void + push_back (const xercesc::DOMElement&); + + // Assumes ownership. + // + void + push_back (xercesc::DOMElement*); + + void + pop_back (); + + // Makes a deep copy. + // + iterator + insert (iterator position, const xercesc::DOMElement&); + + // Assumes ownership. + // + iterator + insert (iterator position, xercesc::DOMElement*); + + void + insert (iterator position, size_type n, const xercesc::DOMElement&); + + template <typename I> + void + insert (iterator position, const I& begin, const I& end); + + iterator + erase (iterator position); + + iterator + erase (iterator begin, iterator end); + +public: + // Note that the DOMDocument object of the two sequences being + // swapped should be the same. + // + void + swap (sequence& x); +}; + +inline bool +operator== (const element_sequence&, const element_sequence&); + +inline bool +operator!= (const element_sequence&, const element_sequence&); + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMElement& e) +{ + using namespace xercesc; + + object::any_sequence& s (o.any ()); + + // Iteration. + // + for (object::any_iterator i (s.begin ()); i != s.end (); ++i) + { + DOMElement& e (*i); + } + + // Modification. + // + s.push_back (e); // deep copy + DOMDocument& doc (o.dom_document ()); + s.push_back (doc.createElement (...)); // assumes ownership +} + </pre> + + <h3><a name="2.12.4">2.12.4 Element Wildcard Order</a></h3> + + <p>Similar to elements, element wildcards in ordered types + (<a href="#2.8.4">Section 2.8.4, "Element Order"</a>) are assigned + content ids and are included in the content order sequence. + Continuing with the bank transactions example started in Section + 2.8.4, we can extend the batch by allowing custom transactions:</p> + + <pre class="xml"> +<complexType name="batch"> + <choice minOccurs="0" maxOccurs="unbounded"> + <element name="withdraw" type="withdraw"/> + <element name="deposit" type="deposit"/> + <any namespace="##other" processContents="lax"/> + </choice> +</complexType> + </pre> + + <p>This will lead to the following changes in the generated + <code>batch</code> C++ class:</p> + + <pre class="c++"> +class batch: public xml_schema::type +{ +public: + ... + + // any + // + typedef element_sequence any_sequence; + typedef any_sequence::iterator any_iterator; + typedef any_sequence::const_iterator any_const_iterator; + + static const std::size_t any_id = 3UL; + + const any_sequence& + any () const; + + any_sequence& + any (); + + void + any (const any_sequence&); + + ... +}; + </pre> + + <p>With this change we also need to update the iteration code to handle + the new content id:</p> + + <pre class="c++"> +for (batch::content_order_const_iterator i (b.content_order ().begin ()); + i != b.content_order ().end (); + ++i) +{ + switch (i->id) + { + ... + + case batch::any_id: + { + const DOMElement& e (b.any ()[i->index]); + ... + break; + } + + ... + } +} + </pre> + + <p>For the complete working code that shows the use of wildcards in + ordered types refer to the <code>order/element</code> example in + the <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <h3><a name="2.12.5">2.12.5 Mapping for <code>anyAttribute</code></a></h3> + + <p>For <code>anyAttribute</code> the type definitions consist of an alias + of the container type with name <code>any_attribute_set</code> + (or <code>any1_attribute_set</code>, etc., for subsequent wildcards + in the type definition), an alias of the iterator type with name + <code>any_attribute_iterator</code> (or <code>any1_attribute_iterator</code>, + etc., for subsequent wildcards in the type definition), and an alias + of the constant iterator type with name <code>any_attribute_const_iterator</code> + (or <code>any1_attribute_const_iterator</code>, etc., for subsequent + wildcards in the type definition). + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container and can + be used for read-write access. + </p> + + <p>The modifier function expects an argument of type reference to + constant of the container type. The modifier function makes + a deep copy of its argument. For instance: + </p> + + + <pre class="xml"> +<complexType name="object"> + <sequence> + ... + </sequence> + <anyAttribute namespace="##other"/> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef attribute_set any_attribute_set; + typedef any_attribute_set::iterator any_attribute_iterator; + typedef any_attribute_set::const_iterator any_attribute_const_iterator; + + // Accessors. + // + const any_attribute_set& + any_attribute () const; + + any_attribute_set& + any_attribute (); + + // Modifier. + // + void + any_attribute (const any_attribute_set&); + + ... + +}; + </pre> + + <p>The <code>attribute_set</code> class is an associative container + similar to the <code>std::set</code> class template as defined by + the ISO/ANSI Standard for C++ (ISO/IEC 14882:1998, Section 23.3.3, + "Class template set") with the key being the attribute's name + and namespace. Unlike <code>std::set</code>, <code>attribute_set</code> + allows searching using names and namespaces instead of + <code>xercesc::DOMAttr</code> objects. It is defined in an + implementation-specific namespace and its interface is presented + below: + </p> + + <pre class="c++"> +class attribute_set +{ +public: + typedef xercesc::DOMAttr key_type; + typedef xercesc::DOMAttr value_type; + typedef xercesc::DOMAttr* pointer; + typedef const xercesc::DOMAttr* const_pointer; + typedef xercesc::DOMAttr& reference; + typedef const xercesc::DOMAttr& const_reference; + + typedef <implementation-defined> iterator; + typedef <implementation-defined> const_iterator; + typedef <implementation-defined> reverse_iterator; + typedef <implementation-defined> const_reverse_iterator; + + typedef <implementation-defined> size_type; + typedef <implementation-defined> difference_type; + typedef <implementation-defined> allocator_type; + +public: + attribute_set (xercesc::DOMDocument&); + + template <typename I> + attribute_set (const I& begin, const I& end, xercesc::DOMDocument&); + + attribute_set (const attribute_set&, xercesc::DOMDocument&); + + attribute_set& + operator= (const attribute_set&); + +public: + const_iterator + begin () const; + + const_iterator + end () const; + + iterator + begin (); + + iterator + end (); + + const_reverse_iterator + rbegin () const; + + const_reverse_iterator + rend () const; + + reverse_iterator + rbegin (); + + reverse_iterator + rend (); + +public: + size_type + size () const; + + size_type + max_size () const; + + bool + empty () const; + + void + clear (); + +public: + // Makes a deep copy. + // + std::pair<iterator, bool> + insert (const xercesc::DOMAttr&); + + // Assumes ownership. + // + std::pair<iterator, bool> + insert (xercesc::DOMAttr*); + + // Makes a deep copy. + // + iterator + insert (iterator position, const xercesc::DOMAttr&); + + // Assumes ownership. + // + iterator + insert (iterator position, xercesc::DOMAttr*); + + template <typename I> + void + insert (const I& begin, const I& end); + +public: + void + erase (iterator position); + + size_type + erase (const std::basic_string<C>& name); + + size_type + erase (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name); + + size_type + erase (const XMLCh* name); + + size_type + erase (const XMLCh* namespace_, const XMLCh* name); + + void + erase (iterator begin, iterator end); + +public: + size_type + count (const std::basic_string<C>& name) const; + + size_type + count (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name) const; + + size_type + count (const XMLCh* name) const; + + size_type + count (const XMLCh* namespace_, const XMLCh* name) const; + + iterator + find (const std::basic_string<C>& name); + + iterator + find (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name); + + iterator + find (const XMLCh* name); + + iterator + find (const XMLCh* namespace_, const XMLCh* name); + + const_iterator + find (const std::basic_string<C>& name) const; + + const_iterator + find (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name) const; + + const_iterator + find (const XMLCh* name) const; + + const_iterator + find (const XMLCh* namespace_, const XMLCh* name) const; + +public: + // Note that the DOMDocument object of the two sets being + // swapped should be the same. + // + void + swap (attribute_set&); +}; + +bool +operator== (const attribute_set&, const attribute_set&); + +bool +operator!= (const attribute_set&, const attribute_set&); + </pre> + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMAttr& a) +{ + using namespace xercesc; + + object::any_attribute_set& s (o.any_attribute ()); + + // Iteration. + // + for (object::any_attribute_iterator i (s.begin ()); i != s.end (); ++i) + { + DOMAttr& a (*i); + } + + // Modification. + // + s.insert (a); // deep copy + DOMDocument& doc (o.dom_document ()); + s.insert (doc.createAttribute (...)); // assumes ownership + + // Searching. + // + object::any_attribute_iterator i (s.find ("name")); + i = s.find ("http://www.w3.org/XML/1998/namespace", "lang"); +} + </pre> + + <!-- Mapping for Mixed Content Models --> + + <h2><a name="2.13">2.13 Mapping for Mixed Content Models</a></h2> + + <p>For XML Schema types with mixed content models C++/Tree provides + mapping support only if the type is marked as ordered + (<a href="#2.8.4">Section 2.8.4, "Element Order"</a>). Use the + <code>--ordered-type-mixed</code> XSD compiler option to + automatically mark all types with mixed content as ordered.</p> + + <p>For an ordered type with mixed content, C++/Tree adds an extra + text content sequence that is used to store the text fragments. + This text content sequence is also assigned the content id and + its entries are included in the content order sequence, just + like elements. As a result, it is possible to capture the order + between elements and text fragments.</p> + + <p>As an example, consider the following schema that describes text + with embedded links:</p> + + <pre class="xml"> +<complexType name="anchor"> + <simpleContent> + <extension base="string"> + <attribute name="href" type="anyURI" use="required"/> + </extension> + </simpleContent> +</complexType> + +<complexType name="text" mixed="true"> + <sequence> + <element name="a" type="anchor" minOccurs="0" maxOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>The generated <code>text</code> C++ class will provide the following + API (assuming it is marked as ordered):</p> + + <pre class="c++"> +class text: public xml_schema::type +{ +public: + // a + // + typedef anchor a_type; + typedef sequence<a_type> a_sequence; + typedef a_sequence::iterator a_iterator; + typedef a_sequence::const_iterator a_const_iterator; + + static const std::size_t a_id = 1UL; + + const a_sequence& + a () const; + + a_sequence& + a (); + + void + a (const a_sequence&); + + // text_content + // + typedef xml_schema::string text_content_type; + typedef sequence<text_content_type> text_content_sequence; + typedef text_content_sequence::iterator text_content_iterator; + typedef text_content_sequence::const_iterator text_content_const_iterator; + + static const std::size_t text_content_id = 2UL; + + const text_content_sequence& + text_content () const; + + text_content_sequence& + text_content (); + + void + text_content (const text_content_sequence&); + + // content_order + // + typedef xml_schema::content_order content_order_type; + typedef std::vector<content_order_type> content_order_sequence; + typedef content_order_sequence::iterator content_order_iterator; + typedef content_order_sequence::const_iterator content_order_const_iterator; + + const content_order_sequence& + content_order () const; + + content_order_sequence& + content_order (); + + void + content_order (const content_order_sequence&); + + ... +}; + </pre> + + <p>Given this interface we can iterate over both link elements + and text in content order. The following code fragment converts + our format to plain text with references.</p> + + <pre class="c++"> +const text& t = ... + +for (text::content_order_const_iterator i (t.content_order ().begin ()); + i != t.content_order ().end (); + ++i) +{ + switch (i->id) + { + case text::a_id: + { + const anchor& a (t.a ()[i->index]); + cerr << a << "[" << a.href () << "]"; + break; + } + case text::text_content_id: + { + const xml_schema::string& s (t.text_content ()[i->index]); + cerr << s; + break; + } + default: + { + assert (false); // Unknown content id. + } + } +} + </pre> + + <p>For the complete working code that shows the use of mixed content + in ordered types refer to the <code>order/mixed</code> example in + the <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <!-- Parsing --> + + + <h1><a name="3">3 Parsing</a></h1> + + <p>This chapter covers various aspects of parsing XML instance + documents in order to obtain corresponding tree-like object + model. + </p> + + <p>Each global XML Schema element in the form:</p> + + <pre class="xml"> +<element name="name" type="type"/> + </pre> + + <p>is mapped to 14 overloaded C++ functions in the form:</p> + + <pre class="c++"> +// Read from a URI or a local file. +// + +std::[unique|auto]_ptr<type> +name (const std::basic_string<C>& uri, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (const std::basic_string<C>& uri, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (const std::basic_string<C>& uri, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +// Read from std::istream. +// + +std::[unique|auto]_ptr<type> +name (std::istream&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +std::[unique|auto]_ptr<type> +name (std::istream&, + const std::basic_string<C>& id, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + const std::basic_string<C>& id, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + const std::basic_string<C>& id, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +// Read from InputSource. +// + +std::[unique|auto]_ptr<type> +name (xercesc::InputSource&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (xercesc::InputSource&, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (xercesc::InputSource&, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +// Read from DOM. +// + +std::[unique|auto]_ptr<type> +name (const xercesc::DOMDocument&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (xml_schema::dom::[unique|auto]_ptr<xercesc::DOMDocument>, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + </pre> + + <p>You can choose between reading an XML instance from a local file, + URI, <code>std::istream</code>, <code>xercesc::InputSource</code>, + or a pre-parsed DOM instance in the form of + <code>xercesc::DOMDocument</code>. All the parsing functions + return a dynamically allocated object model as either + <code>std::unique_ptr</code> or <code>std::auto_ptr</code>, + depending on the C++ standard selected. Each of these parsing + functions is discussed in more detail in the following sections. + </p> + + <h2><a name="3.1">3.1 Initializing the Xerces-C++ Runtime</a></h2> + + <p>Some parsing functions expect you to initialize the Xerces-C++ + runtime while others initialize and terminate it as part of their + work. The general rule is as follows: if a function has any arguments + or return a value that is an instance of a Xerces-C++ type, then + this function expects you to initialize the Xerces-C++ runtime. + Otherwise, the function initializes and terminates the runtime for + you. Note that it is legal to have nested calls to the Xerces-C++ + initialize and terminate functions as long as the calls are balanced. + </p> + + <p>You can instruct parsing functions that initialize and terminate + the runtime not to do so by passing the + <code>xml_schema::flags::dont_initialize</code> flag (see + <a href="#3.2">Section 3.2, "Flags and Properties"</a>). + </p> + + + <h2><a name="3.2">3.2 Flags and Properties</a></h2> + + <p>Parsing flags and properties are the last two arguments of every + parsing function. They allow you to fine-tune the process of + instance validation and parsing. Both arguments are optional. + </p> + + + <p>The following flags are recognized by the parsing functions:</p> + + <dl> + <dt><code>xml_schema::flags::keep_dom</code></dt> + <dd>Keep association between DOM nodes and the resulting + object model nodes. For more information about DOM association + refer to <a href="#5.1">Section 5.1, "DOM Association"</a>.</dd> + + <dt><code>xml_schema::flags::own_dom</code></dt> + <dd>Assume ownership of the DOM document passed. This flag only + makes sense together with the <code>keep_dom</code> flag in + the call to the parsing function with the + <code>xml_schema::dom::[unique|auto]_ptr<DOMDocument></code> + argument.</dd> + + <dt><code>xml_schema::flags::dont_validate</code></dt> + <dd>Do not validate instance documents against schemas.</dd> + + <dt><code>xml_schema::flags::dont_initialize</code></dt> + <dd>Do not initialize the Xerces-C++ runtime.</dd> + </dl> + + <p>You can pass several flags by combining them using the bit-wise OR + operator. For example:</p> + + <pre class="c++"> +using xml_schema::flags; + +std::unique_ptr<type> r ( + name ("test.xml", flags::keep_dom | flags::dont_validate)); + </pre> + + <p>By default, validation of instance documents is turned on even + though parsers generated by XSD do not assume instance + documents are valid. They include a number of checks that prevent + construction of inconsistent object models. This, + however, does not mean that an instance document that was + successfully parsed by the XSD-generated parsers is + valid per the corresponding schema. If an instance document is not + "valid enough" for the generated parsers to construct consistent + object model, one of the exceptions defined in + <code>xml_schema</code> namespace is thrown (see + <a href="#3.3">Section 3.3, "Error Handling"</a>). + </p> + + <p>For more information on the Xerces-C++ runtime initialization + refer to <a href="#3.1">Section 3.1, "Initializing the Xerces-C++ + Runtime"</a>. + </p> + + <p>The <code>xml_schema::properties</code> class allows you to + programmatically specify schema locations to be used instead + of those specified with the <code>xsi::schemaLocation</code> + and <code>xsi::noNamespaceSchemaLocation</code> attributes + in instance documents. The interface of the <code>properties</code> + class is presented below: + </p> + + <pre class="c++"> +class properties +{ +public: + void + schema_location (const std::basic_string<C>& namespace_, + const std::basic_string<C>& location); + void + no_namespace_schema_location (const std::basic_string<C>& location); +}; + </pre> + + <p>Note that all locations are relative to an instance document unless + they are URIs. For example, if you want to use a local file as your + schema, then you will need to pass + <code>file:///absolute/path/to/your/schema</code> as the location + argument. + </p> + + <h2><a name="3.3">3.3 Error Handling</a></h2> + + <p>As discussed in <a href="#2.2">Section 2.2, "Error Handling"</a>, + the mapping uses the C++ exception handling mechanism as its primary + way of reporting error conditions. However, to handle recoverable + parsing and validation errors and warnings, a callback interface maybe + preferred by the application.</p> + + <p>To better understand error handling and reporting strategies employed + by the parsing functions, it is useful to know that the + transformation of an XML instance document to a statically-typed + tree happens in two stages. The first stage, performed by Xerces-C++, + consists of parsing an XML document into a DOM instance. For short, + we will call this stage the XML-DOM stage. Validation, if not disabled, + happens during this stage. The second stage, + performed by the generated parsers, consist of parsing the DOM + instance into the statically-typed tree. We will call this stage + the DOM-Tree stage. Additional checks are performed during this + stage in order to prevent construction of inconsistent tree which + could otherwise happen when validation is disabled, for example.</p> + + <p>All parsing functions except the one that operates on a DOM instance + come in overloaded triples. The first function in such a triple + reports error conditions exclusively by throwing exceptions. It + accumulates all the parsing and validation errors of the XML-DOM + stage and throws them in a single instance of the + <code>xml_schema::parsing</code> exception (described below). + The second and the third functions in the triple use callback + interfaces to report parsing and validation errors and warnings. + The two callback interfaces are <code>xml_schema::error_handler</code> + and <code>xercesc::DOMErrorHandler</code>. For more information + on the <code>xercesc::DOMErrorHandler</code> interface refer to + the Xerces-C++ documentation. The <code>xml_schema::error_handler</code> + interface is presented below: + </p> + + <pre class="c++"> +class error_handler +{ +public: + struct severity + { + enum value + { + warning, + error, + fatal + }; + }; + + virtual bool + handle (const std::basic_string<C>& id, + unsigned long line, + unsigned long column, + severity, + const std::basic_string<C>& message) = 0; + + virtual + ~error_handler (); +}; + </pre> + + <p>The <code>id</code> argument of the <code>error_handler::handle</code> + function identifies the resource being parsed (e.g., a file name or + URI). + </p> + + <p>By returning <code>true</code> from the <code>handle</code> function + you instruct the parser to recover and continue parsing. Returning + <code>false</code> results in termination of the parsing process. + An error with the <code>fatal</code> severity level results in + termination of the parsing process no matter what is returned from + the <code>handle</code> function. It is safe to throw an exception + from the <code>handle</code> function. + </p> + + <p>The DOM-Tree stage reports error conditions exclusively by throwing + exceptions. Individual exceptions thrown by the parsing functions + are described in the following sub-sections. + </p> + + + <h3><a name="3.3.1">3.3.1 <code>xml_schema::parsing</code></a></h3> + + <pre class="c++"> +struct severity +{ + enum value + { + warning, + error + }; + + severity (value); + operator value () const; +}; + +struct error +{ + error (severity, + const std::basic_string<C>& id, + unsigned long line, + unsigned long column, + const std::basic_string<C>& message); + + severity + severity () const; + + const std::basic_string<C>& + id () const; + + unsigned long + line () const; + + unsigned long + column () const; + + const std::basic_string<C>& + message () const; +}; + +std::basic_ostream<C>& +operator<< (std::basic_ostream<C>&, const error&); + +struct diagnostics: std::vector<error> +{ +}; + +std::basic_ostream<C>& +operator<< (std::basic_ostream<C>&, const diagnostics&); + +struct parsing: virtual exception +{ + parsing (); + parsing (const diagnostics&); + + const diagnostics& + diagnostics () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::parsing</code> exception is thrown if there + were parsing or validation errors reported during the XML-DOM stage. + If no callback interface was provided to the parsing function, the + exception contains a list of errors and warnings accessible using + the <code>diagnostics</code> function. The usual conditions when + this exception is thrown include malformed XML instances and, if + validation is turned on, invalid instance documents. + </p> + + <h3><a name="3.3.2">3.3.2 <code>xml_schema::expected_element</code></a></h3> + + <pre class="c++"> +struct expected_element: virtual exception +{ + expected_element (const std::basic_string<C>& name, + const std::basic_string<C>& namespace_); + + + const std::basic_string<C>& + name () const; + + const std::basic_string<C>& + namespace_ () const; + + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::expected_element</code> exception is thrown + when an expected element is not encountered by the DOM-Tree stage. + The name and namespace of the expected element can be obtained using + the <code>name</code> and <code>namespace_</code> functions respectively. + </p> + + + <h3><a name="3.3.3">3.3.3 <code>xml_schema::unexpected_element</code></a></h3> + + <pre class="c++"> +struct unexpected_element: virtual exception +{ + unexpected_element (const std::basic_string<C>& encountered_name, + const std::basic_string<C>& encountered_namespace, + const std::basic_string<C>& expected_name, + const std::basic_string<C>& expected_namespace) + + + const std::basic_string<C>& + encountered_name () const; + + const std::basic_string<C>& + encountered_namespace () const; + + + const std::basic_string<C>& + expected_name () const; + + const std::basic_string<C>& + expected_namespace () const; + + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::unexpected_element</code> exception is thrown + when an unexpected element is encountered by the DOM-Tree stage. + The name and namespace of the encountered element can be obtained + using the <code>encountered_name</code> and + <code>encountered_namespace</code> functions respectively. If an + element was expected instead of the encountered one, its name + and namespace can be obtained using the <code>expected_name</code> and + <code>expected_namespace</code> functions respectively. Otherwise + these functions return empty strings. + </p> + + <h3><a name="3.3.4">3.3.4 <code>xml_schema::expected_attribute</code></a></h3> + + <pre class="c++"> +struct expected_attribute: virtual exception +{ + expected_attribute (const std::basic_string<C>& name, + const std::basic_string<C>& namespace_); + + + const std::basic_string<C>& + name () const; + + const std::basic_string<C>& + namespace_ () const; + + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::expected_attribute</code> exception is thrown + when an expected attribute is not encountered by the DOM-Tree stage. + The name and namespace of the expected attribute can be obtained using + the <code>name</code> and <code>namespace_</code> functions respectively. + </p> + + + <h3><a name="3.3.5">3.3.5 <code>xml_schema::unexpected_enumerator</code></a></h3> + + <pre class="c++"> +struct unexpected_enumerator: virtual exception +{ + unexpected_enumerator (const std::basic_string<C>& enumerator); + + const std::basic_string<C>& + enumerator () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::unexpected_enumerator</code> exception is thrown + when an unexpected enumerator is encountered by the DOM-Tree stage. + The enumerator can be obtained using the <code>enumerator</code> + functions. + </p> + + <h3><a name="3.3.6">3.3.6 <code>xml_schema::expected_text_content</code></a></h3> + + <pre class="c++"> +struct expected_text_content: virtual exception +{ + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::expected_text_content</code> exception is thrown + when a content other than text is encountered and the text content was + expected by the DOM-Tree stage. + </p> + + <h3><a name="3.3.7">3.3.7 <code>xml_schema::no_type_info</code></a></h3> + + <pre class="c++"> +struct no_type_info: virtual exception +{ + no_type_info (const std::basic_string<C>& type_name, + const std::basic_string<C>& type_namespace); + + const std::basic_string<C>& + type_name () const; + + const std::basic_string<C>& + type_namespace () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::no_type_info</code> exception is thrown + when there is no type information associated with a type specified + by the <code>xsi:type</code> attribute. This exception is thrown + by the DOM-Tree stage. The name and namespace of the type in question + can be obtained using the <code>type_name</code> and + <code>type_namespace</code> functions respectively. Usually, catching + this exception means that you haven't linked the code generated + from the schema defining the type in question with your application + or this schema has been compiled without the + <code>--generate-polymorphic</code> option. + </p> + + + <h3><a name="3.3.8">3.3.8 <code>xml_schema::not_derived</code></a></h3> + + <pre class="c++"> +struct not_derived: virtual exception +{ + not_derived (const std::basic_string<C>& base_type_name, + const std::basic_string<C>& base_type_namespace, + const std::basic_string<C>& derived_type_name, + const std::basic_string<C>& derived_type_namespace); + + const std::basic_string<C>& + base_type_name () const; + + const std::basic_string<C>& + base_type_namespace () const; + + + const std::basic_string<C>& + derived_type_name () const; + + const std::basic_string<C>& + derived_type_namespace () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::not_derived</code> exception is thrown + when a type specified by the <code>xsi:type</code> attribute is + not derived from the expected base type. This exception is thrown + by the DOM-Tree stage. The name and namespace of the expected + base type can be obtained using the <code>base_type_name</code> and + <code>base_type_namespace</code> functions respectively. The name + and namespace of the offending type can be obtained using the + <code>derived_type_name</code> and + <code>derived_type_namespace</code> functions respectively. + </p> + + <h3><a name="3.3.9">3.3.9 <code>xml_schema::no_prefix_mapping</code></a></h3> + + <pre class="c++"> +struct no_prefix_mapping: virtual exception +{ + no_prefix_mapping (const std::basic_string<C>& prefix); + + const std::basic_string<C>& + prefix () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::no_prefix_mapping</code> exception is thrown + during the DOM-Tree stage if a namespace prefix is encountered for + which a prefix-namespace mapping hasn't been provided. The namespace + prefix in question can be obtained using the <code>prefix</code> + function. + </p> + + <h2><a name="3.4">3.4 Reading from a Local File or URI</a></h2> + + <p>Using a local file or URI is the simplest way to parse an XML instance. + For example:</p> + + <pre class="c++"> +using std::unique_ptr; + +unique_ptr<type> r1 (name ("test.xml")); +unique_ptr<type> r2 (name ("https://www.codesynthesis.com/test.xml")); + </pre> + + <p>Or, in the C++98 mode:</p> + + <pre class="c++"> +using std::auto_ptr; + +auto_ptr<type> r1 (name ("test.xml")); +auto_ptr<type> r2 (name ("https://www.codesynthesis.com/test.xml")); + </pre> + + <h2><a name="3.5">3.5 Reading from <code>std::istream</code></a></h2> + + <p>When using an <code>std::istream</code> instance, you may also + pass an optional resource id. This id is used to identify the + resource (for example in error messages) as well as to resolve + relative paths. For instance:</p> + + <pre class="c++"> +using std::unique_ptr; + +{ + std::ifstream ifs ("test.xml"); + unique_ptr<type> r (name (ifs, "test.xml")); +} + +{ + std::string str ("..."); // Some XML fragment. + std::istringstream iss (str); + unique_ptr<type> r (name (iss)); +} + </pre> + + <h2><a name="3.6">3.6 Reading from <code>xercesc::InputSource</code></a></h2> + + <p>Reading from a <code>xercesc::InputSource</code> instance + is similar to the <code>std::istream</code> case except + the resource id is maintained by the <code>InputSource</code> + object. For instance:</p> + + <pre class="c++"> +xercesc::StdInInputSource is; +std::unique_ptr<type> r (name (is)); + </pre> + + <h2><a name="3.7">3.7 Reading from DOM</a></h2> + + <p>Reading from a <code>xercesc::DOMDocument</code> instance allows + you to setup a custom XML-DOM stage. Things like DOM + parser reuse, schema pre-parsing, and schema caching can be achieved + with this approach. For more information on how to obtain DOM + representation from an XML instance refer to the Xerces-C++ + documentation. In addition, the + <a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree Mapping + FAQ</a> shows how to parse an XML instance to a Xerces-C++ + DOM document using the XSD runtime utilities. + </p> + + <p>The last parsing function is useful when you would like to perform + your own XML-to-DOM parsing and associate the resulting DOM document + with the object model nodes. The automatic <code>DOMDocument</code> + pointer is reset and the resulting object model assumes ownership + of the DOM document passed. For example:</p> + + <pre class="c++"> +// C++11 version. +// +xml_schema::dom::unique_ptr<xercesc::DOMDocument> doc = ... + +std::unique_ptr<type> r ( + name (std::move (doc), + xml_schema::flags::keep_dom | xml_schema::flags::own_dom)); + +// At this point doc is reset to 0. + +// C++98 version. +// +xml_schema::dom::auto_ptr<xercesc::DOMDocument> doc = ... + +std::auto_ptr<type> r ( + name (doc, xml_schema::flags::keep_dom | xml_schema::flags::own_dom)); + +// At this point doc is reset to 0. + </pre> + + <h1><a name="4">4 Serialization</a></h1> + + <p>This chapter covers various aspects of serializing a + tree-like object model to DOM or XML. + In this regard, serialization is complimentary to the reverse + process of parsing a DOM or XML instance into an object model + which is discussed in <a href="#3">Chapter 3, + "Parsing"</a>. Note that the generation of the serialization code + is optional and should be explicitly requested with the + <code>--generate-serialization</code> option. See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information. + </p> + + <p>Each global XML Schema element in the form: + </p> + + + <pre class="xml"> +<xsd:element name="name" type="type"/> + </pre> + + <p>is mapped to 8 overloaded C++ functions in the form:</p> + + <pre class="c++"> +// Serialize to std::ostream. +// +void +name (std::ostream&, + const type&, + const xml_schema::namespace_fomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (std::ostream&, + const type&, + xml_schema::error_handler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (std::ostream&, + const type&, + xercesc::DOMErrorHandler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + + +// Serialize to XMLFormatTarget. +// +void +name (xercesc::XMLFormatTarget&, + const type&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (xercesc::XMLFormatTarget&, + const type&, + xml_schema::error_handler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (xercesc::XMLFormatTarget&, + const type&, + xercesc::DOMErrorHandler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + + +// Serialize to DOM. +// +xml_schema::dom::[unique|auto]_ptr<xercesc::DOMDocument> +name (const type&, + const xml_schema::namespace_infomap& + xml_schema::namespace_infomap (), + xml_schema::flags = 0); + +void +name (xercesc::DOMDocument&, + const type&, + xml_schema::flags = 0); + </pre> + + <p>You can choose between writing XML to <code>std::ostream</code> or + <code>xercesc::XMLFormatTarget</code> and creating a DOM instance + in the form of <code>xercesc::DOMDocument</code>. Serialization + to <code>ostream</code> or <code>XMLFormatTarget</code> requires a + considerably less work while serialization to DOM provides + for greater flexibility. Each of these serialization functions + is discussed in more detail in the following sections. + </p> + + + <h2><a name="4.1">4.1 Initializing the Xerces-C++ Runtime</a></h2> + + <p>Some serialization functions expect you to initialize the Xerces-C++ + runtime while others initialize and terminate it as part of their + work. The general rule is as follows: if a function has any arguments + or return a value that is an instance of a Xerces-C++ type, then + this function expects you to initialize the Xerces-C++ runtime. + Otherwise, the function initializes and terminates the runtime for + you. Note that it is legal to have nested calls to the Xerces-C++ + initialize and terminate functions as long as the calls are balanced. + </p> + + <p>You can instruct serialization functions that initialize and terminate + the runtime not to do so by passing the + <code>xml_schema::flags::dont_initialize</code> flag (see + <a href="#4.3">Section 4.3, "Flags"</a>). + </p> + + <h2><a name="4.2">4.2 Namespace Infomap and Character Encoding</a></h2> + + <p>When a document being serialized uses XML namespaces, custom + prefix-namespace associations can to be established. If custom + prefix-namespace mapping is not provided then generic prefixes + (<code>p1</code>, <code>p2</code>, etc) are automatically assigned + to namespaces as needed. Also, if + you would like the resulting instance document to contain the + <code>schemaLocation</code> or <code>noNamespaceSchemaLocation</code> + attributes, you will need to provide namespace-schema associations. + The <code>xml_schema::namespace_infomap</code> class is used + to capture this information:</p> + + <pre class="c++"> +struct namespace_info +{ + namespace_info (); + namespace_info (const std::basic_string<C>& name, + const std::basic_string<C>& schema); + + std::basic_string<C> name; + std::basic_string<C> schema; +}; + +// Map of namespace prefix to namespace_info. +// +struct namespace_infomap: public std::map<std::basic_string<C>, + namespace_info> +{ +}; + </pre> + + <p>Consider the following associations as an example:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + </pre> + + <p>This map, if passed to one of the serialization functions, + could result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<t:name xmlns:t="https://www.codesynthesis.com/test" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://www.codesynthesis.com/test test.xsd"> + </pre> + + <p>As you can see, the serialization function automatically added namespace + mapping for the <code>xsi</code> prefix. You can change this by + providing your own prefix:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map["xsn"].name = "http://www.w3.org/2001/XMLSchema-instance"; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + </pre> + + <p>This could result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<t:name xmlns:t="https://www.codesynthesis.com/test" + xmlns:xsn="http://www.w3.org/2001/XMLSchema-instance" + xsn:schemaLocation="https://www.codesynthesis.com/test test.xsd"> + </pre> + + <p>To specify the location of a schema without a namespace you can use + an empty prefix as in the example below: </p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].schema = "test.xsd"; + </pre> + + <p>This would result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<name xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="test.xsd"> + </pre> + + <p>To make a particular namespace default you can use an empty + prefix, for example:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].name = "https://www.codesynthesis.com/test"; +map[""].schema = "test.xsd"; + </pre> + + <p>This could result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<name xmlns="https://www.codesynthesis.com/test" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://www.codesynthesis.com/test test.xsd"> + </pre> + + + <p>Another bit of information that you can pass to the serialization + functions is the character encoding method that you would like to use. + Common values for this argument are <code>"US-ASCII"</code>, + <code>"ISO8859-1"</code>, <code>"UTF-8"</code>, + <code>"UTF-16BE"</code>, <code>"UTF-16LE"</code>, + <code>"UCS-4BE"</code>, and <code>"UCS-4LE"</code>. The default + encoding is <code>"UTF-8"</code>. For more information on + encoding methods see the + "<a href="http://en.wikipedia.org/wiki/Character_code">Character + Encoding</a>" article from Wikipedia. + </p> + + <h2><a name="4.3">4.3 Flags</a></h2> + + <p>Serialization flags are the last argument of every serialization + function. They allow you to fine-tune the process of serialization. + The flags argument is optional. + </p> + + + <p>The following flags are recognized by the serialization + functions:</p> + + <dl> + <dt><code>xml_schema::flags::dont_initialize</code></dt> + <dd>Do not initialize the Xerces-C++ runtime.</dd> + + <dt><code>xml_schema::flags::dont_pretty_print</code></dt> + <dd>Do not add extra spaces or new lines that make the resulting XML + slightly bigger but easier to read.</dd> + + <dt><code>xml_schema::flags::no_xml_declaration</code></dt> + <dd>Do not write XML declaration (<?xml ... ?>).</dd> + </dl> + + <p>You can pass several flags by combining them using the bit-wise OR + operator. For example:</p> + + <pre class="c++"> +std::unique_ptr<type> r = ... +std::ofstream ofs ("test.xml"); +xml_schema::namespace_infomap map; +name (ofs, + *r, + map, + "UTF-8", + xml_schema::flags::no_xml_declaration | + xml_schema::flags::dont_pretty_print); + </pre> + + <p>For more information on the Xerces-C++ runtime initialization + refer to <a href="#4.1">Section 4.1, "Initializing the Xerces-C++ + Runtime"</a>. + </p> + + <h2><a name="4.4">4.4 Error Handling</a></h2> + + <p>As with the parsing functions (see <a href="#3.3">Section 3.3, + "Error Handling"</a>), to better understand error handling and + reporting strategies employed by the serialization functions, it + is useful to know that the transformation of a statically-typed + tree to an XML instance document happens in two stages. The first + stage, performed by the generated code, consist of building a DOM + instance from the statically-typed tree . For short, we will call + this stage the Tree-DOM stage. The second stage, performed by + Xerces-C++, consists of serializing the DOM instance into the XML + document. We will call this stage the DOM-XML stage. + </p> + + <p>All serialization functions except the two that serialize into + a DOM instance come in overloaded triples. The first function + in such a triple reports error conditions exclusively by throwing + exceptions. It accumulates all the serialization errors of the + DOM-XML stage and throws them in a single instance of the + <code>xml_schema::serialization</code> exception (described below). + The second and the third functions in the triple use callback + interfaces to report serialization errors and warnings. The two + callback interfaces are <code>xml_schema::error_handler</code> and + <code>xercesc::DOMErrorHandler</code>. The + <code>xml_schema::error_handler</code> interface is described in + <a href="#3.3">Section 3.3, "Error Handling"</a>. For more information + on the <code>xercesc::DOMErrorHandler</code> interface refer to the + Xerces-C++ documentation. + </p> + + <p>The Tree-DOM stage reports error conditions exclusively by throwing + exceptions. Individual exceptions thrown by the serialization functions + are described in the following sub-sections. + </p> + + <h3><a name="4.4.1">4.4.1 <code>xml_schema::serialization</code></a></h3> + + <pre class="c++"> +struct serialization: virtual exception +{ + serialization (); + serialization (const diagnostics&); + + const diagnostics& + diagnostics () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::diagnostics</code> class is described in + <a href="#3.3.1">Section 3.3.1, "<code>xml_schema::parsing</code>"</a>. + The <code>xml_schema::serialization</code> exception is thrown if + there were serialization errors reported during the DOM-XML stage. + If no callback interface was provided to the serialization function, + the exception contains a list of errors and warnings accessible using + the <code>diagnostics</code> function. + </p> + + + <h3><a name="4.4.2">4.4.2 <code>xml_schema::unexpected_element</code></a></h3> + + <p>The <code>xml_schema::unexpected_element</code> exception is + described in <a href="#3.3.3">Section 3.3.3, + "<code>xml_schema::unexpected_element</code>"</a>. It is thrown + by the serialization functions during the Tree-DOM stage if the + root element name of the provided DOM instance does not match with + the name of the element this serialization function is for. + </p> + + <h3><a name="4.4.3">4.4.3 <code>xml_schema::no_type_info</code></a></h3> + + <p>The <code>xml_schema::no_type_info</code> exception is + described in <a href="#3.3.7">Section 3.3.7, + "<code>xml_schema::no_type_info</code>"</a>. It is thrown + by the serialization functions during the Tree-DOM stage when there + is no type information associated with a dynamic type of an + element. Usually, catching this exception means that you haven't + linked the code generated from the schema defining the type in + question with your application or this schema has been compiled + without the <code>--generate-polymorphic</code> option. + </p> + + <h2><a name="4.5">4.5 Serializing to <code>std::ostream</code></a></h2> + + <p>In order to serialize to <code>std::ostream</code> you will need + an object model, an output stream and, optionally, a namespace + infomap. For instance:</p> + + <pre class="c++"> +// Obtain the object model. +// +std::unique_ptr<type> r = ... + +// Prepare namespace mapping and schema location information. +// +xml_schema::namespace_infomap map; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + +// Write it out. +// +name (std::cout, *r, map); + </pre> + + <p>Note that the output stream is treated as a binary stream. This + becomes important when you use a character encoding that is wider + than 8-bit <code>char</code>, for instance UTF-16 or UCS-4. For + example, things will most likely break if you try to serialize + to <code>std::ostringstream</code> with UTF-16 or UCS-4 as an + encoding. This is due to the special value, + <code>'\0'</code>, that will most likely occur as part of such + serialization and it won't have the special meaning assumed by + <code>std::ostringstream</code>. + </p> + + + <h2><a name="4.6">4.6 Serializing to <code>xercesc::XMLFormatTarget</code></a></h2> + + <p>Serializing to an <code>xercesc::XMLFormatTarget</code> instance + is similar the <code>std::ostream</code> case. For instance: + </p> + + <pre class="c++"> +using std::unique_ptr; + +// Obtain the object model. +// +unique_ptr<type> r = ... + +// Prepare namespace mapping and schema location information. +// +xml_schema::namespace_infomap map; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Choose a target. + // + unique_ptr<XMLFormatTarget> ft; + + if (argc != 2) + { + ft = unique_ptr<XMLFormatTarget> (new StdOutFormatTarget ()); + } + else + { + ft = unique_ptr<XMLFormatTarget> ( + new LocalFileFormatTarget (argv[1])); + } + + // Write it out. + // + name (*ft, *r, map); +} + +XMLPlatformUtils::Terminate (); + </pre> + + <p>Note that we had to initialize the Xerces-C++ runtime before we + could call this serialization function.</p> + + <h2><a name="4.7">4.7 Serializing to DOM</a></h2> + + <p>The mapping provides two overloaded functions that implement + serialization to a DOM instance. The first creates a DOM instance + for you and the second serializes to an existing DOM instance. + While serializing to a new DOM instance is similar to serializing + to <code>std::ostream</code> or <code>xercesc::XMLFormatTarget</code>, + serializing to an existing DOM instance requires quite a bit of work + from your side. You will need to set all the custom namespace mapping + attributes as well as the <code>schemaLocation</code> and/or + <code>noNamespaceSchemaLocation</code> attributes. The following + listing should give you an idea about what needs to be done: + </p> + + <pre class="c++"> +// Obtain the object model. +// +std::unique_ptr<type> r = ... + +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Create a DOM instance. Set custom namespace mapping and schema + // location attributes. + // + DOMDocument& doc = ... + + // Serialize to DOM. + // + name (doc, *r); + + // Serialize the DOM document to XML. + // + ... +} + +XMLPlatformUtils::Terminate (); + </pre> + + <p>For more information on how to create and serialize a DOM instance + refer to the Xerces-C++ documentation. In addition, the + <a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree Mapping + FAQ</a> shows how to implement these operations using the XSD + runtime utilities. + </p> + + <h1><a name="5">5 Additional Functionality</a></h1> + + <p>The C++/Tree mapping provides a number of optional features + that can be useful in certain situations. They are described + in the following sections.</p> + + <h2><a name="5.1">5.1 DOM Association</a></h2> + + <p>Normally, after parsing is complete, the DOM document which + was used to extract the data is discarded. However, the parsing + functions can be instructed to preserve the DOM document + and create an association between the DOM nodes and object model + nodes. When there is an association between the DOM and + object model nodes, you can obtain the corresponding DOM element + or attribute node from an object model node as well as perform + the reverse transition: obtain the corresponding object model + from a DOM element or attribute node.</p> + + <p>Maintaining DOM association is normally useful when the application + needs access to XML constructs that are not preserved in the + object model, for example, XML comments. + Another useful aspect of DOM association is the ability of the + application to navigate the document tree using the generic DOM + interface (for example, with the help of an XPath processor) + and then move back to the statically-typed object model. Note + also that while you can change the underlying DOM document, + these changes are not reflected in the object model and will + be ignored during serialization. If you need to not only access + but also modify some aspects of XML that are not preserved in + the object model, then type customization with custom parsing + constructors and serialization operators should be used instead.</p> + + <p>To request DOM association you will need to pass the + <code>xml_schema::flags::keep_dom</code> flag to one of the + parsing functions (see <a href="#3.2">Section 3.2, + "Flags and Properties"</a> for more information). In this case the + DOM document is retained and will be released when the object model + is deleted. Note that since DOM nodes "out-live" the parsing function + call, you need to initialize the Xerces-C++ runtime before calling + one of the parsing functions with the <code>keep_dom</code> flag and + terminate it after the object model is destroyed (see + <a href="#3.1">Section 3.1, "Initializing the Xerces-C++ Runtime"</a>).</p> + + <p>If the <code>keep_dom</code> flag is passed + as the second argument to the copy constructor and the copy + being made is of a complete tree, then the DOM association + is also maintained in the copy by cloning the underlying + DOM document and reestablishing the associations. For example:</p> + + <pre class="c++"> +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Parse XML to object model. + // + std::unique_ptr<type> r (root ( + "root.xml", + xml_schema::flags::keep_dom | + xml_schema::flags::dont_initialize)); + + // Copy without DOM association. + // + type copy1 (*r); + + // Copy with DOM association. + // + type copy2 (*r, xml_schema::flags::keep_dom); +} + +XMLPlatformUtils::Terminate (); + </pre> + + + <p>To obtain the corresponding DOM node from an object model node + you will need to call the <code>_node</code> accessor function + which returns a pointer to <code>DOMNode</code>. You can then query + this DOM node's type and cast it to either <code>DOMAttr*</code> + or <code>DOMElement*</code>. To obtain the corresponding object + model node from a DOM node, the DOM user data API is used. The + <code>xml_schema::dom::tree_node_key</code> variable contains + the key for object model nodes. The following schema and code + fragment show how to navigate from DOM to object model nodes + and in the opposite direction:</p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="a" type="string"/> + </sequence> +</complexType> + +<element name="root" type="object"/> + </pre> + + <pre class="c++"> +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Parse XML to object model. + // + std::unique_ptr<type> r (root ( + "root.xml", + xml_schema::flags::keep_dom | + xml_schema::flags::dont_initialize)); + + DOMNode* n = r->_node (); + assert (n->getNodeType () == DOMNode::ELEMENT_NODE); + DOMElement* re = static_cast<DOMElement*> (n); + + // Get the 'a' element. Note that it is not necessarily the + // first child node of 'root' since there could be whitespace + // nodes before it. + // + DOMElement* ae; + + for (n = re->getFirstChild (); n != 0; n = n->getNextSibling ()) + { + if (n->getNodeType () == DOMNode::ELEMENT_NODE) + { + ae = static_cast<DOMElement*> (n); + break; + } + } + + // Get from the 'a' DOM element to xml_schema::string object model + // node. + // + xml_schema::type& t ( + *reinterpret_cast<xml_schema::type*> ( + ae->getUserData (xml_schema::dom::tree_node_key))); + + xml_schema::string& a (dynamic_cast<xml_schema::string&> (t)); +} + +XMLPlatformUtils::Terminate (); + </pre> + + <p>The 'mixed' example which can be found in the XSD distribution + shows how to handle the mixed content using DOM association.</p> + + <h2><a name="5.2">5.2 Binary Serialization</a></h2> + + <p>Besides reading from and writing to XML, the C++/Tree 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 serialization saves only the data without any meta + information or markup. As a result, saving to and loading + from a binary representation can be an order of magnitude + faster than 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 binary serialization 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 operators and + extraction constructors 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="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information.</p> + + <p>Once the insertion operators and extraction constructors are + generated, you can use the <code>xml_schema::istream</code> + and <code>xml_schema::ostream</code> wrapper stream templates + to save the object model to and load it from a specific format. + The following code fragment shows how to do this using ACE + (Adaptive Communication Environment) CDR streams as an example:</p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="a" type="string"/> + <element name="b" type="int"/> + </sequence> +</complexType> + +<element name="root" type="object"/> + </pre> + + <pre class="c++"> +// Parse XML to object model. +// +std::unique_ptr<type> r (root ("root.xml")); + +// Save to a CDR stream. +// +ACE_OutputCDR ace_ocdr; +xml_schema::ostream<ACE_OutputCDR> ocdr (ace_ocdr); + +ocdr << *r; + +// Load from a CDR stream. +// +ACE_InputCDR ace_icdr (buf, size); +xml_schema::istream<ACE_InputCDR> icdr (ace_icdr); + +std::unique_ptr<object> copy (new object (icdr)); + +// Serialize to XML. +// +root (std::cout, *copy); + </pre> + + <p>The XSD distribution contains a number of examples that + show how to save the object model to and load it from + CDR, XDR, and a custom format.</p> + + <!-- Appendix A --> + + + <h1><a name="A">Appendix A — Default and Fixed Values</a></h1> + + <p>The following table summarizes the effect of default and fixed + values (specified with the <code>default</code> and <code>fixed</code> + attributes, respectively) on attribute and element values. The + <code>default</code> and <code>fixed</code> attributes are mutually + exclusive. It is also worthwhile to note that the fixed value semantics + is a superset of the default value semantics. + </p> + + <!-- border="1" is necessary for html2ps --> + <table id="default-fixed" border="1"> + <tr> + <th></th> + <th></th> + <th colspan="2">default</th> + <th colspan="2">fixed</th> + </tr> + + <!-- element --> + + <tr> + <th rowspan="4">element</th> + <th rowspan="2">not present</th> + <th>optional</th> + <th>required</th> + <th>optional</th> + <th>required</th> + </tr> + <tr> + <td>not present</td> + <td>invalid instance</td> + <td>not present</td> + <td>invalid instance</td> + </tr> + + + <tr> + <th>empty</th> + <td colspan="2">default value is used</td> + <td colspan="2">fixed value is used</td> + </tr> + + <tr> + <th>value</th> + <td colspan="2">value is used</td> + <td colspan="2">value is used provided it's the same as fixed</td> + </tr> + + <!-- attribute --> + + <!-- element --> + + <tr> + <th rowspan="4">attribute</th> + <th rowspan="2">not present</th> + <th>optional</th> + <th>required</th> + <th>optional</th> + <th>required</th> + </tr> + <tr> + <td>default value is used</td> + <td>invalid schema</td> + <td>fixed value is used</td> + <td>invalid instance</td> + </tr> + + + <tr> + <th>empty</th> + <td colspan="2">empty value is used</td> + <td colspan="2">empty value is used provided it's the same as fixed</td> + </tr> + + <tr> + <th>value</th> + <td colspan="2">value is used</td> + <td colspan="2">value is used provided it's the same as fixed</td> + </tr> + + </table> + + </div> +</div> + + +</body> +</html> diff --git a/doc/cxx/tree/manual/index.xhtml.in b/doc/cxx/tree/manual/index.xhtml.in new file mode 100644 index 0000000..5a7240a --- /dev/null +++ b/doc/cxx/tree/manual/index.xhtml.in @@ -0,0 +1,6826 @@ +<?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>C++/Tree Mapping User Manual</title> + + <meta name="copyright" content="© @copyright@"/> + <meta name="keywords" content="xsd,xml,schema,c++,mapping,data,binding,tree,serialization,guide,manual,examples"/> + <meta name="description" content="C++/Tree Mapping User Manual"/> + <meta name="revision" content="4.1.0"/> + + <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%; + } + + h2 { + font-weight : bold; + font-size : 150%; + + padding-top : 0.8em; + } + + h3 { + font-size : 130%; + 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; + padding: 1em 0 2em 0; + } + + /* Lists */ + ul.list li { + padding-top : 0.3em; + padding-bottom : 0.3em; + } + + + /* 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; + } + + + /* default-fixed */ + #default-fixed { + margin: 2em 0 2em 0; + + border-collapse : collapse; + border : 1px solid; + border-color : #000000; + + font-size : 11px; + line-height : 14px; + } + + #default-fixed th, #default-fixed td { + border: 1px solid; + padding : 0.9em 0.9em 0.7em 0.9em; + } + + #default-fixed th { + background : #cde8f6; + } + + #default-fixed td { + text-align: center; + } + + + /* */ + 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; + } +</style> + + +</head> + +<body> +<div id="container"> + <div id="content"> + + <div class="noprint"> + + <div id="titlepage"> + <div id="title">C++/Tree Mapping User Manual</div> + + <p>Copyright © @copyright@.</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href="https://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="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/index.xhtml">XHTML</a>, + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.pdf">PDF</a>, and + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.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></td> + </tr> + + <tr> + <th>2</th><td><a href="#2">C++/Tree Mapping</a> + <table class="toc"> + <tr> + <th>2.1</th><td><a href="#2.1">Preliminary Information</a> + <table class="toc"> + <tr><th>2.1.1</th><td><a href="#2.1.1">C++ Standard</a></td></tr> + <tr><th>2.1.2</th><td><a href="#2.1.2">Identifiers</a></td></tr> + <tr><th>2.1.3</th><td><a href="#2.1.3">Character Type and Encoding</a></td></tr> + <tr><th>2.1.4</th><td><a href="#2.1.4">XML Schema Namespace</a></td></tr> + <tr><th>2.1.5</th><td><a href="#2.1.5">Anonymous Types</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.2</th><td><a href="#2.2">Error Handling</a> + <table class="toc"> + <tr><th>2.2.1</th><td><a href="#2.2.1"><code>xml_schema::duplicate_id</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.3</th><td><a href="#2.3">Mapping for <code>import</code> and <code>include</code></a> + <table class="toc"> + <tr><th>2.3.1</th><td><a href="#2.3.1">Import</a></td></tr> + <tr><th>2.3.2</th><td><a href="#2.3.2">Inclusion with Target Namespace</a></td></tr> + <tr><th>2.3.3</th><td><a href="#2.3.3">Inclusion without Target Namespace</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.4</th><td><a href="#2.4">Mapping for Namespaces</a></td> + </tr> + <tr> + <th>2.5</th><td><a href="#2.5">Mapping for Built-in Data Types</a> + <table class="toc"> + <tr><th>2.5.1</th><td><a href="#2.5.1">Inheritance from Built-in Data Types</a></td></tr> + <tr><th>2.5.2</th><td><a href="#2.5.2">Mapping for <code>anyType</code></a></td></tr> + <tr><th>2.5.3</th><td><a href="#2.5.3">Mapping for <code>anySimpleType</code></a></td></tr> + <tr><th>2.5.4</th><td><a href="#2.5.4">Mapping for <code>QName</code></a></td></tr> + <tr><th>2.5.5</th><td><a href="#2.5.5">Mapping for <code>IDREF</code></a></td></tr> + <tr><th>2.5.6</th><td><a href="#2.5.6">Mapping for <code>base64Binary</code> and <code>hexBinary</code></a></td></tr> + <tr><th>2.5.7</th><td><a href="#2.5.7">Time Zone Representation</a></td></tr> + <tr><th>2.5.8</th><td><a href="#2.5.8">Mapping for <code>date</code></a></td></tr> + <tr><th>2.5.9</th><td><a href="#2.5.9">Mapping for <code>dateTime</code></a></td></tr> + <tr><th>2.5.10</th><td><a href="#2.5.10">Mapping for <code>duration</code></a></td></tr> + <tr><th>2.5.11</th><td><a href="#2.5.11">Mapping for <code>gDay</code></a></td></tr> + <tr><th>2.5.12</th><td><a href="#2.5.12">Mapping for <code>gMonth</code></a></td></tr> + <tr><th>2.5.13</th><td><a href="#2.5.13">Mapping for <code>gMonthDay</code></a></td></tr> + <tr><th>2.5.14</th><td><a href="#2.5.14">Mapping for <code>gYear</code></a></td></tr> + <tr><th>2.5.15</th><td><a href="#2.5.15">Mapping for <code>gYearMonth</code></a></td></tr> + <tr><th>2.5.16</th><td><a href="#2.5.16">Mapping for <code>time</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.6</th><td><a href="#2.6">Mapping for Simple Types</a> + <table class="toc"> + <tr><th>2.6.1</th><td><a href="#2.6.1">Mapping for Derivation by Restriction</a></td></tr> + <tr><th>2.6.2</th><td><a href="#2.6.2">Mapping for Enumerations</a></td></tr> + <tr><th>2.6.3</th><td><a href="#2.6.3">Mapping for Derivation by List</a></td></tr> + <tr><th>2.6.4</th><td><a href="#2.6.4">Mapping for Derivation by Union</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.7</th><td><a href="#2.7">Mapping for Complex Types</a> + <table class="toc"> + <tr><th>2.7.1</th><td><a href="#2.7.1">Mapping for Derivation by Extension</a></td></tr> + <tr><th>2.7.2</th><td><a href="#2.7.2">Mapping for Derivation by Restriction</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.8</th><td><a href="#2.8">Mapping for Local Elements and Attributes</a> + <table class="toc"> + <tr><th>2.8.1</th><td><a href="#2.8.1">Mapping for Members with the One Cardinality Class</a></td></tr> + <tr><th>2.8.2</th><td><a href="#2.8.2">Mapping for Members with the Optional Cardinality Class</a></td></tr> + <tr><th>2.8.3</th><td><a href="#2.8.3">Mapping for Members with the Sequence Cardinality Class</a></td></tr> + <tr><th>2.8.4</th><td><a href="#2.8.4">Element Order</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.9</th><td><a href="#2.9">Mapping for Global Elements</a> + <table class="toc"> + <tr><th>2.9.1</th><td><a href="#2.9.1">Element Types</a></td></tr> + <tr><th>2.9.2</th><td><a href="#2.9.2">Element Map</a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.10</th><td><a href="#2.10">Mapping for Global Attributes</a></td> + </tr> + <tr> + <th>2.11</th><td><a href="#2.11">Mapping for <code>xsi:type</code> and Substitution Groups</a></td> + </tr> + <tr> + <th>2.12</th><td><a href="#2.12">Mapping for <code>any</code> and <code>anyAttribute</code></a> + <table class="toc"> + <tr><th>2.12.1</th><td><a href="#2.12.1">Mapping for <code>any</code> with the One Cardinality Class</a></td></tr> + <tr><th>2.12.2</th><td><a href="#2.12.2">Mapping for <code>any</code> with the Optional Cardinality Class</a></td></tr> + <tr><th>2.12.3</th><td><a href="#2.12.3">Mapping for <code>any</code> with the Sequence Cardinality Class</a></td></tr> + <tr><th>2.12.4</th><td><a href="#2.12.4">Element Wildcard Order</a></td></tr> + <tr><th>2.12.5</th><td><a href="#2.12.5">Mapping for <code>anyAttribute</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>2.13</th><td><a href="#2.13">Mapping for Mixed Content Models</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">Parsing</a> + <table class="toc"> + <tr> + <th>3.1</th><td><a href="#3.1">Initializing the Xerces-C++ Runtime</a></td> + </tr> + <tr> + <th>3.2</th><td><a href="#3.2">Flags and Properties</a></td> + </tr> + <tr> + <th>3.3</th><td><a href="#3.3">Error Handling</a> + <table class="toc"> + <tr><th>3.3.1</th><td><a href="#3.3.1"><code>xml_schema::parsing</code></a></td></tr> + <tr><th>3.3.2</th><td><a href="#3.3.2"><code>xml_schema::expected_element</code></a></td></tr> + <tr><th>3.3.3</th><td><a href="#3.3.3"><code>xml_schema::unexpected_element</code></a></td></tr> + <tr><th>3.3.4</th><td><a href="#3.3.4"><code>xml_schema::expected_attribute</code></a></td></tr> + <tr><th>3.3.5</th><td><a href="#3.3.5"><code>xml_schema::unexpected_enumerator</code></a></td></tr> + <tr><th>3.3.6</th><td><a href="#3.3.6"><code>xml_schema::expected_text_content</code></a></td></tr> + <tr><th>3.3.7</th><td><a href="#3.3.7"><code>xml_schema::no_type_info</code></a></td></tr> + <tr><th>3.3.8</th><td><a href="#3.3.8"><code>xml_schema::not_derived</code></a></td></tr> + <tr><th>3.3.9</th><td><a href="#3.3.9"><code>xml_schema::not_prefix_mapping</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>3.4</th><td><a href="#3.4">Reading from a Local File or URI</a></td> + </tr> + <tr> + <th>3.5</th><td><a href="#3.5">Reading from <code>std::istream</code></a></td> + </tr> + <tr> + <th>3.6</th><td><a href="#3.6">Reading from <code>xercesc::InputSource</code></a></td> + </tr> + <tr> + <th>3.7</th><td><a href="#3.7">Reading from DOM</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th>4</th><td><a href="#4">Serialization</a> + <table class="toc"> + <tr> + <th>4.1</th><td><a href="#4.1">Initializing the Xerces-C++ Runtime</a></td> + </tr> + <tr> + <th>4.2</th><td><a href="#4.2">Namespace Infomap and Character Encoding</a></td> + </tr> + <tr> + <th>4.3</th><td><a href="#4.3">Flags</a></td> + </tr> + <tr> + <th>4.4</th><td><a href="#4.4">Error Handling</a> + <table class="toc"> + <tr><th>4.4.1</th><td><a href="#4.4.1"><code>xml_schema::serialization</code></a></td></tr> + <tr><th>4.4.2</th><td><a href="#4.4.2"><code>xml_schema::unexpected_element</code></a></td></tr> + <tr><th>4.4.3</th><td><a href="#4.4.3"><code>xml_schema::no_type_info</code></a></td></tr> + </table> + </td> + </tr> + <tr> + <th>4.5</th><td><a href="#4.5">Serializing to <code>std::ostream</code></a></td> + </tr> + <tr> + <th>4.6</th><td><a href="#4.6">Serializing to <code>xercesc::XMLFormatTarget</code></a></td> + </tr> + <tr> + <th>4.7</th><td><a href="#4.7">Serializing to DOM</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th>5</th><td><a href="#5">Additional Functionality</a> + <table class="toc"> + <tr> + <th>5.1</th><td><a href="#5.1">DOM Association</a></td> + </tr> + <tr> + <th>5.2</th><td><a href="#5.2">Binary Serialization</a></td> + </tr> + </table> + </td> + </tr> + + <tr> + <th></th><td><a href="#A">Appendix A — Default and Fixed Values</a></td> + </tr> + + </table> + </div> + + <h1><a name="0">Preface</a></h1> + + <h2><a name="0.1">About This Document</a></h2> + + <p>This document describes the mapping of W3C XML Schema + to the C++ programming language as implemented by + <a href="https://www.codesynthesis.com/products/xsd">CodeSynthesis + XSD</a> - an XML Schema to C++ data binding compiler. The mapping + represents information stored in XML instance documents as a + statically-typed, tree-like in-memory data structure and is + called C++/Tree. + </p> + + <p>Revision 4.1.0<br/> <!-- Remember to change revision in other places --> + This revision of the manual describes the C++/Tree + mapping as implemented by CodeSynthesis XSD version 4.1.0. + </p> + + <p>This document is available in the following formats: + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/index.xhtml">XHTML</a>, + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.pdf">PDF</a>, and + <a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.ps">PostScript</a>.</p> + + <h2><a name="0.2">More Information</a></h2> + + <p>Beyond this manual, you may also find the following sources of + information useful:</p> + + <ul class="list"> + <li><a href="https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/">C++/Tree + Mapping Getting Started Guide</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/Customization_guide">C++/Tree + Mapping Customization Guide</a></li> + + <li><a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree + Mapping Frequently Asked Questions (FAQ)</a></li> + + <li><a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a></li> + + <li>The <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + contains a collection of examples and a README file with an overview + of each example.</li> + + <li>The <code>README</code> file in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> package + explains how to build the examples.</li> + + <li>The <a href="https://www.codesynthesis.com/mailman/listinfo/xsd-users">xsd-users</a> + mailing list is a place to ask questions. Furthermore the + <a href="https://www.codesynthesis.com/pipermail/xsd-users/">archives</a> + may already have answers to some of your questions.</li> + </ul> + + + <h1><a name="1">1 Introduction</a></h1> + + <p>C++/Tree is a W3C XML Schema to C++ mapping that represents the + data stored in XML as a statically-typed, vocabulary-specific + object model. Based on a formal description of an XML vocabulary + (schema), the C++/Tree mapping produces a tree-like data structure + suitable for in-memory processing as well as XML parsing and + serialization code.</p> + + <p>A typical application that processes XML documents usually + performs the following three steps: it first reads (parses) an XML + instance document to an object model, it then performs + some useful computations on that model which may involve + modification of the model, and finally it may write (serialize) + the modified object model back to XML. + </p> + + <p>The C++/Tree mapping consists of C++ types that represent the + given vocabulary (<a href="#2">Chapter 2, "C++/Tree Mapping"</a>), + a set of parsing functions that convert XML documents to + a tree-like in-memory data structure (<a href="#3">Chapter 3, + "Parsing"</a>), and a set of serialization functions that convert + the object model back to XML (<a href="#4">Chapter 4, + "Serialization"</a>). Furthermore, the mapping provides a number + of additional features, such as DOM association and binary + serialization, that can be useful in some applications + (<a href="#5">Chapter 5, "Additional Functionality"</a>). + </p> + + + <!-- Chapter 2 --> + + + <h1><a name="2">2 C++/Tree Mapping</a></h1> + + <h2><a name="2.1">2.1 Preliminary Information</a></h2> + + <h3><a name="2.1.1">2.1.1 C++ Standard</a></h3> + + <p>The C++/Tree mapping provides support for ISO/IEC C++ 2011 (C++11) + and ISO/IEC C++ 1998/2003 (C++98). To select the C++ standard for the + generated code we use the <code>--std</code> XSD compiler command + line option. While the majority of the examples in this guide use + C++11, the document explains the C++11/98 usage difference and so + they can easily be converted to C++98.</p> + + <h3><a name="2.1.2">2.1.2 Identifiers</a></h3> + + <p>XML Schema names may happen to be reserved C++ keywords or contain + characters that are illegal in C++ identifiers. To avoid C++ compilation + problems, such names are changed (escaped) when mapped to C++. If an + XML Schema name is a C++ keyword, the "_" suffix is added to it. All + character of an XML Schema name that are not allowed in C++ identifiers + are replaced with "_". + </p> + + <p>For example, XML Schema name <code>try</code> will be mapped to + C++ identifier <code>try_</code>. Similarly, XML Schema name + <code>strange.na-me</code> will be mapped to C++ identifier + <code>strange_na_me</code>. + </p> + + <p>Furthermore, conflicts between type names and function names in the + same scope are resolved using name escaping. Such conflicts include + both a global element (which is mapped to a set of parsing and/or + serialization functions or element types, see <a href="#2.9">Section + 2.9, "Mapping for Global Elements"</a>) and a global type sharing the + same name as well as a local element or attribute inside a type having + the same name as the type itself.</p> + + <p>For example, if we had a global type <code>catalog</code> + and a global element with the same name then the type would be + mapped to a C++ class with name <code>catalog</code> while the + parsing functions corresponding to the global element would have + their names escaped as <code>catalog_</code>. + </p> + + <p>By default the mapping uses the so-called K&R (Kernighan and + Ritchie) identifier naming convention which is also used throughout + this manual. In this convention both type and function names are in + lower case and words are separated by underscores. If your application + code or schemas use a different notation, you may want to change the + naming convention used by the mapping for consistency. + The compiler supports a set of widely-used naming conventions + that you can select with the <code>--type-naming</code> and + <code>--function-naming</code> options. You can also further + refine one of the predefined conventions or create a completely + custom naming scheme by using the <code>--*-regex</code> options. + For more detailed information on these options refer to the NAMING + CONVENTION section in the <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>.</p> + + <h3><a name="2.1.3">2.1.3 Character Type and Encoding</a></h3> + + <p>The code that implements the mapping, depending on the + <code>--char-type</code> option, is generated using either + <code>char</code> or <code>wchar_t</code> as the character + type. In this document code samples use symbol <code>C</code> + to refer to the character type you have selected when translating + your schemas, for example <code>std::basic_string<C></code>. + </p> + + <p>Another aspect of the mapping that depends on the character type + is character encoding. For the <code>char</code> character type + the default encoding is UTF-8. Other supported encodings are + ISO-8859-1, Xerces-C++ Local Code Page (LPC), as well as + custom encodings and can be selected with the + <code>--char-encoding</code> command line option.</p> + + <p>For the <code>wchar_t</code> character type the encoding is + automatically selected between UTF-16 and UTF-32/UCS-4 depending + on the size of the <code>wchar_t</code> type. On some platforms + (for example, Windows with Visual C++ and AIX with IBM XL C++) + <code>wchar_t</code> is 2 bytes long. For these platforms the + encoding is UTF-16. On other platforms <code>wchar_t</code> is 4 bytes + long and UTF-32/UCS-4 is used.</p> + + <h3><a name="2.1.4">2.1.4 XML Schema Namespace</a></h3> + + <p>The mapping relies on some predefined types, classes, and functions + that are logically defined in the XML Schema namespace reserved for + the XML Schema language (<code>http://www.w3.org/2001/XMLSchema</code>). + By default, this namespace is mapped to C++ namespace + <code>xml_schema</code>. It is automatically accessible + from a C++ compilation unit that includes a header file generated + from an XML Schema definition. + </p> + + <p>Note that, if desired, the default mapping of this namespace can be + changed as described in <a href="#2.4">Section 2.4, "Mapping for + Namespaces"</a>. + </p> + + + <h3><a name="2.1.5">2.1.5 Anonymous Types</a></h3> + + <p>For the purpose of code generation, anonymous types defined in + XML Schema are automatically assigned names that are derived + from enclosing attributes and elements. Otherwise, such types + follows standard mapping rules for simple and complex type + definitions (see <a href="#2.6">Section 2.6, "Mapping for Simple Types"</a> + and <a href="#2.7">Section 2.7, "Mapping for Complex Types"</a>). + For example, in the following schema fragment: + </p> + + <pre class="xml"> +<element name="object"> + <complexType> + ... + </complexType> +</element> + </pre> + + <p>The anonymous type defined inside element <code>object</code> will + be given name <code>object</code>. The compiler has a number of + options that control the process of anonymous type naming. For more + information refer to the <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a>.</p> + + + <h2><a name="2.2">2.2 Error Handling</a></h2> + + <p>The mapping uses the C++ exception handling mechanism as a primary way + of reporting error conditions. All exceptions that are specified in + this mapping derive from <code>xml_schema::exception</code> which + itself is derived from <code>std::exception</code>: + </p> + + <pre class="c++"> +struct exception: virtual std::exception +{ + friend + std::basic_ostream<C>& + operator<< (std::basic_ostream<C>& os, const exception& e) + { + e.print (os); + return os; + } + +protected: + virtual void + print (std::basic_ostream<C>&) const = 0; +}; + </pre> + + <p>The exception hierarchy supports "virtual" <code>operator<<</code> + which allows you to obtain diagnostics corresponding to the thrown + exception using the base exception interface. For example:</p> + + <pre class="c++"> +try +{ + ... +} +catch (const xml_schema::exception& e) +{ + cerr << e << endl; +} + </pre> + + <p>The following sub-sections describe exceptions thrown by the + types that constitute the object model. + <a href="#3.3">Section 3.3, "Error Handling"</a> of + <a href="#3">Chapter 3, "Parsing"</a> describes exceptions + and error handling mechanisms specific to the parsing functions. + <a href="#4.4">Section 4.4, "Error Handling"</a> of + <a href="#4">Chapter 4, "Serialization"</a> describes exceptions + and error handling mechanisms specific to the serialization functions. + </p> + + + <h3><a name="2.2.1">2.2.1 <code>xml_schema::duplicate_id</code></a></h3> + + <pre class="c++"> +struct duplicate_id: virtual exception +{ + duplicate_id (const std::basic_string<C>& id); + + const std::basic_string<C>& + id () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::duplicate_id</code> is thrown when + a conflicting instance of <code>xml_schema::id</code> (see + <a href="#2.5">Section 2.5, "Mapping for Built-in Data Types"</a>) + is added to a tree. The offending ID value can be obtained using + the <code>id</code> function. + </p> + + <h2><a name="2.3">2.3 Mapping for <code>import</code> and <code>include</code></a></h2> + + <h3><a name="2.3.1">2.3.1 Import</a></h3> + + <p>The XML Schema <code>import</code> element is mapped to the C++ + Preprocessor <code>#include</code> directive. The value of + the <code>schemaLocation</code> attribute is used to derive + the name of the header file that appears in the <code>#include</code> + directive. For instance: + </p> + + <pre class="xml"> +<import namespace="https://www.codesynthesis.com/test" + schemaLocation="test.xsd"/> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +#include "test.hxx" + </pre> + + <p>Note that you will need to compile imported schemas separately + in order to produce corresponding header files.</p> + + <h3><a name="2.3.2">2.3.2 Inclusion with Target Namespace</a></h3> + + <p>The XML Schema <code>include</code> element which refers to a schema + with a target namespace or appears in a schema without a target namespace + follows the same mapping rules as the <code>import</code> element, + see <a href="#2.3.1">Section 2.3.1, "Import"</a>. + </p> + + <h3><a name="2.3.3">2.3.3 Inclusion without Target Namespace</a></h3> + + <p>For the XML Schema <code>include</code> element which refers to a schema + without a target namespace and appears in a schema with a target + namespace (such inclusion sometimes called "chameleon inclusion"), + declarations and definitions from the included schema are generated + in-line in the namespace of the including schema as if they were + declared and defined there verbatim. For example, consider the + following two schemas: + </p> + + <pre class="xml"> +<-- common.xsd --> +<schema> + <complexType name="type"> + ... + </complexType> +</schema> + +<-- test.xsd --> +<schema targetNamespace="https://www.codesynthesis.com/test"> + <include schemaLocation="common.xsd"/> +</schema> + </pre> + + <p>The fragment of interest from the generated header file for + <code>text.xsd</code> would look like this:</p> + + <pre class="c++"> +// test.hxx +namespace test +{ + class type + { + ... + }; +} + </pre> + + <h2><a name="2.4">2.4 Mapping for Namespaces</a></h2> + + <p>An XML Schema namespace is mapped to one or more nested C++ + namespaces. XML Schema namespaces are identified by URIs. + 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 instance: + </p> + + <pre class="xml"> +<schema targetNamespace="https://www.codesynthesis.com/system/test"> + ... +</schema> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +namespace system +{ + namespace test + { + ... + } +} + </pre> + + <p>The default mapping of namespace URIs to C++ namespace names can be + altered using the <code>--namespace-map</code> and + <code>--namespace-regex</code> options. See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information. + </p> + + <h2><a name="2.5">2.5 Mapping for Built-in Data Types</a></h2> + + <p>The mapping of XML Schema built-in data types to C++ types is + summarized in the table below.</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">anyType and anySimpleType types</th> + </tr> + <tr> + <td><code>anyType</code></td> + <td><code>type</code></td> + <td><a href="#2.5.2">Section 2.5.2, "Mapping for <code>anyType</code>"</a></td> + </tr> + <tr> + <td><code>anySimpleType</code></td> + <td><code>simple_type</code></td> + <td><a href="#2.5.3">Section 2.5.3, "Mapping for <code>anySimpleType</code>"</a></td> + </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 long</code></td> + </tr> + <tr> + <td><code>unsignedLong</code></td> + <td><code>unsigned_long</code></td> + <td><code>unsigned long long</code></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 long</code></td> + </tr> + <tr> + <td><code>nonPositiveInteger</code></td> + <td><code>non_positive_integer</code></td> + <td><code>long long</code></td> + </tr> + <tr> + <td><code>nonNegativeInteger</code></td> + <td><code>non_negative_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>positiveInteger</code></td> + <td><code>positive_integer</code></td> + <td><code>unsigned long long</code></td> + </tr> + <tr> + <td><code>negativeInteger</code></td> + <td><code>negative_integer</code></td> + <td><code>long 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>type derived from <code>std::basic_string</code></td> + </tr> + <tr> + <td><code>normalizedString</code></td> + <td><code>normalized_string</code></td> + <td>type derived from <code>string</code></td> + </tr> + <tr> + <td><code>token</code></td> + <td><code>token</code></td> + <td>type derived from <code>normalized_string</code></td> + </tr> + <tr> + <td><code>Name</code></td> + <td><code>name</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKEN</code></td> + <td><code>nmtoken</code></td> + <td>type derived from <code>token</code></td> + </tr> + <tr> + <td><code>NMTOKENS</code></td> + <td><code>nmtokens</code></td> + <td>type derived from <code>sequence<nmtoken></code></td> + </tr> + <tr> + <td><code>NCName</code></td> + <td><code>ncname</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>language</code></td> + <td><code>language</code></td> + <td>type derived from <code>token</code></td> + </tr> + + <tr> + <th colspan="3">qualified name</th> + </tr> + <tr> + <td><code>QName</code></td> + <td><code>qname</code></td> + <td><a href="#2.5.4">Section 2.5.4, "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>type derived from <code>ncname</code></td> + </tr> + <tr> + <td><code>IDREF</code></td> + <td><code>idref</code></td> + <td><a href="#2.5.5">Section 2.5.5, "Mapping for <code>IDREF</code>"</a></td> + </tr> + <tr> + <td><code>IDREFS</code></td> + <td><code>idrefs</code></td> + <td>type derived from <code>sequence<idref></code></td> + </tr> + + <tr> + <th colspan="3">URI types</th> + </tr> + <tr> + <td><code>anyURI</code></td> + <td><code>uri</code></td> + <td>type derived from <code>std::basic_string</code></td> + </tr> + + <tr> + <th colspan="3">binary types</th> + </tr> + <tr> + <td><code>base64Binary</code></td> + <td><code>base64_binary</code></td> + <td rowspan="2"><a href="#2.5.6">Section 2.5.6, "Mapping for + <code>base64Binary</code> and <code>hexBinary</code>"</a></td> + </tr> + <tr> + <td><code>hexBinary</code></td> + <td><code>hex_binary</code></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="#2.5.8">Section 2.5.8, "Mapping for + <code>date</code>"</a></td> + </tr> + <tr> + <td><code>dateTime</code></td> + <td><code>date_time</code></td> + <td><a href="#2.5.9">Section 2.5.9, "Mapping for + <code>dateTime</code>"</a></td> + </tr> + <tr> + <td><code>duration</code></td> + <td><code>duration</code></td> + <td><a href="#2.5.10">Section 2.5.10, "Mapping for + <code>duration</code>"</a></td> + </tr> + <tr> + <td><code>gDay</code></td> + <td><code>gday</code></td> + <td><a href="#2.5.11">Section 2.5.11, "Mapping for + <code>gDay</code>"</a></td> + </tr> + <tr> + <td><code>gMonth</code></td> + <td><code>gmonth</code></td> + <td><a href="#2.5.12">Section 2.5.12, "Mapping for + <code>gMonth</code>"</a></td> + </tr> + <tr> + <td><code>gMonthDay</code></td> + <td><code>gmonth_day</code></td> + <td><a href="#2.5.13">Section 2.5.13, "Mapping for + <code>gMonthDay</code>"</a></td> + </tr> + <tr> + <td><code>gYear</code></td> + <td><code>gyear</code></td> + <td><a href="#2.5.14">Section 2.5.14, "Mapping for + <code>gYear</code>"</a></td> + </tr> + <tr> + <td><code>gYearMonth</code></td> + <td><code>gyear_month</code></td> + <td><a href="#2.5.15">Section 2.5.15, "Mapping for + <code>gYearMonth</code>"</a></td> + </tr> + <tr> + <td><code>time</code></td> + <td><code>time</code></td> + <td><a href="#2.5.16">Section 2.5.16, "Mapping for + <code>time</code>"</a></td> + </tr> + + <tr> + <th colspan="3">entity types</th> + </tr> + <tr> + <td><code>ENTITY</code></td> + <td><code>entity</code></td> + <td>type derived from <code>name</code></td> + </tr> + <tr> + <td><code>ENTITIES</code></td> + <td><code>entities</code></td> + <td>type derived from <code>sequence<entity></code></td> + </tr> + </table> + + <p>All XML Schema built-in types are mapped to C++ classes that are + derived from the <code>xml_schema::simple_type</code> class except + where the mapping is to a fundamental C++ type.</p> + + <p>The <code>sequence</code> class template is defined in an + implementation-specific namespace. It conforms to the + sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences"). + Practically, this means that you can treat such a sequence + as if it was <code>std::vector</code>. One notable extension + to the standard interface that is available only for + sequences of non-fundamental C++ types is the addition of + the overloaded <code>push_back</code> and <code>insert</code> + member functions which instead of the constant reference + to the element type accept automatic pointer (<code>std::unique_ptr</code> + or <code>std::auto_ptr</code>, depending on the C++ standard + selected) to the element type. These functions assume ownership + of the pointed to object and reset the passed automatic pointer. + </p> + + <h3><a name="2.5.1">2.5.1 Inheritance from Built-in Data Types</a></h3> + + <p>In cases where the mapping calls for an inheritance from a built-in + type which is mapped to a fundamental C++ type, a proxy type is + used instead of the fundamental C++ type (C++ does not allow + inheritance from fundamental types). For instance:</p> + + <pre class="xml"> +<simpleType name="my_int"> + <restriction base="int"/> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class my_int: public fundamental_base<int> +{ + ... +}; + </pre> + + <p>The <code>fundamental_base</code> class template provides a close + emulation (though not exact) of a fundamental C++ type. + It is defined in an implementation-specific namespace and has the + following interface:</p> + + <pre class="c++"> +template <typename X> +class fundamental_base: public simple_type +{ +public: + fundamental_base (); + fundamental_base (X) + fundamental_base (const fundamental_base&) + +public: + fundamental_base& + operator= (const X&); + +public: + operator const X & () const; + operator X& (); + + template <typename Y> + operator Y () const; + + template <typename Y> + operator Y (); +}; + </pre> + + <h3><a name="2.5.2">2.5.2 Mapping for <code>anyType</code></a></h3> + + <p>The XML Schema <code>anyType</code> built-in data type is mapped to the + <code>xml_schema::type</code> C++ class:</p> + + <pre class="c++"> +class type +{ +public: + virtual + ~type (); + + type (); + type (const type&); + + type& + operator= (const type&); + + virtual type* + _clone () const; + + // anyType DOM content. + // +public: + typedef element_optional dom_content_optional; + + const dom_content_optional& + dom_content () const; + + dom_content_optional& + dom_content (); + + void + dom_content (const xercesc::DOMElement&); + + void + dom_content (xercesc::DOMElement*); + + void + dom_content (const dom_content_optional&); + + const xercesc::DOMDocument& + dom_content_document () const; + + xercesc::DOMDocument& + dom_content_document (); + + bool + null_content () const; + + // DOM association. + // +public: + const xercesc::DOMNode* + _node () const; + + xercesc::DOMNode* + _node (); +}; + </pre> + + <p>When <code>xml_schema::type</code> is used to create an instance + (as opposed to being a base of a derived type), it represents + the XML Schema <code>anyType</code> type. <code>anyType</code> + allows any attributes and any content in any order. In the + C++/Tree mapping this content can be represented as a DOM + fragment, similar to XML Schema wildcards (<a href="#2.12">Section + 2.12, "Mapping for <code>any</code> and + <code>anyAttribute</code>"</a>).</p> + + <p>To enable automatic extraction of <code>anyType</code> content + during parsing, the <code>--generate-any-type</code> option must be + specified. Because the DOM API is used to access such content, the + Xerces-C++ runtime should be initialized by the application prior to + parsing and should remain initialized for the lifetime of objects + with the DOM content. For more information on the Xerces-C++ runtime + initialization see <a href="#3.1">Section 3.1, "Initializing the + Xerces-C++ Runtime"</a>.</p> + + <p>The DOM content is stored as the optional DOM element container + and the DOM content accessors and modifiers presented above are + identical to those generated for an optional element wildcard. + Refer to <a href="#2.12.2">Section 2.12.2, "Mapping for <code>any</code> + with the Optional Cardinality Class"</a> for details on their + semantics.</p> + + <p>The <code>dom_content_document()</code> function returns the + DOM document used to store the raw XML content corresponding + to the <code>anyType</code> instance. It is equivalent to the + <code>dom_document()</code> function generated for types + with wildcards.</p> + + <p>The <code>null_content()</code> accessor is an optimization function + that allows us to check for the lack of content without actually + creating its empty representation, that is, empty DOM document for + <code>anyType</code> or empty string for <code>anySimpleType</code> + (see the following section for details on <code>anySimpleType</code>).</p> + + <p>For more information on DOM association refer to + <a href="#5.1">Section 5.1, "DOM Association"</a>.</p> + + <h3><a name="2.5.3">2.5.3 Mapping for <code>anySimpleType</code></a></h3> + + <p>The XML Schema <code>anySimpleType</code> built-in data type is mapped + to the <code>xml_schema::simple_type</code> C++ class:</p> + + <pre class="c++"> +class simple_type: public type +{ +public: + simple_type (); + simple_type (const C*); + simple_type (const std::basic_string<C>&); + + simple_type (const simple_type&); + + simple_type& + operator= (const simple_type&); + + virtual simple_type* + _clone () const; + + // anySimpleType text content. + // +public: + const std::basic_string<C>& + text_content () const; + + std::basic_string<C>& + text_content (); + + void + text_content (const std::basic_string<C>&); +}; + </pre> + + <p>When <code>xml_schema::simple_type</code> is used to create an instance + (as opposed to being a base of a derived type), it represents + the XML Schema <code>anySimpleType</code> type. <code>anySimpleType</code> + allows any simple content. In the C++/Tree mapping this content can + be represented as a string and accessed or modified with the + <code>text_content()</code> functions shown above.</p> + + <h3><a name="2.5.4">2.5.4 Mapping for <code>QName</code></a></h3> + + <p>The XML Schema <code>QName</code> built-in data type is mapped to the + <code>xml_schema::qname</code> C++ class:</p> + + <pre class="c++"> +class qname: public simple_type +{ +public: + qname (const ncname&); + qname (const uri&, const ncname&); + qname (const qname&); + +public: + qname& + operator= (const qname&); + +public: + virtual qname* + _clone () const; + +public: + bool + qualified () const; + + const uri& + namespace_ () const; + + const ncname& + name () const; +}; + </pre> + + <p>The <code>qualified</code> accessor function can be used to determine + if the name is qualified.</p> + + <h3><a name="2.5.5">2.5.5 Mapping for <code>IDREF</code></a></h3> + + <p>The XML Schema <code>IDREF</code> built-in data type is mapped to the + <code>xml_schema::idref</code> C++ class. This class implements the + smart pointer C++ idiom:</p> + + <pre class="c++"> +class idref: public ncname +{ +public: + idref (const C* s); + idref (const C* s, std::size_t n); + idref (std::size_t n, C c); + idref (const std::basic_string<C>&); + idref (const std::basic_string<C>&, + std::size_t pos, + std::size_t n = npos); + +public: + idref (const idref&); + +public: + virtual idref* + _clone () const; + +public: + idref& + operator= (C c); + + idref& + operator= (const C* s); + + idref& + operator= (const std::basic_string<C>&) + + idref& + operator= (const idref&); + +public: + const type* + operator-> () const; + + type* + operator-> (); + + const type& + operator* () const; + + type& + operator* (); + + const type* + get () const; + + type* + get (); + + // Conversion to bool. + // +public: + typedef void (idref::*bool_convertible)(); + operator bool_convertible () const; +}; + </pre> + + <p>The object, <code>idref</code> instance refers to, is the immediate + container of the matching <code>id</code> instance. For example, + with the following instance document and schema: + </p> + + + <pre class="xml"> +<!-- test.xml --> +<root> + <object id="obj-1" text="hello"/> + <reference>obj-1</reference> +</root> + +<!-- test.xsd --> +<schema> + <complexType name="object_type"> + <attribute name="id" type="ID"/> + <attribute name="text" type="string"/> + </complexType> + + <complexType name="root_type"> + <sequence> + <element name="object" type="object_type"/> + <element name="reference" type="IDREF"/> + </sequence> + </complexType> + + <element name="root" type="root_type"/> +</schema> + </pre> + + <p>The <code>ref</code> instance in the code below will refer to + an object of type <code>object_type</code>:</p> + + <pre class="c++"> +root_type& root = ...; +xml_schema::idref& ref (root.reference ()); +object_type& obj (dynamic_cast<object_type&> (*ref)); +cout << obj.text () << endl; + </pre> + + <p>The smart pointer interface of the <code>idref</code> class always + returns a pointer or reference to <code>xml_schema::type</code>. + This means that you will need to manually cast such pointer or + reference to its real (dynamic) type before you can use it (unless + all you need is the base interface provided by + <code>xml_schema::type</code>). As a special extension to the XML + Schema language, the mapping supports static typing of <code>idref</code> + references by employing the <code>refType</code> extension attribute. + The following example illustrates this mechanism: + </p> + + <pre class="xml"> +<!-- test.xsd --> +<schema + xmlns:xse="https://www.codesynthesis.com/xmlns/xml-schema-extension"> + + ... + + <element name="reference" type="IDREF" xse:refType="object_type"/> + + ... + +</schema> + </pre> + + <p>With this modification we do not need to do manual casting anymore: + </p> + + <pre class="c++"> +root_type& root = ...; +root_type::reference_type& ref (root.reference ()); +object_type& obj (*ref); +cout << ref->text () << endl; + </pre> + + + <h3><a name="2.5.6">2.5.6 Mapping for <code>base64Binary</code> and + <code>hexBinary</code></a></h3> + + <p>The XML Schema <code>base64Binary</code> and <code>hexBinary</code> + built-in data types are mapped to the + <code>xml_schema::base64_binary</code> and + <code>xml_schema::hex_binary</code> C++ classes, respectively. The + <code>base64_binary</code> and <code>hex_binary</code> classes + support a simple buffer abstraction by inheriting from the + <code>xml_schema::buffer</code> class: + </p> + + <pre class="c++"> +class bounds: public virtual exception +{ +public: + virtual const char* + what () const throw (); +}; + +class buffer +{ +public: + typedef std::size_t size_t; + +public: + buffer (size_t size = 0); + buffer (size_t size, size_t capacity); + buffer (const void* data, size_t size); + buffer (const void* data, size_t size, size_t capacity); + buffer (void* data, + size_t size, + size_t capacity, + bool assume_ownership); + +public: + buffer (const buffer&); + + buffer& + operator= (const buffer&); + + 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 (); +}; + </pre> + + <p>The last overloaded constructor reuses an existing data buffer instead + of making a copy. If the <code>assume_ownership</code> argument is + <code>true</code>, the instance assumes ownership of the + memory block pointed to by the <code>data</code> argument and will + eventually release it by calling <code>operator delete</code>. The + <code>capacity</code> and <code>size</code> modifier functions return + <code>true</code> if the underlying buffer has moved. + </p> + + <p>The <code>bounds</code> exception is thrown if the constructor + arguments violate the <code>(size <= capacity)</code> + constraint.</p> + + <p>The <code>base64_binary</code> and <code>hex_binary</code> classes + support the <code>buffer</code> interface and perform automatic + decoding/encoding from/to the Base64 and Hex formats, respectively: + </p> + + <pre class="c++"> +class base64_binary: public simple_type, public buffer +{ +public: + base64_binary (size_t size = 0); + base64_binary (size_t size, size_t capacity); + base64_binary (const void* data, size_t size); + base64_binary (const void* data, size_t size, size_t capacity); + base64_binary (void* data, + size_t size, + size_t capacity, + bool assume_ownership); + +public: + base64_binary (const base64_binary&); + + base64_binary& + operator= (const base64_binary&); + + virtual base64_binary* + _clone () const; + +public: + std::basic_string<C> + encode () const; +}; + </pre> + + <pre class="c++"> +class hex_binary: public simple_type, public buffer +{ +public: + hex_binary (size_t size = 0); + hex_binary (size_t size, size_t capacity); + hex_binary (const void* data, size_t size); + hex_binary (const void* data, size_t size, size_t capacity); + hex_binary (void* data, + size_t size, + size_t capacity, + bool assume_ownership); + +public: + hex_binary (const hex_binary&); + + hex_binary& + operator= (const hex_binary&); + + virtual hex_binary* + _clone () const; + +public: + std::basic_string<C> + encode () const; +}; + </pre> + + + <h2><a name="2.5.7">2.5.7 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>xml_schema::time_zone</code> base class is used to represent + this information:</p> + + <pre class="c++"> +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 <em>not specified</em> + state. If the time zone offset is negative then both hours and + minutes components are represented as negative integers.</p> + + + <h2><a name="2.5.8">2.5.8 Mapping for <code>date</code></a></h2> + + <p>The XML Schema <code>date</code> built-in data type is mapped to the + <code>xml_schema::date</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class date: public simple_type, public time_zone +{ +public: + date (int year, unsigned short month, unsigned short day); + date (int year, unsigned short month, unsigned short day, + short zone_hours, short zone_minutes); + +public: + date (const date&); + + date& + operator= (const date&); + + virtual date* + _clone () const; + +public: + 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="2.5.9">2.5.9 Mapping for <code>dateTime</code></a></h2> + + <p>The XML Schema <code>dateTime</code> built-in data type is mapped to the + <code>xml_schema::date_time</code> C++ 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="#2.5.7">Section + 2.5.7, "Time Zone Representation"</a>.</p> + + <pre class="c++"> +class date_time: public simple_type, public time_zone +{ +public: + 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); +public: + date_time (const date_time&); + + date_time& + operator= (const date_time&); + + virtual date_time* + _clone () const; + +public: + 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="2.5.10">2.5.10 Mapping for <code>duration</code></a></h2> + + <p>The XML Schema <code>duration</code> built-in data type is mapped to the + <code>xml_schema::duration</code> C++ 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++"> +class duration: public simple_type +{ +public: + duration (bool negative, + unsigned int years, unsigned int months, unsigned int days, + unsigned int hours, unsigned int minutes, double seconds); +public: + duration (const duration&); + + duration& + operator= (const duration&); + + virtual duration* + _clone () const; + +public: + 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="2.5.11">2.5.11 Mapping for <code>gDay</code></a></h2> + + <p>The XML Schema <code>gDay</code> built-in data type is mapped to the + <code>xml_schema::gday</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gday: public simple_type, public time_zone +{ +public: + explicit + gday (unsigned short day); + gday (unsigned short day, short zone_hours, short zone_minutes); + +public: + gday (const gday&); + + gday& + operator= (const gday&); + + virtual gday* + _clone () const; + +public: + unsigned short + day () const; + + void + day (unsigned short); +}; + +bool +operator== (const gday&, const gday&); + +bool +operator!= (const gday&, const gday&); + </pre> + + + <h2><a name="2.5.12">2.5.12 Mapping for <code>gMonth</code></a></h2> + + <p>The XML Schema <code>gMonth</code> built-in data type is mapped to the + <code>xml_schema::gmonth</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gmonth: public simple_type, public time_zone +{ +public: + explicit + gmonth (unsigned short month); + gmonth (unsigned short month, + short zone_hours, short zone_minutes); + +public: + gmonth (const gmonth&); + + gmonth& + operator= (const gmonth&); + + virtual gmonth* + _clone () const; + +public: + unsigned short + month () const; + + void + month (unsigned short); +}; + +bool +operator== (const gmonth&, const gmonth&); + +bool +operator!= (const gmonth&, const gmonth&); + </pre> + + + <h2><a name="2.5.13">2.5.13 Mapping for <code>gMonthDay</code></a></h2> + + <p>The XML Schema <code>gMonthDay</code> built-in data type is mapped to the + <code>xml_schema::gmonth_day</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gmonth_day: public simple_type, public time_zone +{ +public: + gmonth_day (unsigned short month, unsigned short day); + gmonth_day (unsigned short month, unsigned short day, + short zone_hours, short zone_minutes); + +public: + gmonth_day (const gmonth_day&); + + gmonth_day& + operator= (const gmonth_day&); + + virtual gmonth_day* + _clone () const; + +public: + 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="2.5.14">2.5.14 Mapping for <code>gYear</code></a></h2> + + <p>The XML Schema <code>gYear</code> built-in data type is mapped to the + <code>xml_schema::gyear</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone Representation"</a>.</p> + + <pre class="c++"> +class gyear: public simple_type, public time_zone +{ +public: + explicit + gyear (int year); + gyear (int year, short zone_hours, short zone_minutes); + +public: + gyear (const gyear&); + + gyear& + operator= (const gyear&); + + virtual gyear* + _clone () const; + +public: + int + year () const; + + void + year (int); +}; + +bool +operator== (const gyear&, const gyear&); + +bool +operator!= (const gyear&, const gyear&); + </pre> + + + <h2><a name="2.5.15">2.5.15 Mapping for <code>gYearMonth</code></a></h2> + + <p>The XML Schema <code>gYearMonth</code> built-in data type is mapped to + the <code>xml_schema::gyear_month</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +class gyear_month: public simple_type, public time_zone +{ +public: + gyear_month (int year, unsigned short month); + gyear_month (int year, unsigned short month, + short zone_hours, short zone_minutes); +public: + gyear_month (const gyear_month&); + + gyear_month& + operator= (const gyear_month&); + + virtual gyear_month* + _clone () const; + +public: + 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="2.5.16">2.5.16 Mapping for <code>time</code></a></h2> + + <p>The XML Schema <code>time</code> built-in data type is mapped to + the <code>xml_schema::time</code> C++ 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="#2.5.7">Section 2.5.7, "Time Zone Representation"</a>.</p> + + <pre class="c++"> +class time: public simple_type, public time_zone +{ +public: + time (unsigned short hours, unsigned short minutes, double seconds); + time (unsigned short hours, unsigned short minutes, double seconds, + short zone_hours, short zone_minutes); + +public: + time (const time&); + + time& + operator= (const time&); + + virtual time* + _clone () const; + +public: + 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> + + + <!-- Mapping for Simple Types --> + + <h2><a name="2.6">2.6 Mapping for Simple Types</a></h2> + + <p>An XML Schema simple type is mapped to a C++ class with the same + name as the simple type. The class defines a public copy constructor, + a public copy assignment operator, and a public virtual + <code>_clone</code> function. The <code>_clone</code> function is + declared <code>const</code>, does not take any arguments, and returns + a pointer to a complete copy of the instance allocated in the free + store. The <code>_clone</code> function shall be used to make copies + when static type and dynamic type of the instance may differ (see + <a href="#2.11">Section 2.11, "Mapping for <code>xsi:type</code> + and Substitution Groups"</a>). For instance:</p> + + <pre class="xml"> +<simpleType name="object"> + ... +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: ... +{ +public: + object (const object&); + +public: + object& + operator= (const object&); + +public: + virtual object* + _clone () const; + + ... + +}; + </pre> + + <p>The base class specification and the rest of the class definition + depend on the type of derivation used to define the simple type. </p> + + + <h3><a name="2.6.1">2.6.1 Mapping for Derivation by Restriction</a></h3> + + <p>XML Schema derivation by restriction is mapped to C++ public + inheritance. The base type of the restriction becomes the base + type for the resulting C++ class. In addition to the members described + in <a href="#2.6">Section 2.6, "Mapping for Simple Types"</a>, the + resulting C++ class defines a public constructor with the base type + as its single argument. For instance:</p> + + <pre class="xml"> +<simpleType name="object"> + <restriction base="base"> + ... + </restriction> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public base +{ +public: + object (const base&); + object (const object&); + +public: + object& + operator= (const object&); + +public: + virtual object* + _clone () const; +}; + </pre> + + + <h3><a name="2.6.2">2.6.2 Mapping for Enumerations</a></h3> + +<p>XML Schema restriction by enumeration is mapped to a C++ class + with semantics similar to C++ <code>enum</code>. Each XML Schema + enumeration element is mapped to a C++ enumerator with the + name derived from the <code>value</code> attribute and defined + in the class scope. In addition to the members + described in <a href="#2.6">Section 2.6, "Mapping for Simple Types"</a>, + the resulting C++ class defines a public constructor that can be called + with one of the enumerators as its single argument, a public constructor + that can be called with enumeration's base value as its single + argument, a public assignment operator that can be used to assign the + value of one of the enumerators, and a public implicit conversion + operator to the underlying C++ enum type.</p> + +<p>Furthermore, for string-based enumeration types, the resulting C++ + class defines a public constructor with a single argument of type + <code>const C*</code> and a public constructor with a single + argument of type <code>const std::basic_string<C>&</code>. + For instance:</p> + + <pre class="xml"> +<simpleType name="color"> + <restriction base="string"> + <enumeration value="red"/> + <enumeration value="green"/> + <enumeration value="blue"/> + </restriction> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class color: public xml_schema::string +{ +public: + enum value + { + red, + green, + blue + }; + +public: + color (value); + color (const C*); + color (const std::basic_string<C>&); + color (const xml_schema::string&); + color (const color&); + +public: + color& + operator= (value); + + color& + operator= (const color&); + +public: + virtual color* + _clone () const; + +public: + operator value () const; +}; + </pre> + + <h3><a name="2.6.3">2.6.3 Mapping for Derivation by List</a></h3> + + <p>XML Schema derivation by list is mapped to C++ public + inheritance from <code>xml_schema::simple_type</code> + (<a href="#2.5.3">Section 2.5.3, "Mapping for + <code>anySimpleType</code>"</a>) and a suitable sequence type. + The list item type becomes the element type of the sequence. + In addition to the members described in <a href="#2.6">Section 2.6, + "Mapping for Simple Types"</a>, the resulting C++ class defines + a public default constructor, a public constructor + with the first argument of type <code>size_type</code> and + the second argument of list item type that creates + a list object with the specified number of copies of the specified + element value, and a public constructor with the two arguments + of an input iterator type that creates a list object from an + iterator range. For instance: + </p> + + <pre class="xml"> +<simpleType name="int_list"> + <list itemType="int"/> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class int_list: public simple_type, + public sequence<int> +{ +public: + int_list (); + int_list (size_type n, int x); + + template <typename I> + int_list (const I& begin, const I& end); + int_list (const int_list&); + +public: + int_list& + operator= (const int_list&); + +public: + virtual int_list* + _clone () const; +}; + </pre> + + <p>The <code>sequence</code> class template is defined in an + implementation-specific namespace. It conforms to the + sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences"). + Practically, this means that you can treat such a sequence + as if it was <code>std::vector</code>. One notable extension + to the standard interface that is available only for + sequences of non-fundamental C++ types is the addition of + the overloaded <code>push_back</code> and <code>insert</code> + member functions which instead of the constant reference + to the element type accept automatic pointer (<code>std::unique_ptr</code> + or <code>std::auto_ptr</code>, depending on the C++ standard + selected) to the element type. These functions assume ownership + of the pointed to object and reset the passed automatic pointer. + </p> + + <h3><a name="2.6.4">2.6.4 Mapping for Derivation by Union</a></h3> + + <p>XML Schema derivation by union is mapped to C++ public + inheritance from <code>xml_schema::simple_type</code> + (<a href="#2.5.3">Section 2.5.3, "Mapping for + <code>anySimpleType</code>"</a>) and <code>std::basic_string<C></code>. + In addition to the members described in <a href="#2.6">Section 2.6, + "Mapping for Simple Types"</a>, the resulting C++ class defines a + public constructor with a single argument of type <code>const C*</code> + and a public constructor with a single argument of type + <code>const std::basic_string<C>&</code>. For instance: + </p> + + <pre class="xml"> +<simpleType name="int_string_union"> + <xsd:union memberTypes="xsd:int xsd:string"/> +</simpleType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class int_string_union: public simple_type, + public std::basic_string<C> +{ +public: + int_string_union (const C*); + int_string_union (const std::basic_string<C>&); + int_string_union (const int_string_union&); + +public: + int_string_union& + operator= (const int_string_union&); + +public: + virtual int_string_union* + _clone () const; +}; + </pre> + + <h2><a name="2.7">2.7 Mapping for Complex Types</a></h2> + + <p>An XML Schema complex type is mapped to a C++ class with the same + name as the complex type. The class defines a public copy constructor, + a public copy assignment operator, and a public virtual + <code>_clone</code> function. The <code>_clone</code> function is + declared <code>const</code>, does not take any arguments, and returns + a pointer to a complete copy of the instance allocated in the free + store. The <code>_clone</code> function shall be used to make copies + when static type and dynamic type of the instance may differ (see + <a href="#2.11">Section 2.11, "Mapping for <code>xsi:type</code> + and Substitution Groups"</a>).</p> + + <p>Additionally, the resulting C++ class + defines two public constructors that take an initializer for each + member of the complex type and all its base types that belongs to + the One cardinality class (see <a href="#2.8">Section 2.8, "Mapping + for Local Elements and Attributes"</a>). In the first constructor, + the arguments are passed as constant references and the newly created + instance is initialized with copies of the passed objects. In the + second constructor, arguments that are complex types (that is, + they themselves contain elements or attributes) are passed as + either <code>std::unique_ptr</code> (C++11) or <code>std::auto_ptr</code> + (C++98), depending on the C++ standard selected. In this case the newly + created instance is directly initialized with and assumes ownership + of the pointed to objects and the <code>std::[unique|auto]_ptr</code> + arguments are reset to <code>0</code>. For instance:</p> + + <pre class="xml"> +<complexType name="complex"> + <sequence> + <element name="a" type="int"/> + <element name="b" type="string"/> + </sequence> +</complexType> + +<complexType name="object"> + <sequence> + <element name="s-one" type="boolean"/> + <element name="c-one" type="complex"/> + <element name="optional" type="int" minOccurs="0"/> + <element name="sequence" type="string" maxOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class complex: public xml_schema::type +{ +public: + object (const int& a, const xml_schema::string& b); + object (const complex&); + +public: + object& + operator= (const complex&); + +public: + virtual complex* + _clone () const; + + ... + +}; + +class object: public xml_schema::type +{ +public: + object (const bool& s_one, const complex& c_one); + object (const bool& s_one, std::[unique|auto]_ptr<complex> c_one); + object (const object&); + +public: + object& + operator= (const object&); + +public: + virtual object* + _clone () const; + + ... + +}; + </pre> + + <p>Notice that the generated <code>complex</code> class does not + have the second (<code>std::[unique|auto]_ptr</code>) version of the + constructor since all its required members are of simple types.</p> + + <p>If an XML Schema complex type has an ultimate base which is an XML + Schema simple type then the resulting C++ class also defines a public + constructor that takes an initializer for the base type as well as + for each member of the complex type and all its base types that + belongs to the One cardinality class. For instance:</p> + + <pre class="xml"> +<complexType name="object"> + <simpleContent> + <extension base="date"> + <attribute name="lang" type="language" use="required"/> + </extension> + </simpleContent> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::string +{ +public: + object (const xml_schema::language& lang); + + object (const xml_schema::date& base, + const xml_schema::language& lang); + + ... + +}; + </pre> + + <p>Furthermore, for string-based XML Schema complex types, the resulting C++ + class also defines two public constructors with the first arguments + of type <code>const C*</code> and <code>std::basic_string<C>&</code>, + respectively, followed by arguments for each member of the complex + type and all its base types that belongs to the One cardinality + class. For enumeration-based complex types the resulting C++ + class also defines a public constructor with the first arguments + of the underlying enum type followed by arguments for each member + of the complex type and all its base types that belongs to the One + cardinality class. For instance:</p> + + <pre class="xml"> +<simpleType name="color"> + <restriction base="string"> + <enumeration value="red"/> + <enumeration value="green"/> + <enumeration value="blue"/> + </restriction> +</simpleType> + +<complexType name="object"> + <simpleContent> + <extension base="color"> + <attribute name="lang" type="language" use="required"/> + </extension> + </simpleContent> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class color: public xml_schema::string +{ +public: + enum value + { + red, + green, + blue + }; + +public: + color (value); + color (const C*); + color (const std::basic_string<C>&); + + ... + +}; + +class object: color +{ +public: + object (const color& base, + const xml_schema::language& lang); + + object (const color::value& base, + const xml_schema::language& lang); + + object (const C* base, + const xml_schema::language& lang); + + object (const std::basic_string<C>& base, + const xml_schema::language& lang); + + ... + +}; + </pre> + + <p>Additional constructors can be requested with the + <code>--generate-default-ctor</code> and + <code>--generate-from-base-ctor</code> options. See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for details.</p> + + <p>If an XML Schema complex type is not explicitly derived from any type, + the resulting C++ class is derived from <code>xml_schema::type</code>. + In cases where an XML Schema complex type is defined using derivation + by extension or restriction, the resulting C++ base class specification + depends on the type of derivation and is described in the subsequent + sections. + </p> + + <p>The mapping for elements and attributes that are defined in a complex + type is described in <a href="#2.8">Section 2.8, "Mapping for Local + Elements and Attributes"</a>. + </p> + + <h3><a name="2.7.1">2.7.1 Mapping for Derivation by Extension</a></h3> + + <p>XML Schema derivation by extension is mapped to C++ public + inheritance. The base type of the extension becomes the base + type for the resulting C++ class. + </p> + + <h3><a name="2.7.2">2.7.2 Mapping for Derivation by Restriction</a></h3> + + <p>XML Schema derivation by restriction is mapped to C++ public + inheritance. The base type of the restriction becomes the base + type for the resulting C++ class. XML Schema elements and + attributes defined within restriction do not result in any + definitions in the resulting C++ class. Instead, corresponding + (unrestricted) definitions are inherited from the base class. + In the future versions of this mapping, such elements and + attributes may result in redefinitions of accessors and + modifiers to reflect their restricted semantics. + </p> + + <!-- 2.8 Mapping for Local Elements and Attributes --> + + <h2><a name="2.8">2.8 Mapping for Local Elements and Attributes</a></h2> + + <p>XML Schema element and attribute definitions are called local + if they appear within a complex type definition, an element group + definition, or an attribute group definitions. + </p> + + <p>Local XML Schema element and attribute definitions have the same + C++ mapping. Therefore, in this section, local elements and + attributes are collectively called members. + </p> + + <p>While there are many different member cardinality combinations + (determined by the <code>use</code> attribute for attributes and + the <code>minOccurs</code> and <code>maxOccurs</code> attributes + for elements), the mapping divides all possible cardinality + combinations into three cardinality classes: + </p> + + <dl> + <dt><i>one</i></dt> + <dd>attributes: <code>use == "required"</code></dd> + <dd>attributes: <code>use == "optional"</code> and has default or fixed value</dd> + <dd>elements: <code>minOccurs == "1"</code> and <code>maxOccurs == "1"</code></dd> + + <dt><i>optional</i></dt> + <dd>attributes: <code>use == "optional"</code> and doesn't have default or fixed value</dd> + <dd>elements: <code>minOccurs == "0"</code> and <code>maxOccurs == "1"</code></dd> + + <dt><i>sequence</i></dt> + <dd>elements: <code>maxOccurs > "1"</code></dd> + </dl> + + <p>An optional attribute with a default or fixed value acquires this value + if the attribute hasn't been specified in an instance document (see + <a href="#A">Appendix A, "Default and Fixed Values"</a>). This + mapping places such optional attributes to the One cardinality + class.</p> + + <p>A member is mapped to a set of public type definitions + (<code>typedef</code>s) and a set of public accessor and modifier + functions. Type definitions have names derived from the member's + name. The accessor and modifier functions have the same name as the + member. For example: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + typedef xml_schema::string member_type; + + const member_type& + member () const; + + ... + +}; + </pre> + + <p>In addition, if a member has a default or fixed value, a static + accessor function is generated that returns this value. For + example:</p> + +<pre class="xml"> +<complexType name="object"> + <attribute name="data" type="string" default="test"/> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + typedef xml_schema::string data_type; + + const data_type& + data () const; + + static const data_type& + data_default_value (); + + ... + +}; + </pre> + + <p>Names and semantics of type definitions for the member as well + as signatures of the accessor and modifier functions depend on + the member's cardinality class and are described in the following + sub-sections. + </p> + + + <h3><a name="2.8.1">2.8.1 Mapping for Members with the One Cardinality Class</a></h3> + + <p>For the One cardinality class, the type definitions consist of + an alias for the member's type with the name created by appending + the <code>_type</code> suffix to the member's name. + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + member and can be used for read-only access. The non-constant + version returns an unrestricted reference to the member and can + be used for read-write access. + </p> + + <p>The first modifier function expects an argument of type reference to + constant of the member's type. It makes a deep copy of its argument. + Except for member's types that are mapped to fundamental C++ types, + the second modifier function is provided that expects an argument + of type automatic pointer (<code>std::unique_ptr</code> or + <code>std::auto_ptr</code>, depending on the C++ standard selected) + to the member's type. It assumes ownership of the pointed to object + and resets the passed automatic pointer. For instance:</p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef xml_schema::string member_type; + + // Accessors. + // + const member_type& + member () const; + + member_type& + member (); + + // Modifiers. + // + void + member (const member_type&); + + void + member (std::[unique|auto]_ptr<member_type>); + ... + +}; + </pre> + + <p>In addition, if requested by specifying the <code>--generate-detach</code> + option and only for members of non-fundamental C++ types, the mapping + provides a detach function that returns an automatic pointer to the + member's type, for example:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + ... + + std::[unique|auto]_ptr<member_type> + detach_member (); + ... + +}; + </pre> + + <p>This function detaches the value from the tree leaving the member + value uninitialized. Accessing such an uninitialized value prior to + re-initializing it results in undefined behavior.</p> + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o) +{ + using xml_schema::string; + + string s (o.member ()); // get + object::member_type& sr (o.member ()); // get + + o.member ("hello"); // set, deep copy + o.member () = "hello"; // set, deep copy + + // C++11 version. + // + std::unique_ptr<string> p (new string ("hello")); + o.member (std::move (p)); // set, assumes ownership + p = o.detach_member (); // detach, member is uninitialized + o.member (std::move (p)); // re-attach + + // C++98 version. + // + std::auto_ptr<string> p (new string ("hello")); + o.member (p); // set, assumes ownership + p = o.detach_member (); // detach, member is uninitialized + o.member (p); // re-attach +} + </pre> + + +<h3><a name="2.8.2">2.8.2 Mapping for Members with the Optional Cardinality Class</a></h3> + + <p>For the Optional cardinality class, the type definitions consist of + an alias for the member's type with the name created by appending + the <code>_type</code> suffix to the member's name and an alias for + the container type with the name created by appending the + <code>_optional</code> suffix to the member's name. + </p> + + <p>Unlike accessor functions for the One cardinality class, accessor + functions for the Optional cardinality class return references to + corresponding containers rather than directly to members. The + accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to + the container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container + and can be used for read-write access. + </p> + + <p>The modifier functions are overloaded for the member's + type and the container type. The first modifier function + expects an argument of type reference to constant of the + member's type. It makes a deep copy of its argument. + Except for member's types that are mapped to fundamental C++ types, + the second modifier function is provided that expects an argument + of type automatic pointer (<code>std::unique_ptr</code> or + <code>std::auto_ptr</code>, depending on the C++ standard selected) + to the member's type. It assumes ownership of the pointed to object + and resets the passed automatic pointer. The last modifier function + expects an argument of type reference to constant of the container + type. It makes a deep copy of its argument. For instance: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string" minOccurs="0"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef xml_schema::string member_type; + typedef optional<member_type> member_optional; + + // Accessors. + // + const member_optional& + member () const; + + member_optional& + member (); + + // Modifiers. + // + void + member (const member_type&); + + void + member (std::[unique|auto]_ptr<member_type>); + + void + member (const member_optional&); + + ... + +}; + </pre> + + + <p>The <code>optional</code> class template is defined in an + implementation-specific namespace and has the following + interface. The <code>[unique|auto]_ptr</code>-based constructor + and modifier function are only available if the template + argument is not a fundamental C++ type. + </p> + + <pre class="c++"> +template <typename X> +class optional +{ +public: + optional (); + + // Makes a deep copy. + // + explicit + optional (const X&); + + // Assumes ownership. + // + explicit + optional (std::[unique|auto]_ptr<X>); + + optional (const optional&); + +public: + optional& + operator= (const X&); + + optional& + operator= (const optional&); + + // Pointer-like interface. + // +public: + const X* + operator-> () const; + + X* + operator-> (); + + const X& + operator* () const; + + X& + operator* (); + + typedef void (optional::*bool_convertible) (); + operator bool_convertible () const; + + // Get/set interface. + // +public: + bool + present () const; + + const X& + get () const; + + X& + get (); + + // Makes a deep copy. + // + void + set (const X&); + + // Assumes ownership. + // + void + set (std::[unique|auto]_ptr<X>); + + // Detach and return the contained value. + // + std::[unique|auto]_ptr<X> + detach (); + + void + reset (); +}; + +template <typename X> +bool +operator== (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator!= (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator< (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator> (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator<= (const optional<X>&, const optional<X>&); + +template <typename X> +bool +operator>= (const optional<X>&, const optional<X>&); + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o) +{ + using xml_schema::string; + + if (o.member ().present ()) // test + { + string& s (o.member ().get ()); // get + o.member ("hello"); // set, deep copy + o.member ().set ("hello"); // set, deep copy + o.member ().reset (); // reset + } + + // Same as above but using pointer notation: + // + if (o.member ()) // test + { + string& s (*o.member ()); // get + o.member ("hello"); // set, deep copy + *o.member () = "hello"; // set, deep copy + o.member ().reset (); // reset + } + + // C++11 version. + // + std::unique_ptr<string> p (new string ("hello")); + o.member (std::move (p)); // set, assumes ownership + + p.reset (new string ("hello")); + o.member ().set (std::move (p)); // set, assumes ownership + + p = o.member ().detach (); // detach, member is reset + o.member ().set (std::move (p)); // re-attach + + // C++98 version. + // + std::auto_ptr<string> p (new string ("hello")); + o.member (p); // set, assumes ownership + + p = new string ("hello"); + o.member ().set (p); // set, assumes ownership + + p = o.member ().detach (); // detach, member is reset + o.member ().set (p); // re-attach +} + </pre> + + + <h3><a name="2.8.3">2.8.3 Mapping for Members with the Sequence Cardinality Class</a></h3> + + <p>For the Sequence cardinality class, the type definitions consist of an + alias for the member's type with the name created by appending + the <code>_type</code> suffix to the member's name, an alias of + the container type with the name created by appending the + <code>_sequence</code> suffix to the member's name, an alias of + the iterator type with the name created by appending the + <code>_iterator</code> suffix to the member's name, and an alias + of the constant iterator type with the name created by appending the + <code>_const_iterator</code> suffix to the member's name. + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container and can + be used for read-write access. + </p> + + <p>The modifier function expects an argument of type reference to + constant of the container type. The modifier function + makes a deep copy of its argument. For instance: + </p> + + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="member" type="string" minOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef xml_schema::string member_type; + typedef sequence<member_type> member_sequence; + typedef member_sequence::iterator member_iterator; + typedef member_sequence::const_iterator member_const_iterator; + + // Accessors. + // + const member_sequence& + member () const; + + member_sequence& + member (); + + // Modifier. + // + void + member (const member_sequence&); + + ... + +}; + </pre> + + <p>The <code>sequence</code> class template is defined in an + implementation-specific namespace. It conforms to the + sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences"). + Practically, this means that you can treat such a sequence + as if it was <code>std::vector</code>. Two notable extensions + to the standard interface that are available only for + sequences of non-fundamental C++ types are the addition of + the overloaded <code>push_back</code> and <code>insert</code> + as well as the <code>detach_back</code> and <code>detach</code> + member functions. The additional <code>push_back</code> and + <code>insert</code> functions accept an automatic pointer + (<code>std::unique_ptr</code> or <code>std::auto_ptr</code>, + depending on the C++ standard selected) to the + element type instead of the constant reference. They assume + ownership of the pointed to object and reset the passed + automatic pointer. The <code>detach_back</code> and + <code>detach</code> functions detach the element + value from the sequence container and, by default, remove + the element from the sequence. These additional functions + have the following signatures:</p> + + <pre class="c++"> +template <typename X> +class sequence +{ +public: + ... + + void + push_back (std::[unique|auto]_ptr<X>) + + iterator + insert (iterator position, std::[unique|auto]_ptr<X>) + + std::[unique|auto]_ptr<X> + detach_back (bool pop = true); + + iterator + detach (iterator position, + std::[unique|auto]_ptr<X>& result, + bool erase = true) + + ... +} + </pre> + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o) +{ + using xml_schema::string; + + object::member_sequence& s (o.member ()); + + // Iteration. + // + for (object::member_iterator i (s.begin ()); i != s.end (); ++i) + { + string& value (*i); + } + + // Modification. + // + s.push_back ("hello"); // deep copy + + // C++11 version. + // + std::unique_ptr<string> p (new string ("hello")); + s.push_back (std::move (p)); // assumes ownership + p = s.detach_back (); // detach and pop + s.push_back (std::move (p)); // re-append + + // C++98 version. + // + std::auto_ptr<string> p (new string ("hello")); + s.push_back (p); // assumes ownership + p = s.detach_back (); // detach and pop + s.push_back (p); // re-append + + // Setting a new container. + // + object::member_sequence n; + n.push_back ("one"); + n.push_back ("two"); + o.member (n); // deep copy +} + </pre> + + <h3><a name="2.8.4">2.8.4 Element Order</a></h3> + + <p>C++/Tree is a "flattening" mapping in a sense that many levels of + nested compositors (<code>choice</code> and <code>sequence</code>), + all potentially with their own cardinalities, are in the end mapped + to a flat set of elements with one of the three cardinality classes + discussed in the previous sections. While this results in a simple + and easy to use API for most types, in certain cases, the order of + elements in the actual XML documents is not preserved once parsed + into the object model. And sometimes such order has + application-specific significance. As an example, consider a schema + that defines a batch of bank transactions:</p> + + <pre class="xml"> +<complexType name="withdraw"> + <sequence> + <element name="account" type="unsignedInt"/> + <element name="amount" type="unsignedInt"/> + </sequence> +</complexType> + +<complexType name="deposit"> + <sequence> + <element name="account" type="unsignedInt"/> + <element name="amount" type="unsignedInt"/> + </sequence> +</complexType> + +<complexType name="batch"> + <choice minOccurs="0" maxOccurs="unbounded"> + <element name="withdraw" type="withdraw"/> + <element name="deposit" type="deposit"/> + </choice> +</complexType> + </pre> + + <p>The batch can contain any number of transactions in any order + but the order of transactions in each actual batch is significant. + For instance, consider what could happen if we reorder the + transactions and apply all the withdrawals before deposits.</p> + + <p>For the <code>batch</code> schema type defined above the default + C++/Tree mapping will produce a C++ class that contains a pair of + sequence containers, one for each of the two elements. While this + will capture the content (transactions), the order of this content + as it appears in XML will be lost. Also, if we try to serialize the + batch we just loaded back to XML, all the withdrawal transactions + will appear before deposits.</p> + + <p>To overcome this limitation of a flattening mapping, C++/Tree + allows us to mark certain XML Schema types, for which content + order is important, as ordered.</p> + + <p>There are several command line options that control which + schema types are treated as ordered. To make an individual + type ordered, we use the <code>--ordered-type</code> option, + for example:</p> + + <pre class="term"> +--ordered-type batch + </pre> + + <p>To automatically treat all the types that are derived from an ordered + type also ordered, we use the <code>--ordered-type-derived</code> + option. This is primarily useful if you would like to iterate + over the complete hierarchy's content using the content order + sequence (discussed below).</p> + + <p>Ordered types are also useful for handling mixed content. To + automatically mark all the types with mixed content as ordered + we use the <code>--ordered-type-mixed</code> option. For more + information on handling mixed content see <a href="#2.13">Section + 2.13, "Mapping for Mixed Content Models"</a>.</p> + + <p>Finally, we can mark all the types in the schema we are + compiling with the <code>--ordered-type-all</code> option. + You should only resort to this option if all the types in + your schema truly suffer from the loss of content + order since, as we will discuss shortly, ordered types + require extra effort to access and, especially, modify. + See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information on + these options.</p> + + <p>Once a type is marked ordered, C++/Tree alters its mapping + in several ways. Firstly, for each local element, element + wildcard (<a href="#2.12.4">Section 2.12.4, "Element Wildcard + Order"</a>), and mixed content text (<a href="#2.13">Section + 2.13, "Mapping for Mixed Content Models"</a>) in this type, a + content id constant is generated. Secondly, an addition sequence + is added to the class that captures the content order. Here + is how the mapping of our <code>batch</code> class changes + once we make it ordered:</p> + + <pre class="c++"> +class batch: public xml_schema::type +{ +public: + // withdraw + // + typedef withdraw withdraw_type; + typedef sequence<withdraw_type> withdraw_sequence; + typedef withdraw_sequence::iterator withdraw_iterator; + typedef withdraw_sequence::const_iterator withdraw_const_iterator; + + static const std::size_t withdraw_id = 1; + + const withdraw_sequence& + withdraw () const; + + withdraw_sequence& + withdraw (); + + void + withdraw (const withdraw_sequence&); + + // deposit + // + typedef deposit deposit_type; + typedef sequence<deposit_type> deposit_sequence; + typedef deposit_sequence::iterator deposit_iterator; + typedef deposit_sequence::const_iterator deposit_const_iterator; + + static const std::size_t deposit_id = 2; + + const deposit_sequence& + deposit () const; + + deposit_sequence& + deposit (); + + void + deposit (const deposit_sequence&); + + // content_order + // + typedef xml_schema::content_order content_order_type; + typedef std::vector<content_order_type> content_order_sequence; + typedef content_order_sequence::iterator content_order_iterator; + typedef content_order_sequence::const_iterator content_order_const_iterator; + + const content_order_sequence& + content_order () const; + + content_order_sequence& + content_order (); + + void + content_order (const content_order_sequence&); + + ... +}; + </pre> + + <p>Notice the <code>withdraw_id</code> and <code>deposit_id</code> + content ids as well as the extra <code>content_order</code> + sequence that does not correspond to any element in the + schema definition. The other changes to the mapping for ordered + types has to do with XML parsing and serialization code. During + parsing the content order is captured in the <code>content_order</code> + sequence while during serialization this sequence is used to + determine the order in which content is serialized. The + <code>content_order</code> sequence is also copied during + copy construction and assigned during copy assignment. It is also + taken into account during comparison.</p> + + <p>The entry type of the <code>content_order</code> sequence is the + <code>xml_schema::content_order</code> type that has the following + interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + struct content_order + { + content_order (std::size_t id, std::size_t index = 0); + + std::size_t id; + std::size_t index; + }; + + bool + operator== (const content_order&, const content_order&); + + bool + operator!= (const content_order&, const content_order&); + + bool + operator< (const content_order&, const content_order&); +} + </pre> + + <p>The <code>content_order</code> sequence describes the order of + content (elements, including wildcards, as well as mixed content + text). Each entry in this sequence consists of the content id + (for example, <code>withdraw_id</code> or <code>deposit_id</code> + in our case) as well as, for elements of the sequence cardinality + class, an index into the corresponding sequence container (the + index is unused for the one and optional cardinality classes). + For example, in our case, if the content id is <code>withdraw_id</code>, + then the index will point into the <code>withdraw</code> element + sequence.</p> + + <p>With all this information we can now examine how to iterate over + transaction in the batch in content order:</p> + + <pre class="c++"> +batch& b = ... + +for (batch::content_order_const_iterator i (b.content_order ().begin ()); + i != b.content_order ().end (); + ++i) +{ + switch (i->id) + { + case batch::withdraw_id: + { + const withdraw& t (b.withdraw ()[i->index]); + cerr << t.account () << " withdraw " << t.amount () << endl; + break; + } + case batch::deposit_id: + { + const deposit& t (b.deposit ()[i->index]); + cerr << t.account () << " deposit " << t.amount () << endl; + break; + } + default: + { + assert (false); // Unknown content id. + } + } +} + </pre> + + <p>If we serialized our batch back to XML, we would also see that the + order of transactions in the output is exactly the same as in the + input rather than all the withdrawals first followed by all the + deposits.</p> + + <p>The most complex aspect of working with ordered types is + modifications. Now we not only need to change the content, + but also remember to update the order information corresponding + to this change. As a first example, we add a deposit transaction + to the batch:</p> + + <pre class="c++"> +using xml_schema::content_order; + +batch::deposit_sequence& d (b.deposit ()); +batch::withdraw_sequence& w (b.withdraw ()); +batch::content_order_sequence& co (b.content_order ()); + +d.push_back (deposit (123456789, 100000)); +co.push_back (content_order (batch::deposit_id, d.size () - 1)); + </pre> + + <p>In the above example we first added the content (deposit + transaction) and then updated the content order information + by adding an entry with <code>deposit_id</code> content + id and the index of the just added deposit transaction.</p> + + <p>Removing the last transaction can be easy if we know which + transaction (deposit or withdrawal) is last:</p> + + <pre class="c++"> +d.pop_back (); +co.pop_back (); + </pre> + + <p>If, however, we do not know which transaction is last, then + things get a bit more complicated:</p> + + <pre class="c++"> +switch (co.back ().id) +{ +case batch::withdraw_id: + { + d.pop_back (); + break; + } +case batch::deposit_id: + { + w.pop_back (); + break; + } +} + +co.pop_back (); + </pre> + + <p>The following example shows how to add a transaction at the + beginning of the batch:</p> + + <pre class="c++"> +w.push_back (withdraw (123456789, 100000)); +co.insert (co.begin (), + content_order (batch::withdraw_id, w.size () - 1)); + </pre> + + <p>Note also that when we merely modify the content of one + of the elements in place, we do not need to update its + order since it doesn't change. For example, here is how + we can change the amount in the first withdrawal:</p> + + <pre class="c++"> +w[0].amount (10000); + </pre> + + <p>For the complete working code shown in this section refer to the + <code>order/element</code> example in the + <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <p>If both the base and derived types are ordered, then the + content order sequence is only added to the base and the content + ids are unique within the whole hierarchy. In this case + the content order sequence for the derived type contains + ordering information for both base and derived content.</p> + + <p>In some applications we may need to perform more complex + content processing. For example, in our case, we may need + to remove all the withdrawal transactions. The default + container, <code>std::vector</code>, is not particularly + suitable for such operations. What may be required by + some applications is a multi-index container that not + only allows us to iterate in content order similar to + <code>std::vector</code> but also search by the content + id as well as the content id and index pair.</p> + + <p>While C++/Tree does not provide this functionality by + default, it allows us to specify a custom container + type for content order with the <code>--order-container</code> + command line option. The only requirement from the + generated code side for such a container is to provide + the <code>vector</code>-like <code>push_back()</code>, + <code>size()</code>, and const iteration interfaces.</p> + + <p>As an example, here is how we can use the Boost Multi-Index + container for content order. First we create the + <code>content-order-container.hxx</code> header with the + following definition:</p> + + <pre class="c++"> +#ifndef CONTENT_ORDER_CONTAINER +#define CONTENT_ORDER_CONTAINER + +#include <cstddef> // std::size_t + +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/multi_index/identity.hpp> +#include <boost/multi_index/ordered_index.hpp> +#include <boost/multi_index/random_access_index.hpp> + +struct by_id {}; +struct by_id_index {}; + +template <typename T> +using content_order_container = + boost::multi_index::multi_index_container< + T, + boost::multi_index::indexed_by< + boost::multi_index::random_access<>, + boost::multi_index::ordered_unique< + boost::multi_index::tag<by_id_index>, + boost::multi_index::identity<T> + >, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag<by_id>, + boost::multi_index::member<T, std::size_t, &T::id> + > + > + >; + +#endif + </pre> + + <p>Next we add the following two XSD compiler options to include + this header into every generated header file and to use the + custom container type (see the XSD compiler command line manual + for more information on shell quoting for the first option):</p> + + <pre class="term"> +--hxx-prologue '#include "content-order-container.hxx"' +--order-container content_order_container + </pre> + + <p>With these changes we can now use the multi-index functionality, + for example, to search for a specific content id:</p> + + <pre class="c++"> +typedef batch::content_order_sequence::index<by_id>::type id_set; +typedef id_set::iterator id_iterator; + +const id_set& ids (b.content_order ().get<by_id> ()); + +std::pair<id_iterator, id_iterator> r ( + ids.equal_range (std::size_t (batch::deposit_id)); + +for (id_iterator i (r.first); i != r.second; ++i) +{ + const deposit& t (b.deposit ()[i->index]); + cerr << t.account () << " deposit " << t.amount () << endl; +} + </pre> + + <h2><a name="2.9">2.9 Mapping for Global Elements</a></h2> + + <p>An XML Schema element definition is called global if it appears + directly under the <code>schema</code> element. + A global element is a valid root of an instance document. By + default, a global element is mapped to a set of overloaded + parsing and, optionally, serialization functions with the + same name as the element. It is also possible to generate types + for root elements instead of parsing and serialization functions. + This is primarily useful to distinguish object models with the + same root type but with different root elements. See + <a href="#2.9.1">Section 2.9.1, "Element Types"</a> for details. + It is also possible to request the generation of an element map + which allows uniform parsing and serialization of multiple root + elements. See <a href="#2.9.2">Section 2.9.2, "Element Map"</a> + for details. + </p> + + <p>The parsing functions read XML instance documents and return + corresponding object models as an automatic pointer + (<code>std::unique_ptr</code> or <code>std::auto_ptr</code>, + depending on the C++ standard selected). Their signatures + have the following pattern (<code>type</code> denotes + element's type and <code>name</code> denotes element's + name): + </p> + + <pre class="c++"> +std::[unique|auto]_ptr<type> +name (....); + </pre> + + <p>The process of parsing, including the exact signatures of the parsing + functions, is the subject of <a href="#3">Chapter 3, "Parsing"</a>. + </p> + + <p>The serialization functions write object models back to XML instance + documents. Their signatures have the following pattern: + </p> + + <pre class="c++"> +void +name (<stream type>&, const type&, ....); + </pre> + + <p>The process of serialization, including the exact signatures of the + serialization functions, is the subject of <a href="#4">Chapter 4, + "Serialization"</a>. + </p> + + + <h3><a name="2.9.1">2.9.1 Element Types</a></h3> + + <p>The generation of element types is requested with the + <code>--generate-element-type</code> option. With this option + each global element is mapped to a C++ class with the + same name as the element. Such a class is derived from + <code>xml_schema::element_type</code> and contains the same set + of type definitions, constructors, and member function as would a + type containing a single element with the One cardinality class + named <code>"value"</code>. In addition, the element type also + contains a set of member functions for accessing the element + name and namespace as well as its value in a uniform manner. + For example:</p> + + <pre class="xml"> +<complexType name="type"> + <sequence> + ... + </sequence> +</complexType> + +<element name="root" type="type"/> + </pre> + +<p>is mapped to:</p> + + <pre class="c++"> +class type +{ + ... +}; + +class root: public xml_schema::element_type +{ +public: + // Element value. + // + typedef type value_type; + + const value_type& + value () const; + + value_type& + value (); + + void + value (const value_type&); + + void + value (std::[unique|auto]_ptr<value_type>); + + // Constructors. + // + root (const value_type&); + + root (std::[unique|auto]_ptr<value_type>); + + root (const xercesc::DOMElement&, xml_schema::flags = 0); + + root (const root&, xml_schema::flags = 0); + + virtual root* + _clone (xml_schema::flags = 0) const; + + // Element name and namespace. + // + static const std::string& + name (); + + static const std::string& + namespace_ (); + + virtual const std::string& + _name () const; + + virtual const std::string& + _namespace () const; + + // Element value as xml_schema::type. + // + virtual const xml_schema::type* + _value () const; + + virtual xml_schema::type* + _value (); +}; + +void +operator<< (xercesc::DOMElement&, const root&); + </pre> + + <p>The <code>xml_schema::element_type</code> class is a common + base type for all element types and is defined as follows:</p> + + <pre class="c++"> +namespace xml_schema +{ + class element_type + { + public: + virtual + ~element_type (); + + virtual element_type* + _clone (flags f = 0) const = 0; + + virtual const std::basic_string<C>& + _name () const = 0; + + virtual const std::basic_string<C>& + _namespace () const = 0; + + virtual xml_schema::type* + _value () = 0; + + virtual const xml_schema::type* + _value () const = 0; + }; +} + </pre> + + <p>The <code>_value()</code> member function returns a pointer to + the element value or 0 if the element is of a fundamental C++ + type and therefore is not derived from <code>xml_schema::type</code>. + </p> + + <p>Unlike parsing and serialization functions, element types + are only capable of parsing and serializing from/to a + <code>DOMElement</code> object. This means that the application + will need to perform its own XML-to-DOM parsing and DOM-to-XML + serialization. The following section describes a mechanism + provided by the mapping to uniformly parse and serialize + multiple root elements.</p> + + + <h3><a name="2.9.2">2.9.2 Element Map</a></h3> + + <p>When element types are generated for root elements it is also + possible to request the generation of an element map with the + <code>--generate-element-map</code> option. The element map + allows uniform parsing and serialization of multiple root + elements via the common <code>xml_schema::element_type</code> + base type. The <code>xml_schema::element_map</code> class is + defined as follows:</p> + + <pre class="c++"> +namespace xml_schema +{ + class element_map + { + public: + static std::[unique|auto]_ptr<xml_schema::element_type> + parse (const xercesc::DOMElement&, flags = 0); + + static void + serialize (xercesc::DOMElement&, const element_type&); + }; +} + </pre> + + <p>The <code>parse()</code> function creates the corresponding + element type object based on the element name and namespace + and returns it as an automatic pointer (<code>std::unique_ptr</code> + or <code>std::auto_ptr</code>, depending on the C++ standard + selected) to <code>xml_schema::element_type</code>. + The <code>serialize()</code> function serializes the passed element + object to <code>DOMElement</code>. Note that in case of + <code>serialize()</code>, the <code>DOMElement</code> object + should have the correct name and namespace. If no element type is + available for an element, both functions throw the + <code>xml_schema::no_element_info</code> exception:</p> + + <pre class="c++"> +struct no_element_info: virtual exception +{ + no_element_info (const std::basic_string<C>& element_name, + const std::basic_string<C>& element_namespace); + + const std::basic_string<C>& + element_name () const; + + const std::basic_string<C>& + element_namespace () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The application can discover the actual type of the element + object returned by <code>parse()</code> either using + <code>dynamic_cast</code> or by comparing element names and + namespaces. The following code fragments illustrate how the + element map can be used:</p> + + <pre class="c++"> +// Parsing. +// +DOMElement& e = ... // Parse XML to DOM. + +unique_ptr<xml_schema::element_type> r ( + xml_schema::element_map::parse (e)); + +if (root1 r1 = dynamic_cast<root1*> (r.get ())) +{ + ... +} +else if (r->_name == root2::name () && + r->_namespace () == root2::namespace_ ()) +{ + root2& r2 (static_cast<root2&> (*r)); + + ... +} + </pre> + + <pre class="c++"> +// Serialization. +// +xml_schema::element_type& r = ... + +string name (r._name ()); +string ns (r._namespace ()); + +DOMDocument& doc = ... // Create a new DOMDocument with name and ns. +DOMElement& e (*doc->getDocumentElement ()); + +xml_schema::element_map::serialize (e, r); + +// Serialize DOMDocument to XML. + </pre> + + <!-- --> + + <h2><a name="2.10">2.10 Mapping for Global Attributes</a></h2> + + <p>An XML Schema attribute definition is called global if it appears + directly under the <code>schema</code> element. A global + attribute does not have any mapping. + </p> + + <!-- + When it is referenced from + a local attribute definition (using the <code>ref</code> attribute) + it is treated as a local attribute (see Section 2.8, "Mapping for + Local Elements and Attributes"). + --> + + <h2><a name="2.11">2.11 Mapping for <code>xsi:type</code> and Substitution + Groups</a></h2> + + <p>The mapping provides optional support for the XML Schema polymorphism + features (<code>xsi:type</code> and substitution groups) which can + be requested with the <code>--generate-polymorphic</code> option. + When used, the dynamic type of a member may be different from + its static type. Consider the following schema definition and + instance document: + </p> + + <pre class="xml"> +<!-- test.xsd --> +<schema> + <complexType name="base"> + <attribute name="text" type="string"/> + </complexType> + + <complexType name="derived"> + <complexContent> + <extension base="base"> + <attribute name="extra-text" type="string"/> + </extension> + </complexContent> + </complexType> + + <complexType name="root_type"> + <sequence> + <element name="item" type="base" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <element name="root" type="root_type"/> +</schema> + +<!-- test.xml --> +<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <item text="hello"/> + <item text="hello" extra-text="world" xsi:type="derived"/> +</root> + </pre> + + <p>In the resulting object model, the container for + the <code>root::item</code> member will have two elements: + the first element's type will be <code>base</code> while + the second element's (dynamic) type will be + <code>derived</code>. This can be discovered using the + <code>dynamic_cast</code> operator as shown in the following + example: + </p> + + <pre class="c++"> +void +f (root& r) +{ + for (root::item_const_iterator i (r.item ().begin ()); + i != r.item ().end () + ++i) + { + if (derived* d = dynamic_cast<derived*> (&(*i))) + { + // derived + } + else + { + // base + } + } +} + </pre> + + <p>The <code>_clone</code> virtual function should be used instead of + copy constructors to make copies of members that might use + polymorphism: + </p> + + <pre class="c++"> +void +f (root& r) +{ + for (root::item_const_iterator i (r.item ().begin ()); + i != r.item ().end () + ++i) + { + std::unique_ptr<base> c (i->_clone ()); + } +} + </pre> + + <p>The mapping 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 mapping + 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>You can also indicate that all types should be treated as polymorphic + with the <code>--polymorphic-type-all</code>. However, this may result + in slower generated code with a greater footprint.</p> + + + <!-- Mapping for any and anyAttribute --> + + + <h2><a name="2.12">2.12 Mapping for <code>any</code> and <code>anyAttribute</code></a></h2> + + <p>For the XML Schema <code>any</code> and <code>anyAttribute</code> + wildcards an optional mapping can be requested with the + <code>--generate-wildcard</code> option. The mapping represents + the content matched by wildcards as DOM fragments. Because the + DOM API is used to access such content, the Xerces-C++ runtime + should be initialized by the application prior to parsing and + should remain initialized for the lifetime of objects with + the wildcard content. For more information on the Xerces-C++ + runtime initialization see <a href="#3.1">Section 3.1, + "Initializing the Xerces-C++ Runtime"</a>. + </p> + + <p>The mapping for <code>any</code> is similar to the mapping for + local elements (see <a href="#2.8">Section 2.8, "Mapping for Local + Elements and Attributes"</a>) except that the type used in the + wildcard mapping is <code>xercesc::DOMElement</code>. As with local + elements, the mapping divides all possible cardinality combinations + into three cardinality classes: <i>one</i>, <i>optional</i>, and + <i>sequence</i>. + </p> + + <p>The mapping for <code>anyAttribute</code> represents the attributes + matched by this wildcard as a set of <code>xercesc::DOMAttr</code> + objects with a key being the attribute's name and namespace.</p> + + <p>Similar to local elements and attributes, the <code>any</code> and + <code>anyAttribute</code> wildcards are mapped to a set of public type + definitions (typedefs) and a set of public accessor and modifier + functions. Type definitions have names derived from <code>"any"</code> + for the <code>any</code> wildcard and <code>"any_attribute"</code> + for the <code>anyAttribute</code> wildcard. The accessor and modifier + functions are named <code>"any"</code> for the <code>any</code> wildcard + and <code>"any_attribute"</code> for the <code>anyAttribute</code> + wildcard. Subsequent wildcards in the same type have escaped names + such as <code>"any1"</code> or <code>"any_attribute1"</code>. + </p> + + <p>Because Xerces-C++ DOM nodes always belong to a <code>DOMDocument</code>, + each type with a wildcard has an associated <code>DOMDocument</code> + object. The reference to this object can be obtained using the accessor + function called <code>dom_document</code>. The access to the document + object from the application code may be necessary to create or modify + the wildcard content. For example: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other"/> + </sequence> + <anyAttribute namespace="##other"/> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // any + // + const xercesc::DOMElement& + any () const; + + void + any (const xercesc::DOMElement&); + + ... + + // any_attribute + // + typedef attribute_set any_attribute_set; + typedef any_attribute_set::iterator any_attribute_iterator; + typedef any_attribute_set::const_iterator any_attribute_const_iterator; + + const any_attribute_set& + any_attribute () const; + + any_attribute_set& + any_attribute (); + + ... + + // DOMDocument object for wildcard content. + // + const xercesc::DOMDocument& + dom_document () const; + + xercesc::DOMDocument& + dom_document (); + + ... +}; + </pre> + + + <p>Names and semantics of type definitions for the wildcards as well + as signatures of the accessor and modifier functions depend on the + wildcard type as well as the cardinality class for the <code>any</code> + wildcard. They are described in the following sub-sections. + </p> + + + <h3><a name="2.12.1">2.12.1 Mapping for <code>any</code> with the One Cardinality Class</a></h3> + + <p>For <code>any</code> with the One cardinality class, + there are no type definitions. The accessor functions come in + constant and non-constant versions. The constant accessor function + returns a constant reference to <code>xercesc::DOMElement</code> and + can be used for read-only access. The non-constant version returns + an unrestricted reference to <code>xercesc::DOMElement</code> and can + be used for read-write access. + </p> + + <p>The first modifier function expects an argument of type reference + to constant <code>xercesc::DOMElement</code> and makes a deep copy + of its argument. The second modifier function expects an argument of + type pointer to <code>xercesc::DOMElement</code>. This modifier + function assumes ownership of its argument and expects the element + object to be created using the DOM document associated with this + instance. For example: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Accessors. + // + const xercesc::DOMElement& + any () const; + + xercesc::DOMElement& + any (); + + // Modifiers. + // + void + any (const xercesc::DOMElement&); + + void + any (xercesc::DOMElement*); + + ... + +}; + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMElement& e) +{ + using namespace xercesc; + + DOMElement& e1 (o.any ()); // get + o.any (e) // set, deep copy + DOMDocument& doc (o.dom_document ()); + o.any (doc.createElement (...)); // set, assumes ownership +} + </pre> + + <h3><a name="2.12.2">2.12.2 Mapping for <code>any</code> with the Optional Cardinality Class</a></h3> + + <p>For <code>any</code> with the Optional cardinality class, the type + definitions consist of an alias for the container type with name + <code>any_optional</code> (or <code>any1_optional</code>, etc., for + subsequent wildcards in the type definition). + </p> + + <p>Unlike accessor functions for the One cardinality class, accessor + functions for the Optional cardinality class return references to + corresponding containers rather than directly to <code>DOMElement</code>. + The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to + the container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container + and can be used for read-write access. + </p> + + <p>The modifier functions are overloaded for <code>xercesc::DOMElement</code> + and the container type. The first modifier function expects an argument of + type reference to constant <code>xercesc::DOMElement</code> and + makes a deep copy of its argument. The second modifier function + expects an argument of type pointer to <code>xercesc::DOMElement</code>. + This modifier function assumes ownership of its argument and expects + the element object to be created using the DOM document associated + with this instance. The third modifier function expects an argument + of type reference to constant of the container type and makes a + deep copy of its argument. For instance: + </p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other" minOccurs="0"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef element_optional any_optional; + + // Accessors. + // + const any_optional& + any () const; + + any_optional& + any (); + + // Modifiers. + // + void + any (const xercesc::DOMElement&); + + void + any (xercesc::DOMElement*); + + void + any (const any_optional&); + + ... + +}; + </pre> + + + <p>The <code>element_optional</code> container is a + specialization of the <code>optional</code> class template described + in <a href="#2.8.2">Section 2.8.2, "Mapping for Members with the Optional + Cardinality Class"</a>. Its interface is presented below: + </p> + + <pre class="c++"> +class element_optional +{ +public: + explicit + element_optional (xercesc::DOMDocument&); + + // Makes a deep copy. + // + element_optional (const xercesc::DOMElement&, xercesc::DOMDocument&); + + // Assumes ownership. + // + element_optional (xercesc::DOMElement*, xercesc::DOMDocument&); + + element_optional (const element_optional&, xercesc::DOMDocument&); + +public: + element_optional& + operator= (const xercesc::DOMElement&); + + element_optional& + operator= (const element_optional&); + + // Pointer-like interface. + // +public: + const xercesc::DOMElement* + operator-> () const; + + xercesc::DOMElement* + operator-> (); + + const xercesc::DOMElement& + operator* () const; + + xercesc::DOMElement& + operator* (); + + typedef void (element_optional::*bool_convertible) (); + operator bool_convertible () const; + + // Get/set interface. + // +public: + bool + present () const; + + const xercesc::DOMElement& + get () const; + + xercesc::DOMElement& + get (); + + // Makes a deep copy. + // + void + set (const xercesc::DOMElement&); + + // Assumes ownership. + // + void + set (xercesc::DOMElement*); + + void + reset (); +}; + +bool +operator== (const element_optional&, const element_optional&); + +bool +operator!= (const element_optional&, const element_optional&); + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMElement& e) +{ + using namespace xercesc; + + DOMDocument& doc (o.dom_document ()); + + if (o.any ().present ()) // test + { + DOMElement& e1 (o.any ().get ()); // get + o.any ().set (e); // set, deep copy + o.any ().set (doc.createElement (...)); // set, assumes ownership + o.any ().reset (); // reset + } + + // Same as above but using pointer notation: + // + if (o.member ()) // test + { + DOMElement& e1 (*o.any ()); // get + o.any (e); // set, deep copy + o.any (doc.createElement (...)); // set, assumes ownership + o.any ().reset (); // reset + } +} + </pre> + + + + <h3><a name="2.12.3">2.12.3 Mapping for <code>any</code> with the Sequence Cardinality Class</a></h3> + + <p>For <code>any</code> with the Sequence cardinality class, the type + definitions consist of an alias of the container type with name + <code>any_sequence</code> (or <code>any1_sequence</code>, etc., for + subsequent wildcards in the type definition), an alias of the iterator + type with name <code>any_iterator</code> (or <code>any1_iterator</code>, + etc., for subsequent wildcards in the type definition), and an alias + of the constant iterator type with name <code>any_const_iterator</code> + (or <code>any1_const_iterator</code>, etc., for subsequent wildcards + in the type definition). + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container and can + be used for read-write access. + </p> + + <p>The modifier function expects an argument of type reference to + constant of the container type. The modifier function makes + a deep copy of its argument. For instance: + </p> + + + <pre class="xml"> +<complexType name="object"> + <sequence> + <any namespace="##other" minOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef element_sequence any_sequence; + typedef any_sequence::iterator any_iterator; + typedef any_sequence::const_iterator any_const_iterator; + + // Accessors. + // + const any_sequence& + any () const; + + any_sequence& + any (); + + // Modifier. + // + void + any (const any_sequence&); + + ... + +}; + </pre> + + <p>The <code>element_sequence</code> container is a + specialization of the <code>sequence</code> class template described + in <a href="#2.8.3">Section 2.8.3, "Mapping for Members with the + Sequence Cardinality Class"</a>. Its interface is similar to + the sequence interface as defined by the ISO/ANSI Standard for + C++ (ISO/IEC 14882:1998, Section 23.1.1, "Sequences") and is + presented below: + </p> + + <pre class="c++"> +class element_sequence +{ +public: + typedef xercesc::DOMElement value_type; + typedef xercesc::DOMElement* pointer; + typedef const xercesc::DOMElement* const_pointer; + typedef xercesc::DOMElement& reference; + typedef const xercesc::DOMElement& const_reference; + + typedef <implementation-defined> iterator; + typedef <implementation-defined> const_iterator; + typedef <implementation-defined> reverse_iterator; + typedef <implementation-defined> const_reverse_iterator; + + typedef <implementation-defined> size_type; + typedef <implementation-defined> difference_type; + typedef <implementation-defined> allocator_type; + +public: + explicit + element_sequence (xercesc::DOMDocument&); + + // DOMElement cannot be default-constructed. + // + // explicit + // element_sequence (size_type n); + + element_sequence (size_type n, + const xercesc::DOMElement&, + xercesc::DOMDocument&); + + template <typename I> + element_sequence (const I& begin, + const I& end, + xercesc::DOMDocument&); + + element_sequence (const element_sequence&, xercesc::DOMDocument&); + + element_sequence& + operator= (const element_sequence&); + +public: + void + assign (size_type n, const xercesc::DOMElement&); + + template <typename I> + void + assign (const I& begin, const I& end); + +public: + // This version of resize can only be used to shrink the + // sequence because DOMElement cannot be default-constructed. + // + void + resize (size_type); + + void + resize (size_type, const xercesc::DOMElement&); + +public: + size_type + size () const; + + size_type + max_size () const; + + size_type + capacity () const; + + bool + empty () const; + + void + reserve (size_type); + + void + clear (); + +public: + const_iterator + begin () const; + + const_iterator + end () const; + + iterator + begin (); + + iterator + end (); + + const_reverse_iterator + rbegin () const; + + const_reverse_iterator + rend () const + + reverse_iterator + rbegin (); + + reverse_iterator + rend (); + +public: + xercesc::DOMElement& + operator[] (size_type); + + const xercesc::DOMElement& + operator[] (size_type) const; + + xercesc::DOMElement& + at (size_type); + + const xercesc::DOMElement& + at (size_type) const; + + xercesc::DOMElement& + front (); + + const xercesc::DOMElement& + front () const; + + xercesc::DOMElement& + back (); + + const xercesc::DOMElement& + back () const; + +public: + // Makes a deep copy. + // + void + push_back (const xercesc::DOMElement&); + + // Assumes ownership. + // + void + push_back (xercesc::DOMElement*); + + void + pop_back (); + + // Makes a deep copy. + // + iterator + insert (iterator position, const xercesc::DOMElement&); + + // Assumes ownership. + // + iterator + insert (iterator position, xercesc::DOMElement*); + + void + insert (iterator position, size_type n, const xercesc::DOMElement&); + + template <typename I> + void + insert (iterator position, const I& begin, const I& end); + + iterator + erase (iterator position); + + iterator + erase (iterator begin, iterator end); + +public: + // Note that the DOMDocument object of the two sequences being + // swapped should be the same. + // + void + swap (sequence& x); +}; + +inline bool +operator== (const element_sequence&, const element_sequence&); + +inline bool +operator!= (const element_sequence&, const element_sequence&); + </pre> + + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMElement& e) +{ + using namespace xercesc; + + object::any_sequence& s (o.any ()); + + // Iteration. + // + for (object::any_iterator i (s.begin ()); i != s.end (); ++i) + { + DOMElement& e (*i); + } + + // Modification. + // + s.push_back (e); // deep copy + DOMDocument& doc (o.dom_document ()); + s.push_back (doc.createElement (...)); // assumes ownership +} + </pre> + + <h3><a name="2.12.4">2.12.4 Element Wildcard Order</a></h3> + + <p>Similar to elements, element wildcards in ordered types + (<a href="#2.8.4">Section 2.8.4, "Element Order"</a>) are assigned + content ids and are included in the content order sequence. + Continuing with the bank transactions example started in Section + 2.8.4, we can extend the batch by allowing custom transactions:</p> + + <pre class="xml"> +<complexType name="batch"> + <choice minOccurs="0" maxOccurs="unbounded"> + <element name="withdraw" type="withdraw"/> + <element name="deposit" type="deposit"/> + <any namespace="##other" processContents="lax"/> + </choice> +</complexType> + </pre> + + <p>This will lead to the following changes in the generated + <code>batch</code> C++ class:</p> + + <pre class="c++"> +class batch: public xml_schema::type +{ +public: + ... + + // any + // + typedef element_sequence any_sequence; + typedef any_sequence::iterator any_iterator; + typedef any_sequence::const_iterator any_const_iterator; + + static const std::size_t any_id = 3UL; + + const any_sequence& + any () const; + + any_sequence& + any (); + + void + any (const any_sequence&); + + ... +}; + </pre> + + <p>With this change we also need to update the iteration code to handle + the new content id:</p> + + <pre class="c++"> +for (batch::content_order_const_iterator i (b.content_order ().begin ()); + i != b.content_order ().end (); + ++i) +{ + switch (i->id) + { + ... + + case batch::any_id: + { + const DOMElement& e (b.any ()[i->index]); + ... + break; + } + + ... + } +} + </pre> + + <p>For the complete working code that shows the use of wildcards in + ordered types refer to the <code>order/element</code> example in + the <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <h3><a name="2.12.5">2.12.5 Mapping for <code>anyAttribute</code></a></h3> + + <p>For <code>anyAttribute</code> the type definitions consist of an alias + of the container type with name <code>any_attribute_set</code> + (or <code>any1_attribute_set</code>, etc., for subsequent wildcards + in the type definition), an alias of the iterator type with name + <code>any_attribute_iterator</code> (or <code>any1_attribute_iterator</code>, + etc., for subsequent wildcards in the type definition), and an alias + of the constant iterator type with name <code>any_attribute_const_iterator</code> + (or <code>any1_attribute_const_iterator</code>, etc., for subsequent + wildcards in the type definition). + </p> + + <p>The accessor functions come in constant and non-constant versions. + The constant accessor function returns a constant reference to the + container and can be used for read-only access. The non-constant + version returns an unrestricted reference to the container and can + be used for read-write access. + </p> + + <p>The modifier function expects an argument of type reference to + constant of the container type. The modifier function makes + a deep copy of its argument. For instance: + </p> + + + <pre class="xml"> +<complexType name="object"> + <sequence> + ... + </sequence> + <anyAttribute namespace="##other"/> +</complexType> + </pre> + + <p>is mapped to:</p> + + <pre class="c++"> +class object: public xml_schema::type +{ +public: + // Type definitions. + // + typedef attribute_set any_attribute_set; + typedef any_attribute_set::iterator any_attribute_iterator; + typedef any_attribute_set::const_iterator any_attribute_const_iterator; + + // Accessors. + // + const any_attribute_set& + any_attribute () const; + + any_attribute_set& + any_attribute (); + + // Modifier. + // + void + any_attribute (const any_attribute_set&); + + ... + +}; + </pre> + + <p>The <code>attribute_set</code> class is an associative container + similar to the <code>std::set</code> class template as defined by + the ISO/ANSI Standard for C++ (ISO/IEC 14882:1998, Section 23.3.3, + "Class template set") with the key being the attribute's name + and namespace. Unlike <code>std::set</code>, <code>attribute_set</code> + allows searching using names and namespaces instead of + <code>xercesc::DOMAttr</code> objects. It is defined in an + implementation-specific namespace and its interface is presented + below: + </p> + + <pre class="c++"> +class attribute_set +{ +public: + typedef xercesc::DOMAttr key_type; + typedef xercesc::DOMAttr value_type; + typedef xercesc::DOMAttr* pointer; + typedef const xercesc::DOMAttr* const_pointer; + typedef xercesc::DOMAttr& reference; + typedef const xercesc::DOMAttr& const_reference; + + typedef <implementation-defined> iterator; + typedef <implementation-defined> const_iterator; + typedef <implementation-defined> reverse_iterator; + typedef <implementation-defined> const_reverse_iterator; + + typedef <implementation-defined> size_type; + typedef <implementation-defined> difference_type; + typedef <implementation-defined> allocator_type; + +public: + attribute_set (xercesc::DOMDocument&); + + template <typename I> + attribute_set (const I& begin, const I& end, xercesc::DOMDocument&); + + attribute_set (const attribute_set&, xercesc::DOMDocument&); + + attribute_set& + operator= (const attribute_set&); + +public: + const_iterator + begin () const; + + const_iterator + end () const; + + iterator + begin (); + + iterator + end (); + + const_reverse_iterator + rbegin () const; + + const_reverse_iterator + rend () const; + + reverse_iterator + rbegin (); + + reverse_iterator + rend (); + +public: + size_type + size () const; + + size_type + max_size () const; + + bool + empty () const; + + void + clear (); + +public: + // Makes a deep copy. + // + std::pair<iterator, bool> + insert (const xercesc::DOMAttr&); + + // Assumes ownership. + // + std::pair<iterator, bool> + insert (xercesc::DOMAttr*); + + // Makes a deep copy. + // + iterator + insert (iterator position, const xercesc::DOMAttr&); + + // Assumes ownership. + // + iterator + insert (iterator position, xercesc::DOMAttr*); + + template <typename I> + void + insert (const I& begin, const I& end); + +public: + void + erase (iterator position); + + size_type + erase (const std::basic_string<C>& name); + + size_type + erase (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name); + + size_type + erase (const XMLCh* name); + + size_type + erase (const XMLCh* namespace_, const XMLCh* name); + + void + erase (iterator begin, iterator end); + +public: + size_type + count (const std::basic_string<C>& name) const; + + size_type + count (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name) const; + + size_type + count (const XMLCh* name) const; + + size_type + count (const XMLCh* namespace_, const XMLCh* name) const; + + iterator + find (const std::basic_string<C>& name); + + iterator + find (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name); + + iterator + find (const XMLCh* name); + + iterator + find (const XMLCh* namespace_, const XMLCh* name); + + const_iterator + find (const std::basic_string<C>& name) const; + + const_iterator + find (const std::basic_string<C>& namespace_, + const std::basic_string<C>& name) const; + + const_iterator + find (const XMLCh* name) const; + + const_iterator + find (const XMLCh* namespace_, const XMLCh* name) const; + +public: + // Note that the DOMDocument object of the two sets being + // swapped should be the same. + // + void + swap (attribute_set&); +}; + +bool +operator== (const attribute_set&, const attribute_set&); + +bool +operator!= (const attribute_set&, const attribute_set&); + </pre> + + <p>The following code shows how one could use this mapping:</p> + + <pre class="c++"> +void +f (object& o, const xercesc::DOMAttr& a) +{ + using namespace xercesc; + + object::any_attribute_set& s (o.any_attribute ()); + + // Iteration. + // + for (object::any_attribute_iterator i (s.begin ()); i != s.end (); ++i) + { + DOMAttr& a (*i); + } + + // Modification. + // + s.insert (a); // deep copy + DOMDocument& doc (o.dom_document ()); + s.insert (doc.createAttribute (...)); // assumes ownership + + // Searching. + // + object::any_attribute_iterator i (s.find ("name")); + i = s.find ("http://www.w3.org/XML/1998/namespace", "lang"); +} + </pre> + + <!-- Mapping for Mixed Content Models --> + + <h2><a name="2.13">2.13 Mapping for Mixed Content Models</a></h2> + + <p>For XML Schema types with mixed content models C++/Tree provides + mapping support only if the type is marked as ordered + (<a href="#2.8.4">Section 2.8.4, "Element Order"</a>). Use the + <code>--ordered-type-mixed</code> XSD compiler option to + automatically mark all types with mixed content as ordered.</p> + + <p>For an ordered type with mixed content, C++/Tree adds an extra + text content sequence that is used to store the text fragments. + This text content sequence is also assigned the content id and + its entries are included in the content order sequence, just + like elements. As a result, it is possible to capture the order + between elements and text fragments.</p> + + <p>As an example, consider the following schema that describes text + with embedded links:</p> + + <pre class="xml"> +<complexType name="anchor"> + <simpleContent> + <extension base="string"> + <attribute name="href" type="anyURI" use="required"/> + </extension> + </simpleContent> +</complexType> + +<complexType name="text" mixed="true"> + <sequence> + <element name="a" type="anchor" minOccurs="0" maxOccurs="unbounded"/> + </sequence> +</complexType> + </pre> + + <p>The generated <code>text</code> C++ class will provide the following + API (assuming it is marked as ordered):</p> + + <pre class="c++"> +class text: public xml_schema::type +{ +public: + // a + // + typedef anchor a_type; + typedef sequence<a_type> a_sequence; + typedef a_sequence::iterator a_iterator; + typedef a_sequence::const_iterator a_const_iterator; + + static const std::size_t a_id = 1UL; + + const a_sequence& + a () const; + + a_sequence& + a (); + + void + a (const a_sequence&); + + // text_content + // + typedef xml_schema::string text_content_type; + typedef sequence<text_content_type> text_content_sequence; + typedef text_content_sequence::iterator text_content_iterator; + typedef text_content_sequence::const_iterator text_content_const_iterator; + + static const std::size_t text_content_id = 2UL; + + const text_content_sequence& + text_content () const; + + text_content_sequence& + text_content (); + + void + text_content (const text_content_sequence&); + + // content_order + // + typedef xml_schema::content_order content_order_type; + typedef std::vector<content_order_type> content_order_sequence; + typedef content_order_sequence::iterator content_order_iterator; + typedef content_order_sequence::const_iterator content_order_const_iterator; + + const content_order_sequence& + content_order () const; + + content_order_sequence& + content_order (); + + void + content_order (const content_order_sequence&); + + ... +}; + </pre> + + <p>Given this interface we can iterate over both link elements + and text in content order. The following code fragment converts + our format to plain text with references.</p> + + <pre class="c++"> +const text& t = ... + +for (text::content_order_const_iterator i (t.content_order ().begin ()); + i != t.content_order ().end (); + ++i) +{ + switch (i->id) + { + case text::a_id: + { + const anchor& a (t.a ()[i->index]); + cerr << a << "[" << a.href () << "]"; + break; + } + case text::text_content_id: + { + const xml_schema::string& s (t.text_content ()[i->index]); + cerr << s; + break; + } + default: + { + assert (false); // Unknown content id. + } + } +} + </pre> + + <p>For the complete working code that shows the use of mixed content + in ordered types refer to the <code>order/mixed</code> example in + the <code>cxx/tree/</code> directory in the + <a href="https://cppget.org/xsd-examples">xsd-examples</a> + package.</p> + + <!-- Parsing --> + + + <h1><a name="3">3 Parsing</a></h1> + + <p>This chapter covers various aspects of parsing XML instance + documents in order to obtain corresponding tree-like object + model. + </p> + + <p>Each global XML Schema element in the form:</p> + + <pre class="xml"> +<element name="name" type="type"/> + </pre> + + <p>is mapped to 14 overloaded C++ functions in the form:</p> + + <pre class="c++"> +// Read from a URI or a local file. +// + +std::[unique|auto]_ptr<type> +name (const std::basic_string<C>& uri, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (const std::basic_string<C>& uri, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (const std::basic_string<C>& uri, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +// Read from std::istream. +// + +std::[unique|auto]_ptr<type> +name (std::istream&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +std::[unique|auto]_ptr<type> +name (std::istream&, + const std::basic_string<C>& id, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + const std::basic_string<C>& id, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (std::istream&, + const std::basic_string<C>& id, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +// Read from InputSource. +// + +std::[unique|auto]_ptr<type> +name (xercesc::InputSource&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (xercesc::InputSource&, + xml_schema::error_handler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (xercesc::InputSource&, + xercesc::DOMErrorHandler&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + + +// Read from DOM. +// + +std::[unique|auto]_ptr<type> +name (const xercesc::DOMDocument&, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + +std::[unique|auto]_ptr<type> +name (xml_schema::dom::[unique|auto]_ptr<xercesc::DOMDocument>, + xml_schema::flags = 0, + const xml_schema::properties& = xml_schema::properties ()); + </pre> + + <p>You can choose between reading an XML instance from a local file, + URI, <code>std::istream</code>, <code>xercesc::InputSource</code>, + or a pre-parsed DOM instance in the form of + <code>xercesc::DOMDocument</code>. All the parsing functions + return a dynamically allocated object model as either + <code>std::unique_ptr</code> or <code>std::auto_ptr</code>, + depending on the C++ standard selected. Each of these parsing + functions is discussed in more detail in the following sections. + </p> + + <h2><a name="3.1">3.1 Initializing the Xerces-C++ Runtime</a></h2> + + <p>Some parsing functions expect you to initialize the Xerces-C++ + runtime while others initialize and terminate it as part of their + work. The general rule is as follows: if a function has any arguments + or return a value that is an instance of a Xerces-C++ type, then + this function expects you to initialize the Xerces-C++ runtime. + Otherwise, the function initializes and terminates the runtime for + you. Note that it is legal to have nested calls to the Xerces-C++ + initialize and terminate functions as long as the calls are balanced. + </p> + + <p>You can instruct parsing functions that initialize and terminate + the runtime not to do so by passing the + <code>xml_schema::flags::dont_initialize</code> flag (see + <a href="#3.2">Section 3.2, "Flags and Properties"</a>). + </p> + + + <h2><a name="3.2">3.2 Flags and Properties</a></h2> + + <p>Parsing flags and properties are the last two arguments of every + parsing function. They allow you to fine-tune the process of + instance validation and parsing. Both arguments are optional. + </p> + + + <p>The following flags are recognized by the parsing functions:</p> + + <dl> + <dt><code>xml_schema::flags::keep_dom</code></dt> + <dd>Keep association between DOM nodes and the resulting + object model nodes. For more information about DOM association + refer to <a href="#5.1">Section 5.1, "DOM Association"</a>.</dd> + + <dt><code>xml_schema::flags::own_dom</code></dt> + <dd>Assume ownership of the DOM document passed. This flag only + makes sense together with the <code>keep_dom</code> flag in + the call to the parsing function with the + <code>xml_schema::dom::[unique|auto]_ptr<DOMDocument></code> + argument.</dd> + + <dt><code>xml_schema::flags::dont_validate</code></dt> + <dd>Do not validate instance documents against schemas.</dd> + + <dt><code>xml_schema::flags::dont_initialize</code></dt> + <dd>Do not initialize the Xerces-C++ runtime.</dd> + </dl> + + <p>You can pass several flags by combining them using the bit-wise OR + operator. For example:</p> + + <pre class="c++"> +using xml_schema::flags; + +std::unique_ptr<type> r ( + name ("test.xml", flags::keep_dom | flags::dont_validate)); + </pre> + + <p>By default, validation of instance documents is turned on even + though parsers generated by XSD do not assume instance + documents are valid. They include a number of checks that prevent + construction of inconsistent object models. This, + however, does not mean that an instance document that was + successfully parsed by the XSD-generated parsers is + valid per the corresponding schema. If an instance document is not + "valid enough" for the generated parsers to construct consistent + object model, one of the exceptions defined in + <code>xml_schema</code> namespace is thrown (see + <a href="#3.3">Section 3.3, "Error Handling"</a>). + </p> + + <p>For more information on the Xerces-C++ runtime initialization + refer to <a href="#3.1">Section 3.1, "Initializing the Xerces-C++ + Runtime"</a>. + </p> + + <p>The <code>xml_schema::properties</code> class allows you to + programmatically specify schema locations to be used instead + of those specified with the <code>xsi::schemaLocation</code> + and <code>xsi::noNamespaceSchemaLocation</code> attributes + in instance documents. The interface of the <code>properties</code> + class is presented below: + </p> + + <pre class="c++"> +class properties +{ +public: + void + schema_location (const std::basic_string<C>& namespace_, + const std::basic_string<C>& location); + void + no_namespace_schema_location (const std::basic_string<C>& location); +}; + </pre> + + <p>Note that all locations are relative to an instance document unless + they are URIs. For example, if you want to use a local file as your + schema, then you will need to pass + <code>file:///absolute/path/to/your/schema</code> as the location + argument. + </p> + + <h2><a name="3.3">3.3 Error Handling</a></h2> + + <p>As discussed in <a href="#2.2">Section 2.2, "Error Handling"</a>, + the mapping uses the C++ exception handling mechanism as its primary + way of reporting error conditions. However, to handle recoverable + parsing and validation errors and warnings, a callback interface maybe + preferred by the application.</p> + + <p>To better understand error handling and reporting strategies employed + by the parsing functions, it is useful to know that the + transformation of an XML instance document to a statically-typed + tree happens in two stages. The first stage, performed by Xerces-C++, + consists of parsing an XML document into a DOM instance. For short, + we will call this stage the XML-DOM stage. Validation, if not disabled, + happens during this stage. The second stage, + performed by the generated parsers, consist of parsing the DOM + instance into the statically-typed tree. We will call this stage + the DOM-Tree stage. Additional checks are performed during this + stage in order to prevent construction of inconsistent tree which + could otherwise happen when validation is disabled, for example.</p> + + <p>All parsing functions except the one that operates on a DOM instance + come in overloaded triples. The first function in such a triple + reports error conditions exclusively by throwing exceptions. It + accumulates all the parsing and validation errors of the XML-DOM + stage and throws them in a single instance of the + <code>xml_schema::parsing</code> exception (described below). + The second and the third functions in the triple use callback + interfaces to report parsing and validation errors and warnings. + The two callback interfaces are <code>xml_schema::error_handler</code> + and <code>xercesc::DOMErrorHandler</code>. For more information + on the <code>xercesc::DOMErrorHandler</code> interface refer to + the Xerces-C++ documentation. The <code>xml_schema::error_handler</code> + interface is presented below: + </p> + + <pre class="c++"> +class error_handler +{ +public: + struct severity + { + enum value + { + warning, + error, + fatal + }; + }; + + virtual bool + handle (const std::basic_string<C>& id, + unsigned long line, + unsigned long column, + severity, + const std::basic_string<C>& message) = 0; + + virtual + ~error_handler (); +}; + </pre> + + <p>The <code>id</code> argument of the <code>error_handler::handle</code> + function identifies the resource being parsed (e.g., a file name or + URI). + </p> + + <p>By returning <code>true</code> from the <code>handle</code> function + you instruct the parser to recover and continue parsing. Returning + <code>false</code> results in termination of the parsing process. + An error with the <code>fatal</code> severity level results in + termination of the parsing process no matter what is returned from + the <code>handle</code> function. It is safe to throw an exception + from the <code>handle</code> function. + </p> + + <p>The DOM-Tree stage reports error conditions exclusively by throwing + exceptions. Individual exceptions thrown by the parsing functions + are described in the following sub-sections. + </p> + + + <h3><a name="3.3.1">3.3.1 <code>xml_schema::parsing</code></a></h3> + + <pre class="c++"> +struct severity +{ + enum value + { + warning, + error + }; + + severity (value); + operator value () const; +}; + +struct error +{ + error (severity, + const std::basic_string<C>& id, + unsigned long line, + unsigned long column, + const std::basic_string<C>& message); + + severity + severity () const; + + const std::basic_string<C>& + id () const; + + unsigned long + line () const; + + unsigned long + column () const; + + const std::basic_string<C>& + message () const; +}; + +std::basic_ostream<C>& +operator<< (std::basic_ostream<C>&, const error&); + +struct diagnostics: std::vector<error> +{ +}; + +std::basic_ostream<C>& +operator<< (std::basic_ostream<C>&, const diagnostics&); + +struct parsing: virtual exception +{ + parsing (); + parsing (const diagnostics&); + + const diagnostics& + diagnostics () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::parsing</code> exception is thrown if there + were parsing or validation errors reported during the XML-DOM stage. + If no callback interface was provided to the parsing function, the + exception contains a list of errors and warnings accessible using + the <code>diagnostics</code> function. The usual conditions when + this exception is thrown include malformed XML instances and, if + validation is turned on, invalid instance documents. + </p> + + <h3><a name="3.3.2">3.3.2 <code>xml_schema::expected_element</code></a></h3> + + <pre class="c++"> +struct expected_element: virtual exception +{ + expected_element (const std::basic_string<C>& name, + const std::basic_string<C>& namespace_); + + + const std::basic_string<C>& + name () const; + + const std::basic_string<C>& + namespace_ () const; + + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::expected_element</code> exception is thrown + when an expected element is not encountered by the DOM-Tree stage. + The name and namespace of the expected element can be obtained using + the <code>name</code> and <code>namespace_</code> functions respectively. + </p> + + + <h3><a name="3.3.3">3.3.3 <code>xml_schema::unexpected_element</code></a></h3> + + <pre class="c++"> +struct unexpected_element: virtual exception +{ + unexpected_element (const std::basic_string<C>& encountered_name, + const std::basic_string<C>& encountered_namespace, + const std::basic_string<C>& expected_name, + const std::basic_string<C>& expected_namespace) + + + const std::basic_string<C>& + encountered_name () const; + + const std::basic_string<C>& + encountered_namespace () const; + + + const std::basic_string<C>& + expected_name () const; + + const std::basic_string<C>& + expected_namespace () const; + + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::unexpected_element</code> exception is thrown + when an unexpected element is encountered by the DOM-Tree stage. + The name and namespace of the encountered element can be obtained + using the <code>encountered_name</code> and + <code>encountered_namespace</code> functions respectively. If an + element was expected instead of the encountered one, its name + and namespace can be obtained using the <code>expected_name</code> and + <code>expected_namespace</code> functions respectively. Otherwise + these functions return empty strings. + </p> + + <h3><a name="3.3.4">3.3.4 <code>xml_schema::expected_attribute</code></a></h3> + + <pre class="c++"> +struct expected_attribute: virtual exception +{ + expected_attribute (const std::basic_string<C>& name, + const std::basic_string<C>& namespace_); + + + const std::basic_string<C>& + name () const; + + const std::basic_string<C>& + namespace_ () const; + + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::expected_attribute</code> exception is thrown + when an expected attribute is not encountered by the DOM-Tree stage. + The name and namespace of the expected attribute can be obtained using + the <code>name</code> and <code>namespace_</code> functions respectively. + </p> + + + <h3><a name="3.3.5">3.3.5 <code>xml_schema::unexpected_enumerator</code></a></h3> + + <pre class="c++"> +struct unexpected_enumerator: virtual exception +{ + unexpected_enumerator (const std::basic_string<C>& enumerator); + + const std::basic_string<C>& + enumerator () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::unexpected_enumerator</code> exception is thrown + when an unexpected enumerator is encountered by the DOM-Tree stage. + The enumerator can be obtained using the <code>enumerator</code> + functions. + </p> + + <h3><a name="3.3.6">3.3.6 <code>xml_schema::expected_text_content</code></a></h3> + + <pre class="c++"> +struct expected_text_content: virtual exception +{ + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::expected_text_content</code> exception is thrown + when a content other than text is encountered and the text content was + expected by the DOM-Tree stage. + </p> + + <h3><a name="3.3.7">3.3.7 <code>xml_schema::no_type_info</code></a></h3> + + <pre class="c++"> +struct no_type_info: virtual exception +{ + no_type_info (const std::basic_string<C>& type_name, + const std::basic_string<C>& type_namespace); + + const std::basic_string<C>& + type_name () const; + + const std::basic_string<C>& + type_namespace () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::no_type_info</code> exception is thrown + when there is no type information associated with a type specified + by the <code>xsi:type</code> attribute. This exception is thrown + by the DOM-Tree stage. The name and namespace of the type in question + can be obtained using the <code>type_name</code> and + <code>type_namespace</code> functions respectively. Usually, catching + this exception means that you haven't linked the code generated + from the schema defining the type in question with your application + or this schema has been compiled without the + <code>--generate-polymorphic</code> option. + </p> + + + <h3><a name="3.3.8">3.3.8 <code>xml_schema::not_derived</code></a></h3> + + <pre class="c++"> +struct not_derived: virtual exception +{ + not_derived (const std::basic_string<C>& base_type_name, + const std::basic_string<C>& base_type_namespace, + const std::basic_string<C>& derived_type_name, + const std::basic_string<C>& derived_type_namespace); + + const std::basic_string<C>& + base_type_name () const; + + const std::basic_string<C>& + base_type_namespace () const; + + + const std::basic_string<C>& + derived_type_name () const; + + const std::basic_string<C>& + derived_type_namespace () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::not_derived</code> exception is thrown + when a type specified by the <code>xsi:type</code> attribute is + not derived from the expected base type. This exception is thrown + by the DOM-Tree stage. The name and namespace of the expected + base type can be obtained using the <code>base_type_name</code> and + <code>base_type_namespace</code> functions respectively. The name + and namespace of the offending type can be obtained using the + <code>derived_type_name</code> and + <code>derived_type_namespace</code> functions respectively. + </p> + + <h3><a name="3.3.9">3.3.9 <code>xml_schema::no_prefix_mapping</code></a></h3> + + <pre class="c++"> +struct no_prefix_mapping: virtual exception +{ + no_prefix_mapping (const std::basic_string<C>& prefix); + + const std::basic_string<C>& + prefix () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::no_prefix_mapping</code> exception is thrown + during the DOM-Tree stage if a namespace prefix is encountered for + which a prefix-namespace mapping hasn't been provided. The namespace + prefix in question can be obtained using the <code>prefix</code> + function. + </p> + + <h2><a name="3.4">3.4 Reading from a Local File or URI</a></h2> + + <p>Using a local file or URI is the simplest way to parse an XML instance. + For example:</p> + + <pre class="c++"> +using std::unique_ptr; + +unique_ptr<type> r1 (name ("test.xml")); +unique_ptr<type> r2 (name ("https://www.codesynthesis.com/test.xml")); + </pre> + + <p>Or, in the C++98 mode:</p> + + <pre class="c++"> +using std::auto_ptr; + +auto_ptr<type> r1 (name ("test.xml")); +auto_ptr<type> r2 (name ("https://www.codesynthesis.com/test.xml")); + </pre> + + <h2><a name="3.5">3.5 Reading from <code>std::istream</code></a></h2> + + <p>When using an <code>std::istream</code> instance, you may also + pass an optional resource id. This id is used to identify the + resource (for example in error messages) as well as to resolve + relative paths. For instance:</p> + + <pre class="c++"> +using std::unique_ptr; + +{ + std::ifstream ifs ("test.xml"); + unique_ptr<type> r (name (ifs, "test.xml")); +} + +{ + std::string str ("..."); // Some XML fragment. + std::istringstream iss (str); + unique_ptr<type> r (name (iss)); +} + </pre> + + <h2><a name="3.6">3.6 Reading from <code>xercesc::InputSource</code></a></h2> + + <p>Reading from a <code>xercesc::InputSource</code> instance + is similar to the <code>std::istream</code> case except + the resource id is maintained by the <code>InputSource</code> + object. For instance:</p> + + <pre class="c++"> +xercesc::StdInInputSource is; +std::unique_ptr<type> r (name (is)); + </pre> + + <h2><a name="3.7">3.7 Reading from DOM</a></h2> + + <p>Reading from a <code>xercesc::DOMDocument</code> instance allows + you to setup a custom XML-DOM stage. Things like DOM + parser reuse, schema pre-parsing, and schema caching can be achieved + with this approach. For more information on how to obtain DOM + representation from an XML instance refer to the Xerces-C++ + documentation. In addition, the + <a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree Mapping + FAQ</a> shows how to parse an XML instance to a Xerces-C++ + DOM document using the XSD runtime utilities. + </p> + + <p>The last parsing function is useful when you would like to perform + your own XML-to-DOM parsing and associate the resulting DOM document + with the object model nodes. The automatic <code>DOMDocument</code> + pointer is reset and the resulting object model assumes ownership + of the DOM document passed. For example:</p> + + <pre class="c++"> +// C++11 version. +// +xml_schema::dom::unique_ptr<xercesc::DOMDocument> doc = ... + +std::unique_ptr<type> r ( + name (std::move (doc), + xml_schema::flags::keep_dom | xml_schema::flags::own_dom)); + +// At this point doc is reset to 0. + +// C++98 version. +// +xml_schema::dom::auto_ptr<xercesc::DOMDocument> doc = ... + +std::auto_ptr<type> r ( + name (doc, xml_schema::flags::keep_dom | xml_schema::flags::own_dom)); + +// At this point doc is reset to 0. + </pre> + + <h1><a name="4">4 Serialization</a></h1> + + <p>This chapter covers various aspects of serializing a + tree-like object model to DOM or XML. + In this regard, serialization is complimentary to the reverse + process of parsing a DOM or XML instance into an object model + which is discussed in <a href="#3">Chapter 3, + "Parsing"</a>. Note that the generation of the serialization code + is optional and should be explicitly requested with the + <code>--generate-serialization</code> option. See the + <a href="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information. + </p> + + <p>Each global XML Schema element in the form: + </p> + + + <pre class="xml"> +<xsd:element name="name" type="type"/> + </pre> + + <p>is mapped to 8 overloaded C++ functions in the form:</p> + + <pre class="c++"> +// Serialize to std::ostream. +// +void +name (std::ostream&, + const type&, + const xml_schema::namespace_fomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (std::ostream&, + const type&, + xml_schema::error_handler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (std::ostream&, + const type&, + xercesc::DOMErrorHandler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + + +// Serialize to XMLFormatTarget. +// +void +name (xercesc::XMLFormatTarget&, + const type&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (xercesc::XMLFormatTarget&, + const type&, + xml_schema::error_handler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + +void +name (xercesc::XMLFormatTarget&, + const type&, + xercesc::DOMErrorHandler&, + const xml_schema::namespace_infomap& = + xml_schema::namespace_infomap (), + const std::basic_string<C>& encoding = "UTF-8", + xml_schema::flags = 0); + + +// Serialize to DOM. +// +xml_schema::dom::[unique|auto]_ptr<xercesc::DOMDocument> +name (const type&, + const xml_schema::namespace_infomap& + xml_schema::namespace_infomap (), + xml_schema::flags = 0); + +void +name (xercesc::DOMDocument&, + const type&, + xml_schema::flags = 0); + </pre> + + <p>You can choose between writing XML to <code>std::ostream</code> or + <code>xercesc::XMLFormatTarget</code> and creating a DOM instance + in the form of <code>xercesc::DOMDocument</code>. Serialization + to <code>ostream</code> or <code>XMLFormatTarget</code> requires a + considerably less work while serialization to DOM provides + for greater flexibility. Each of these serialization functions + is discussed in more detail in the following sections. + </p> + + + <h2><a name="4.1">4.1 Initializing the Xerces-C++ Runtime</a></h2> + + <p>Some serialization functions expect you to initialize the Xerces-C++ + runtime while others initialize and terminate it as part of their + work. The general rule is as follows: if a function has any arguments + or return a value that is an instance of a Xerces-C++ type, then + this function expects you to initialize the Xerces-C++ runtime. + Otherwise, the function initializes and terminates the runtime for + you. Note that it is legal to have nested calls to the Xerces-C++ + initialize and terminate functions as long as the calls are balanced. + </p> + + <p>You can instruct serialization functions that initialize and terminate + the runtime not to do so by passing the + <code>xml_schema::flags::dont_initialize</code> flag (see + <a href="#4.3">Section 4.3, "Flags"</a>). + </p> + + <h2><a name="4.2">4.2 Namespace Infomap and Character Encoding</a></h2> + + <p>When a document being serialized uses XML namespaces, custom + prefix-namespace associations can to be established. If custom + prefix-namespace mapping is not provided then generic prefixes + (<code>p1</code>, <code>p2</code>, etc) are automatically assigned + to namespaces as needed. Also, if + you would like the resulting instance document to contain the + <code>schemaLocation</code> or <code>noNamespaceSchemaLocation</code> + attributes, you will need to provide namespace-schema associations. + The <code>xml_schema::namespace_infomap</code> class is used + to capture this information:</p> + + <pre class="c++"> +struct namespace_info +{ + namespace_info (); + namespace_info (const std::basic_string<C>& name, + const std::basic_string<C>& schema); + + std::basic_string<C> name; + std::basic_string<C> schema; +}; + +// Map of namespace prefix to namespace_info. +// +struct namespace_infomap: public std::map<std::basic_string<C>, + namespace_info> +{ +}; + </pre> + + <p>Consider the following associations as an example:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + </pre> + + <p>This map, if passed to one of the serialization functions, + could result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<t:name xmlns:t="https://www.codesynthesis.com/test" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://www.codesynthesis.com/test test.xsd"> + </pre> + + <p>As you can see, the serialization function automatically added namespace + mapping for the <code>xsi</code> prefix. You can change this by + providing your own prefix:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map["xsn"].name = "http://www.w3.org/2001/XMLSchema-instance"; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + </pre> + + <p>This could result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<t:name xmlns:t="https://www.codesynthesis.com/test" + xmlns:xsn="http://www.w3.org/2001/XMLSchema-instance" + xsn:schemaLocation="https://www.codesynthesis.com/test test.xsd"> + </pre> + + <p>To specify the location of a schema without a namespace you can use + an empty prefix as in the example below: </p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].schema = "test.xsd"; + </pre> + + <p>This would result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<name xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="test.xsd"> + </pre> + + <p>To make a particular namespace default you can use an empty + prefix, for example:</p> + + <pre class="c++"> +xml_schema::namespace_infomap map; + +map[""].name = "https://www.codesynthesis.com/test"; +map[""].schema = "test.xsd"; + </pre> + + <p>This could result in the following XML fragment:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<name xmlns="https://www.codesynthesis.com/test" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://www.codesynthesis.com/test test.xsd"> + </pre> + + + <p>Another bit of information that you can pass to the serialization + functions is the character encoding method that you would like to use. + Common values for this argument are <code>"US-ASCII"</code>, + <code>"ISO8859-1"</code>, <code>"UTF-8"</code>, + <code>"UTF-16BE"</code>, <code>"UTF-16LE"</code>, + <code>"UCS-4BE"</code>, and <code>"UCS-4LE"</code>. The default + encoding is <code>"UTF-8"</code>. For more information on + encoding methods see the + "<a href="http://en.wikipedia.org/wiki/Character_code">Character + Encoding</a>" article from Wikipedia. + </p> + + <h2><a name="4.3">4.3 Flags</a></h2> + + <p>Serialization flags are the last argument of every serialization + function. They allow you to fine-tune the process of serialization. + The flags argument is optional. + </p> + + + <p>The following flags are recognized by the serialization + functions:</p> + + <dl> + <dt><code>xml_schema::flags::dont_initialize</code></dt> + <dd>Do not initialize the Xerces-C++ runtime.</dd> + + <dt><code>xml_schema::flags::dont_pretty_print</code></dt> + <dd>Do not add extra spaces or new lines that make the resulting XML + slightly bigger but easier to read.</dd> + + <dt><code>xml_schema::flags::no_xml_declaration</code></dt> + <dd>Do not write XML declaration (<?xml ... ?>).</dd> + </dl> + + <p>You can pass several flags by combining them using the bit-wise OR + operator. For example:</p> + + <pre class="c++"> +std::unique_ptr<type> r = ... +std::ofstream ofs ("test.xml"); +xml_schema::namespace_infomap map; +name (ofs, + *r, + map, + "UTF-8", + xml_schema::flags::no_xml_declaration | + xml_schema::flags::dont_pretty_print); + </pre> + + <p>For more information on the Xerces-C++ runtime initialization + refer to <a href="#4.1">Section 4.1, "Initializing the Xerces-C++ + Runtime"</a>. + </p> + + <h2><a name="4.4">4.4 Error Handling</a></h2> + + <p>As with the parsing functions (see <a href="#3.3">Section 3.3, + "Error Handling"</a>), to better understand error handling and + reporting strategies employed by the serialization functions, it + is useful to know that the transformation of a statically-typed + tree to an XML instance document happens in two stages. The first + stage, performed by the generated code, consist of building a DOM + instance from the statically-typed tree . For short, we will call + this stage the Tree-DOM stage. The second stage, performed by + Xerces-C++, consists of serializing the DOM instance into the XML + document. We will call this stage the DOM-XML stage. + </p> + + <p>All serialization functions except the two that serialize into + a DOM instance come in overloaded triples. The first function + in such a triple reports error conditions exclusively by throwing + exceptions. It accumulates all the serialization errors of the + DOM-XML stage and throws them in a single instance of the + <code>xml_schema::serialization</code> exception (described below). + The second and the third functions in the triple use callback + interfaces to report serialization errors and warnings. The two + callback interfaces are <code>xml_schema::error_handler</code> and + <code>xercesc::DOMErrorHandler</code>. The + <code>xml_schema::error_handler</code> interface is described in + <a href="#3.3">Section 3.3, "Error Handling"</a>. For more information + on the <code>xercesc::DOMErrorHandler</code> interface refer to the + Xerces-C++ documentation. + </p> + + <p>The Tree-DOM stage reports error conditions exclusively by throwing + exceptions. Individual exceptions thrown by the serialization functions + are described in the following sub-sections. + </p> + + <h3><a name="4.4.1">4.4.1 <code>xml_schema::serialization</code></a></h3> + + <pre class="c++"> +struct serialization: virtual exception +{ + serialization (); + serialization (const diagnostics&); + + const diagnostics& + diagnostics () const; + + virtual const char* + what () const throw (); +}; + </pre> + + <p>The <code>xml_schema::diagnostics</code> class is described in + <a href="#3.3.1">Section 3.3.1, "<code>xml_schema::parsing</code>"</a>. + The <code>xml_schema::serialization</code> exception is thrown if + there were serialization errors reported during the DOM-XML stage. + If no callback interface was provided to the serialization function, + the exception contains a list of errors and warnings accessible using + the <code>diagnostics</code> function. + </p> + + + <h3><a name="4.4.2">4.4.2 <code>xml_schema::unexpected_element</code></a></h3> + + <p>The <code>xml_schema::unexpected_element</code> exception is + described in <a href="#3.3.3">Section 3.3.3, + "<code>xml_schema::unexpected_element</code>"</a>. It is thrown + by the serialization functions during the Tree-DOM stage if the + root element name of the provided DOM instance does not match with + the name of the element this serialization function is for. + </p> + + <h3><a name="4.4.3">4.4.3 <code>xml_schema::no_type_info</code></a></h3> + + <p>The <code>xml_schema::no_type_info</code> exception is + described in <a href="#3.3.7">Section 3.3.7, + "<code>xml_schema::no_type_info</code>"</a>. It is thrown + by the serialization functions during the Tree-DOM stage when there + is no type information associated with a dynamic type of an + element. Usually, catching this exception means that you haven't + linked the code generated from the schema defining the type in + question with your application or this schema has been compiled + without the <code>--generate-polymorphic</code> option. + </p> + + <h2><a name="4.5">4.5 Serializing to <code>std::ostream</code></a></h2> + + <p>In order to serialize to <code>std::ostream</code> you will need + an object model, an output stream and, optionally, a namespace + infomap. For instance:</p> + + <pre class="c++"> +// Obtain the object model. +// +std::unique_ptr<type> r = ... + +// Prepare namespace mapping and schema location information. +// +xml_schema::namespace_infomap map; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + +// Write it out. +// +name (std::cout, *r, map); + </pre> + + <p>Note that the output stream is treated as a binary stream. This + becomes important when you use a character encoding that is wider + than 8-bit <code>char</code>, for instance UTF-16 or UCS-4. For + example, things will most likely break if you try to serialize + to <code>std::ostringstream</code> with UTF-16 or UCS-4 as an + encoding. This is due to the special value, + <code>'\0'</code>, that will most likely occur as part of such + serialization and it won't have the special meaning assumed by + <code>std::ostringstream</code>. + </p> + + + <h2><a name="4.6">4.6 Serializing to <code>xercesc::XMLFormatTarget</code></a></h2> + + <p>Serializing to an <code>xercesc::XMLFormatTarget</code> instance + is similar the <code>std::ostream</code> case. For instance: + </p> + + <pre class="c++"> +using std::unique_ptr; + +// Obtain the object model. +// +unique_ptr<type> r = ... + +// Prepare namespace mapping and schema location information. +// +xml_schema::namespace_infomap map; + +map["t"].name = "https://www.codesynthesis.com/test"; +map["t"].schema = "test.xsd"; + +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Choose a target. + // + unique_ptr<XMLFormatTarget> ft; + + if (argc != 2) + { + ft = unique_ptr<XMLFormatTarget> (new StdOutFormatTarget ()); + } + else + { + ft = unique_ptr<XMLFormatTarget> ( + new LocalFileFormatTarget (argv[1])); + } + + // Write it out. + // + name (*ft, *r, map); +} + +XMLPlatformUtils::Terminate (); + </pre> + + <p>Note that we had to initialize the Xerces-C++ runtime before we + could call this serialization function.</p> + + <h2><a name="4.7">4.7 Serializing to DOM</a></h2> + + <p>The mapping provides two overloaded functions that implement + serialization to a DOM instance. The first creates a DOM instance + for you and the second serializes to an existing DOM instance. + While serializing to a new DOM instance is similar to serializing + to <code>std::ostream</code> or <code>xercesc::XMLFormatTarget</code>, + serializing to an existing DOM instance requires quite a bit of work + from your side. You will need to set all the custom namespace mapping + attributes as well as the <code>schemaLocation</code> and/or + <code>noNamespaceSchemaLocation</code> attributes. The following + listing should give you an idea about what needs to be done: + </p> + + <pre class="c++"> +// Obtain the object model. +// +std::unique_ptr<type> r = ... + +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Create a DOM instance. Set custom namespace mapping and schema + // location attributes. + // + DOMDocument& doc = ... + + // Serialize to DOM. + // + name (doc, *r); + + // Serialize the DOM document to XML. + // + ... +} + +XMLPlatformUtils::Terminate (); + </pre> + + <p>For more information on how to create and serialize a DOM instance + refer to the Xerces-C++ documentation. In addition, the + <a href="http://wiki.codesynthesis.com/Tree/FAQ">C++/Tree Mapping + FAQ</a> shows how to implement these operations using the XSD + runtime utilities. + </p> + + <h1><a name="5">5 Additional Functionality</a></h1> + + <p>The C++/Tree mapping provides a number of optional features + that can be useful in certain situations. They are described + in the following sections.</p> + + <h2><a name="5.1">5.1 DOM Association</a></h2> + + <p>Normally, after parsing is complete, the DOM document which + was used to extract the data is discarded. However, the parsing + functions can be instructed to preserve the DOM document + and create an association between the DOM nodes and object model + nodes. When there is an association between the DOM and + object model nodes, you can obtain the corresponding DOM element + or attribute node from an object model node as well as perform + the reverse transition: obtain the corresponding object model + from a DOM element or attribute node.</p> + + <p>Maintaining DOM association is normally useful when the application + needs access to XML constructs that are not preserved in the + object model, for example, XML comments. + Another useful aspect of DOM association is the ability of the + application to navigate the document tree using the generic DOM + interface (for example, with the help of an XPath processor) + and then move back to the statically-typed object model. Note + also that while you can change the underlying DOM document, + these changes are not reflected in the object model and will + be ignored during serialization. If you need to not only access + but also modify some aspects of XML that are not preserved in + the object model, then type customization with custom parsing + constructors and serialization operators should be used instead.</p> + + <p>To request DOM association you will need to pass the + <code>xml_schema::flags::keep_dom</code> flag to one of the + parsing functions (see <a href="#3.2">Section 3.2, + "Flags and Properties"</a> for more information). In this case the + DOM document is retained and will be released when the object model + is deleted. Note that since DOM nodes "out-live" the parsing function + call, you need to initialize the Xerces-C++ runtime before calling + one of the parsing functions with the <code>keep_dom</code> flag and + terminate it after the object model is destroyed (see + <a href="#3.1">Section 3.1, "Initializing the Xerces-C++ Runtime"</a>).</p> + + <p>If the <code>keep_dom</code> flag is passed + as the second argument to the copy constructor and the copy + being made is of a complete tree, then the DOM association + is also maintained in the copy by cloning the underlying + DOM document and reestablishing the associations. For example:</p> + + <pre class="c++"> +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Parse XML to object model. + // + std::unique_ptr<type> r (root ( + "root.xml", + xml_schema::flags::keep_dom | + xml_schema::flags::dont_initialize)); + + // Copy without DOM association. + // + type copy1 (*r); + + // Copy with DOM association. + // + type copy2 (*r, xml_schema::flags::keep_dom); +} + +XMLPlatformUtils::Terminate (); + </pre> + + + <p>To obtain the corresponding DOM node from an object model node + you will need to call the <code>_node</code> accessor function + which returns a pointer to <code>DOMNode</code>. You can then query + this DOM node's type and cast it to either <code>DOMAttr*</code> + or <code>DOMElement*</code>. To obtain the corresponding object + model node from a DOM node, the DOM user data API is used. The + <code>xml_schema::dom::tree_node_key</code> variable contains + the key for object model nodes. The following schema and code + fragment show how to navigate from DOM to object model nodes + and in the opposite direction:</p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="a" type="string"/> + </sequence> +</complexType> + +<element name="root" type="object"/> + </pre> + + <pre class="c++"> +using namespace xercesc; + +XMLPlatformUtils::Initialize (); + +{ + // Parse XML to object model. + // + std::unique_ptr<type> r (root ( + "root.xml", + xml_schema::flags::keep_dom | + xml_schema::flags::dont_initialize)); + + DOMNode* n = r->_node (); + assert (n->getNodeType () == DOMNode::ELEMENT_NODE); + DOMElement* re = static_cast<DOMElement*> (n); + + // Get the 'a' element. Note that it is not necessarily the + // first child node of 'root' since there could be whitespace + // nodes before it. + // + DOMElement* ae; + + for (n = re->getFirstChild (); n != 0; n = n->getNextSibling ()) + { + if (n->getNodeType () == DOMNode::ELEMENT_NODE) + { + ae = static_cast<DOMElement*> (n); + break; + } + } + + // Get from the 'a' DOM element to xml_schema::string object model + // node. + // + xml_schema::type& t ( + *reinterpret_cast<xml_schema::type*> ( + ae->getUserData (xml_schema::dom::tree_node_key))); + + xml_schema::string& a (dynamic_cast<xml_schema::string&> (t)); +} + +XMLPlatformUtils::Terminate (); + </pre> + + <p>The 'mixed' example which can be found in the XSD distribution + shows how to handle the mixed content using DOM association.</p> + + <h2><a name="5.2">5.2 Binary Serialization</a></h2> + + <p>Besides reading from and writing to XML, the C++/Tree 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 serialization saves only the data without any meta + information or markup. As a result, saving to and loading + from a binary representation can be an order of magnitude + faster than 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 binary serialization 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 operators and + extraction constructors 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="https://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD + Compiler Command Line Manual</a> for more information.</p> + + <p>Once the insertion operators and extraction constructors are + generated, you can use the <code>xml_schema::istream</code> + and <code>xml_schema::ostream</code> wrapper stream templates + to save the object model to and load it from a specific format. + The following code fragment shows how to do this using ACE + (Adaptive Communication Environment) CDR streams as an example:</p> + + <pre class="xml"> +<complexType name="object"> + <sequence> + <element name="a" type="string"/> + <element name="b" type="int"/> + </sequence> +</complexType> + +<element name="root" type="object"/> + </pre> + + <pre class="c++"> +// Parse XML to object model. +// +std::unique_ptr<type> r (root ("root.xml")); + +// Save to a CDR stream. +// +ACE_OutputCDR ace_ocdr; +xml_schema::ostream<ACE_OutputCDR> ocdr (ace_ocdr); + +ocdr << *r; + +// Load from a CDR stream. +// +ACE_InputCDR ace_icdr (buf, size); +xml_schema::istream<ACE_InputCDR> icdr (ace_icdr); + +std::unique_ptr<object> copy (new object (icdr)); + +// Serialize to XML. +// +root (std::cout, *copy); + </pre> + + <p>The XSD distribution contains a number of examples that + show how to save the object model to and load it from + CDR, XDR, and a custom format.</p> + + <!-- Appendix A --> + + + <h1><a name="A">Appendix A — Default and Fixed Values</a></h1> + + <p>The following table summarizes the effect of default and fixed + values (specified with the <code>default</code> and <code>fixed</code> + attributes, respectively) on attribute and element values. The + <code>default</code> and <code>fixed</code> attributes are mutually + exclusive. It is also worthwhile to note that the fixed value semantics + is a superset of the default value semantics. + </p> + + <!-- border="1" is necessary for html2ps --> + <table id="default-fixed" border="1"> + <tr> + <th></th> + <th></th> + <th colspan="2">default</th> + <th colspan="2">fixed</th> + </tr> + + <!-- element --> + + <tr> + <th rowspan="4">element</th> + <th rowspan="2">not present</th> + <th>optional</th> + <th>required</th> + <th>optional</th> + <th>required</th> + </tr> + <tr> + <td>not present</td> + <td>invalid instance</td> + <td>not present</td> + <td>invalid instance</td> + </tr> + + + <tr> + <th>empty</th> + <td colspan="2">default value is used</td> + <td colspan="2">fixed value is used</td> + </tr> + + <tr> + <th>value</th> + <td colspan="2">value is used</td> + <td colspan="2">value is used provided it's the same as fixed</td> + </tr> + + <!-- attribute --> + + <!-- element --> + + <tr> + <th rowspan="4">attribute</th> + <th rowspan="2">not present</th> + <th>optional</th> + <th>required</th> + <th>optional</th> + <th>required</th> + </tr> + <tr> + <td>default value is used</td> + <td>invalid schema</td> + <td>fixed value is used</td> + <td>invalid instance</td> + </tr> + + + <tr> + <th>empty</th> + <td colspan="2">empty value is used</td> + <td colspan="2">empty value is used provided it's the same as fixed</td> + </tr> + + <tr> + <th>value</th> + <td colspan="2">value is used</td> + <td colspan="2">value is used provided it's the same as fixed</td> + </tr> + + </table> + + </div> +</div> + + +</body> +</html> diff --git a/doc/cxx/tree/manual/manual.html2ps.in b/doc/cxx/tree/manual/manual.html2ps.in new file mode 100644 index 0000000..5629122 --- /dev/null +++ b/doc/cxx/tree/manual/manual.html2ps.in @@ -0,0 +1,66 @@ +@@html2ps { + option { + toc: hb; + colour: 1; + hyphenate: 1; + titlepage: 1; + } + + datefmt: "%B %Y"; + + titlepage { + content: " +<div align=center> + <h1><big>C++/Tree Mapping User Manual</big></h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> + <h1> </h1> +</div> + <p>Revision $[revision] $D</p> + <p>Copyright © @copyright@.</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href='https://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='https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/index.xhtml'>XHTML</a>, + <a href='https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.pdf'>PDF</a>, and + <a href='https://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/cxx-tree-manual.ps'>PostScript</a>.</p>"; + } + + toc { + indent: 2em; + } + + header { + odd-right: $H; + even-left: $H; + } + + footer { + odd-left: $D; + odd-center: $T, v$[revision]; + odd-right: $N; + + even-left: $N; + even-center: $T, v$[revision]; + even-right: $D; + } +} + +body { + font-size: 12pt; + text-align: justify; +} + +pre { + font-size: 10pt; +} |