diff options
Diffstat (limited to 'doc/cxx/hybrid')
-rw-r--r-- | doc/cxx/hybrid/guide/figure-1.png | bin | 0 -> 11933 bytes | |||
-rw-r--r-- | doc/cxx/hybrid/guide/figure-1.svg | 217 | ||||
-rw-r--r-- | doc/cxx/hybrid/guide/guide.html2ps | 65 | ||||
-rw-r--r-- | doc/cxx/hybrid/guide/index.xhtml | 6521 | ||||
-rw-r--r-- | doc/cxx/hybrid/guide/makefile | 48 |
5 files changed, 6851 insertions, 0 deletions
diff --git a/doc/cxx/hybrid/guide/figure-1.png b/doc/cxx/hybrid/guide/figure-1.png Binary files differnew file mode 100644 index 0000000..b89cec8 --- /dev/null +++ b/doc/cxx/hybrid/guide/figure-1.png diff --git a/doc/cxx/hybrid/guide/figure-1.svg b/doc/cxx/hybrid/guide/figure-1.svg new file mode 100644 index 0000000..ccc79cd --- /dev/null +++ b/doc/cxx/hybrid/guide/figure-1.svg @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="210mm" + height="297mm" + id="svg2471" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docname="hybrid.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="/home/boris/hybrid.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs3"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective2477" /> + </defs> + <sodipodi:namedview + inkscape:document-units="mm" + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.5980613" + inkscape:cx="243.67741" + inkscape:cy="741.86348" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1002" + inkscape:window-height="853" + inkscape:window-x="276" + inkscape:window-y="78"> + <inkscape:grid + type="xygrid" + id="grid2479" /> + </sodipodi:namedview> + <metadata + id="metadata4"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + style="opacity:1;fill:#ccdcee;fill-opacity:1;fill-rule:evenodd;stroke:#ccdcee;stroke-width:16.80470467;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect7825" + width="203.0603" + height="115.96954" + x="78.263054" + y="236.86377" /> + <rect + style="fill:#6e91bd;fill-opacity:1;fill-rule:evenodd;stroke:#6e91bd;stroke-width:18.24513817;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect2489" + width="169.64984" + height="20.998301" + x="95.946136" + y="265.48535" /> + <text + xml:space="preserve" + style="font-size:10.91242504px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold" + x="145.5929" + y="271.39957" + id="text7835" + sodipodi:linespacing="100%" + transform="scale(0.9741498,1.0265362)"><tspan + y="271.39957" + x="145.5929" + sodipodi:role="line" + id="tspan2585">Object Model</tspan></text> + <text + xml:space="preserve" + style="font-size:10.91242504px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold" + x="151.27502" + y="177.57848" + id="text2500" + sodipodi:linespacing="100%" + transform="scale(0.9741498,1.0265362)"><tspan + sodipodi:role="line" + id="tspan2570" + x="151.27502" + y="177.57848">Parser</tspan></text> + <g + id="g2631" + transform="matrix(0.7818522,0,0,0.7818522,12.112543,35.072306)"> + <rect + y="355.19925" + x="103.22679" + height="34.53841" + width="84.758575" + id="rect2532" + style="fill:#6e91bd;fill-opacity:1;fill-rule:evenodd;stroke:#6e91bd;stroke-width:16.53946114;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <text + transform="scale(0.9741498,1.0265362)" + sodipodi:linespacing="100%" + id="text2534" + y="366.63315" + x="124.96281" + style="font-size:13.95714664px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold" + xml:space="preserve"><tspan + y="366.63315" + x="124.96281" + id="tspan2603" + sodipodi:role="line">Parser</tspan></text> + </g> + <g + id="g2636" + transform="matrix(0.7818522,0,0,0.7818522,18.187466,35.76421)"> + <rect + y="354.78888" + x="232.87415" + height="34.474037" + width="85.579155" + id="rect2594" + style="fill:#6e91bd;fill-opacity:1;fill-rule:evenodd;stroke:#6e91bd;stroke-width:16.60383415;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <text + transform="scale(0.9741498,1.0265362)" + sodipodi:linespacing="100%" + id="text2596" + y="367.06186" + x="241.66556" + style="font-size:13.95714664px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold" + xml:space="preserve"><tspan + y="367.06186" + x="241.66556" + id="tspan2598" + sodipodi:role="line">Serializer</tspan></text> + </g> + <text + xml:space="preserve" + style="font-size:10.16407776px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + x="147.14096" + y="244.02005" + id="text2845" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan2610" + x="147.14096" + y="244.02005">C++/Hybrid</tspan></text> + <rect + style="opacity:1;fill:#ccdcee;fill-opacity:1;fill-rule:evenodd;stroke:#ccdcee;stroke-width:16.53161621;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect2617" + width="202.50182" + height="30.237684" + x="78.263412" + y="177.76631" /> + <text + xml:space="preserve" + style="font-size:10.16407776px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + x="147.56195" + y="196.06781" + id="text2619" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan2623" + x="147.56195" + y="196.06781">Application</tspan></text> + <rect + style="opacity:1;fill:#ccdcee;fill-opacity:1;fill-rule:evenodd;stroke:#ccdcee;stroke-width:15.20303345;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect2641" + width="85.640442" + height="29.708515" + x="77.687241" + y="382.08945" /> + <rect + style="opacity:1;fill:#ccdcee;fill-opacity:1;fill-rule:evenodd;stroke:#ccdcee;stroke-width:15.19906044;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect2643" + width="85.584244" + height="29.71249" + x="195.71512" + y="381.7876" /> + <text + xml:space="preserve" + style="font-size:10.16407776px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + x="88.750069" + y="400.15198" + id="text2645" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan2653" + x="88.750069" + y="400.15198">C++/Parser</tspan></text> + <text + xml:space="preserve" + style="font-size:10.16407776px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + x="196.68718" + y="400.15198" + id="text2649" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan2655" + x="196.68718" + y="400.15198">C++/Serializer</tspan></text> + </g> +</svg> diff --git a/doc/cxx/hybrid/guide/guide.html2ps b/doc/cxx/hybrid/guide/guide.html2ps new file mode 100644 index 0000000..92ef95d --- /dev/null +++ b/doc/cxx/hybrid/guide/guide.html2ps @@ -0,0 +1,65 @@ +@html2ps { + option { + toc: hb; + colour: 1; + hyphenate: 1; + titlepage: 1; + } + + datefmt: "%B %Y"; + + titlepage { + content: " +<div align=center> + <h1><big>Embedded C++/Hybrid 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 © 2005-2011 CODE SYNTHESIS TOOLS CC</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href='http://www.codesynthesis.com/licenses/fdl-1.2.txt'>GNU Free + Documentation License, version 1.2</a>; with no Invariant Sections, + no Front-Cover Texts and no Back-Cover Texts. + </p> + + <p>This document is available in the following formats: + <a href='http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/index.xhtml'>XHTML</a>, + <a href='http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/cxx-hybrid-e-guide.pdf'>PDF</a>, and + <a href='http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/cxx-hybrid-e-guide.ps'>PostScript</a>.</p>"; + } + + 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/hybrid/guide/index.xhtml b/doc/cxx/hybrid/guide/index.xhtml new file mode 100644 index 0000000..9bf3df1 --- /dev/null +++ b/doc/cxx/hybrid/guide/index.xhtml @@ -0,0 +1,6521 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> + +<head> + <title>Embedded C++/Hybrid Mapping Getting Started Guide</title> + + <meta name="copyright" content="© 2005-2011 Code Synthesis Tools CC"/> + <meta name="keywords" content="xsd,xml,schema,c++,mapping,data,binding,parse,serialize,create,modify,write,validation,embedded,mobile"/> + <meta name="description" content="Embedded C++/Hybrid Mapping Getting Started Guide"/> + + <link rel="stylesheet" type="text/css" href="../../../default.css" /> + +<style type="text/css"> + pre { + padding : 0 0 0 0em; + margin : 0em 0em 0em 0; + + font-size : 102% + } + + body { + min-width: 48em; + } + + h1 { + font-weight: bold; + font-size: 200%; + line-height: 1.2em; + } + + h2 { + font-weight : bold; + font-size : 150%; + + padding-top : 0.8em; + } + + h3 { + font-size : 140%; + padding-top : 0.8em; + } + + /* Adjust indentation for three levels. */ + #container { + max-width: 48em; + } + + #content { + padding: 0 0.1em 0 4em; + /*background-color: red;*/ + } + + #content h1 { + margin-left: -2.06em; + } + + #content h2 { + margin-left: -1.33em; + } + + /* Title page */ + + #titlepage { + padding: 2em 0 1em 0; + border-bottom: 1px solid black; + } + + #titlepage .title { + font-weight: bold; + font-size: 200%; + text-align: center; + } + + #titlepage #first-title { + padding: 1em 0 0.4em 0; + } + + #titlepage #second-title { + padding: 0.4em 0 2em 0; + } + + /* Lists */ + ul.list li, ol.list li { + padding-top : 0.3em; + padding-bottom : 0.3em; + } + + div.img { + text-align: center; + padding: 2em 0 2em 0; + } + + /* */ + dl dt { + padding : 0.8em 0 0 0; + } + + /* TOC */ + table.toc { + border-style : none; + border-collapse : separate; + border-spacing : 0; + + margin : 0.2em 0 0.2em 0; + padding : 0 0 0 0; + } + + table.toc tr { + padding : 0 0 0 0; + margin : 0 0 0 0; + } + + table.toc * td, table.toc * th { + border-style : none; + margin : 0 0 0 0; + vertical-align : top; + } + + table.toc * th { + font-weight : normal; + padding : 0em 0.1em 0em 0; + text-align : left; + white-space : nowrap; + } + + table.toc * table.toc th { + padding-left : 1em; + } + + table.toc * td { + padding : 0em 0 0em 0.7em; + text-align : left; + } + + /* Built-in table */ + #builtin { + margin: 2em 0 2em 0; + + border-collapse : collapse; + border : 1px solid; + border-color : #000000; + + font-size : 11px; + line-height : 14px; + } + + #builtin th, #builtin td { + border: 1px solid; + padding : 0.9em 0.9em 0.7em 0.9em; + } + + #builtin th { + background : #cde8f6; + } + + #builtin td { + text-align: left; + } +</style> + + +</head> + +<body> +<div id="container"> + <div id="content"> + + <div class="noprint"> + + <div id="titlepage"> + <div class="title" id="first-title">Embedded C++/Hybrid Mapping</div> + <div class="title" id="second-title">Getting Started Guide</div> + + <p>Copyright © 2005-2011 CODE SYNTHESIS TOOLS CC</p> + + <p>Permission is granted to copy, distribute and/or modify this + document under the terms of the + <a href="http://www.codesynthesis.com/licenses/fdl-1.2.txt">GNU Free + Documentation License, version 1.2</a>; with no Invariant Sections, + no Front-Cover Texts and no Back-Cover Texts. + </p> + + <p>This document is available in the following formats: + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/index.xhtml">XHTML</a>, + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/cxx-hybrid-e-guide.pdf">PDF</a>, and + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/hybrid/guide/cxx-hybrid-e-guide.ps">PostScript</a>.</p> + + </div> + + <h1>Table of Contents</h1> + + <table class="toc"> + <tr> + <th></th><td><a href="#0">Preface</a> + <table class="toc"> + <tr><th></th><td><a href="#0.1">About This Document</a></td></tr> + <tr><th></th><td><a href="#0.2">More Information</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>1</th><td><a href="#1">Introduction</a> + <table class="toc"> + <tr><th>1.1</th><td><a href="#1.1">Mapping Overview</a></td></tr> + <tr><th>1.2</th><td><a href="#1.2">Benefits</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>2</th><td><a href="#2">Hello World Example</a> + <table class="toc"> + <tr><th>2.1</th><td><a href="#2.1">Writing XML Document and Schema</a></td></tr> + <tr><th>2.2</th><td><a href="#2.2">Translating Schema to C++</a></td></tr> + <tr><th>2.3</th><td><a href="#2.3">Implementing Application Logic</a></td></tr> + <tr><th>2.4</th><td><a href="#2.4">Compiling and Running</a></td></tr> + <tr><th>2.5</th><td><a href="#2.5">Adding Serialization</a></td></tr> + <tr><th>2.6</th><td><a href="#2.6">A Minimal Version</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">Mapping Configuration</a> + <table class="toc"> + <tr><th>3.1</th><td><a href="#3.1">Standard Template Library</a></td></tr> + <tr><th>3.2</th><td><a href="#3.2">Input/Output Stream Library</a></td></tr> + <tr><th>3.3</th><td><a href="#3.3">C++ Exceptions</a></td></tr> + <tr><th>3.4</th><td><a href="#3.4">XML Schema Validation</a></td></tr> + <tr><th>3.5</th><td><a href="#3.5">64-bit Integer Type</a></td></tr> + <tr><th>3.6</th><td><a href="#3.6">Parser and Serializer Reuse</a></td></tr> + <tr><th>3.7</th><td><a href="#3.7">Support for Polymorphism</a></td></tr> + <tr><th>3.8</th><td><a href="#3.8">Custom Allocators</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>4</th><td><a href="#4">Working with Object Models</a> + <table class="toc"> + <tr><th>4.1</th><td><a href="#4.1">Namespaces</a></td></tr> + <tr><th>4.2</th><td><a href="#4.2">Memory Management</a></td></tr> + <tr><th>4.3</th><td><a href="#4.3">Enumerations</a></td></tr> + <tr><th>4.4</th><td><a href="#4.4">Attributes and Elements</a></td></tr> + <tr><th>4.5</th><td><a href="#4.5">Compositors</a></td></tr> + <tr><th>4.6</th><td><a href="#4.6">Accessing the Object Model</a></td></tr> + <tr><th>4.7</th><td><a href="#4.7">Modifying the Object Model</a></td></tr> + <tr><th>4.8</th><td><a href="#4.8">Creating the Object Model from Scratch</a></td></tr> + <tr><th>4.9</th><td><a href="#4.9">Customizing the Object Model</a></td></tr> + <tr><th>4.10</th><td><a href="#4.10">Polymorphic Object Models</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>5</th><td><a href="#5">Mapping for Built-In XML Schema Types</a> + <table class="toc"> + <tr><th>5.1</th><td><a href="#5.1">Mapping for <code>QName</code></a></td></tr> + <tr><th>5.2</th><td><a href="#5.2">Mapping for <code>NMTOKENS</code> and <code>IDREFS</code>s</a></td></tr> + <tr><th>5.3</th><td><a href="#5.3">Mapping for <code>base54Binary</code> and <code>hexBinary</code>s</a></td></tr> + <tr><th>5.4</th><td><a href="#5.4">Time Zone Representation</a></td></tr> + <tr><th>5.5</th><td><a href="#5.5">Mapping for <code>date</code></a></td></tr> + <tr><th>5.6</th><td><a href="#5.6">Mapping for <code>dateTime</code></a></td></tr> + <tr><th>5.7</th><td><a href="#5.7">Mapping for <code>duration</code></a></td></tr> + <tr><th>5.8</th><td><a href="#5.8">Mapping for <code>gDay</code></a></td></tr> + <tr><th>5.9</th><td><a href="#5.9">Mapping for <code>gMonth</code></a></td></tr> + <tr><th>5.10</th><td><a href="#5.10">Mapping for <code>gMonthDay</code></a></td></tr> + <tr><th>5.11</th><td><a href="#5.11">Mapping for <code>gYear</code></a></td></tr> + <tr><th>5.12</th><td><a href="#5.12">Mapping for <code>gYearMonth</code></a></td></tr> + <tr><th>5.13</th><td><a href="#5.13">Mapping for <code>time</code></a></td></tr> + <tr><th>5.14</th><td><a href="#5.14">Mapping for <code>anyType</code></a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>6</th><td><a href="#6">Parsing and Serialization</a> + <table class="toc"> + <tr><th>6.1</th><td><a href="#6.1">Customizing Parsers and Serializers</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>7</th><td><a href="#7">Binary Representation</a> + <table class="toc"> + <tr><th>7.1</th><td><a href="#7.1">CDR (Common Data Representation)</a></td></tr> + <tr><th>7.2</th><td><a href="#7.2">XDR (eXternal Data Representation)</a></td></tr> + <tr><th>7.3</th><td><a href="#7.3">Custom Representations</a></td></tr> + </table> + </td> + </tr> + + </table> + </div> + + <h1><a name="0">Preface</a></h1> + + <h2><a name="0.1">About This Document</a></h2> + + <p>The goal of this document is to provide you with an + understanding of the C++/Hybrid programming model and allow you + to efficiently evaluate XSD/e against your project's technical + requirements. As such, this document is intended for embedded + C++ developers and software architects who are looking for an + embedded XML processing solution. Prior experience with XML + and C++ is required to understand this document. Basic + understanding of XML Schema is advantageous but not expected + or required. + </p> + + + <h2><a name="0.2">More Information</a></h2> + + <p>Beyond this guide, you may also find the following sources of + information useful:</p> + + <ul class="list"> + <li><a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a></li> + + <li><a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml">Embedded + C++/Parser Mapping Getting Started Guide</a>. The C++/Hybrid + mapping uses C++/Parser for XML parsing.</li> + + <li><a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml">Embedded + C++/Serializer Mapping Getting Started Guide</a>. The C++/Hybrid + mapping uses C++/Serializer for XML serialization.</li> + + <li>The <code>INSTALL</code> file in the XSD/e distribution provides + build instructions for various platforms.</li> + + <li>The <code>examples/cxx/hybrid/</code> directory in the XSD/e + distribution contains a collection of examples and a README + file with an overview of each example.</li> + + <li>The <a href="http://www.codesynthesis.com/mailman/listinfo/xsde-users">xsde-users</a> + mailing list is the place to ask technical questions about XSD/e and the + Embedded C++/Hybrid mapping. Furthermore, the + <a href="http://www.codesynthesis.com/pipermail/xsde-users/">archives</a> + may already have answers to some of your questions.</li> + + </ul> + + <!-- Introduction --> + + <h1><a name="1">1 Introduction</a></h1> + + <p>Welcome to CodeSynthesis XSD/e and the Embedded C++/Hybrid mapping. + XSD/e is a dependency-free W3C XML Schema to C++ compiler for mobile, + embedded, and light-weight applications. Embedded C++/Hybrid is an XML + Schema to C++ mapping that represents the data stored in XML as a + light-weight, statically-typed, in-memory object model. + </p> + + <h2><a name="1.1">1.1 Mapping Overview</a></h2> + + <p>Based on a formal description of an XML vocabulary (schema), the + C++/Hybrid mapping produces a tree-like data structure suitable + for in-memory processing. The core of the mapping consists of C++ + classes that constitute the object model and are derived from + types defined in XML Schema. The C++/Hybrid mapping uses the + APIs provided by the + <a href="http://www.codesynthesis.com/products/xsde/c++/parser/">Embedded + C++/Parser</a> and + <a href="http://www.codesynthesis.com/products/xsde/c++/serializer/">Embedded + C++/Serializer</a> + mappings to perform validation and parsing of XML to the object + model and validation and serialization of the object model to + XML. The following diagram illustrates the high-level architecture + of the C++/Hybrid mapping:</p> + + <!-- align=center is needed for html2ps --> + <div class="img" align="center"><img src="figure-1.png"/></div> + + <p>The use of well-defined APIs presented by the C++/Parser and + C++/Serializer mappings for XML parsing and serialization + allows a number of advanced techniques, for example, customization + of parsing and serialization code, filtering of XML during + parsing or object model during serialization, as well as the hybrid, + partially event-driven, partially in-memory processing + where the XML document is delivered to the application as + parts of the object model. The last feature combines the + ease and convenience of the in-memory processing model + with the ability to minimize the use of RAM and process documents + that would otherwise not fit into memory. + </p> + + <p>Besides reading from and writing to XML, the C++/Hybrid mapping + also supports saving the object model to and loading it from a + number of predefined as well as custom binary formats. Binary + representations contain only the data without any meta information + or markup. Consequently, saving to and loading from a binary + format can be an order of magnitude faster as well as result + in a much smaller application footprint compared to parsing and + serializing the same data in XML. Furthermore, the resulting + representation is normally several times smaller than the equivalent + XML.</p> + + <p>The Embedded C++/Hybrid mapping was specifically designed and + optimized for mobile and embedded systems where hardware + constraints require high efficiency and economical use of + resources. As a result, the generated parsing and serialization + code is 2-10 times faster than general-purpose XML processors + while at the same time maintaining extremely low static and + dynamic memory footprints. For example, an executable that + performs validating XML parsing and serialization can be as small + as 150KB in size. The size can be further reduced by disabling + support for parsing or serialization as well as XML Schema + validation. + </p> + + <p>The generated code and the runtime library are also highly-portable + and, in their minimal configuration, can be used without STL, RTTI, + iostream, C++ exceptions, and with the minimal use of C++ templates.</p> + + <p>A typical application that uses the C++/Hybrid mapping for XML + processing performs the following three steps: it first + reads (parses) an XML document to an in-memory object model, it + then performs some useful computations on that object model which + may involve modification of the model, and finally it may write + (serialize) the modified object model back to XML. The next chapter + presents a simple application that performs these three steps. The + following chapters describe the Embedded C++/Hybrid mapping in more + detail.</p> + + <h2><a name="1.2">1.2 Benefits</a></h2> + + <p>Traditional XML access APIs such as Document Object Model (DOM) + or Simple API for XML (SAX) as well as general-purpose XML Schema + validators have a number of drawbacks that make them less suitable + for creating mobile and embedded XML processing applications. These + drawbacks include: + </p> + + <ul class="list"> + <li>Generic representation of XML in terms of elements, attributes, + and text forces an application developer to write a substantial + amount of bridging code that identifies and transforms pieces + of information encoded in XML to a representation more suitable + for consumption by the application logic.</li> + + <li>String-based flow control defers error detection to runtime. + It also reduces code readability and maintainability.</li> + + <li>Lack of type safety and inefficient use of resources due to + the data being represented as text.</li> + + <li>Extra validation code that is not used by the application.</li> + + <li>Resulting applications are hard to debug, change, and + maintain.</li> + </ul> + + <p>In contrast, a light-weight, statically-typed, vocabulary-specific + object model produced by the Embedded C++/Hybrid mapping allows + you to operate in your domain terms instead of the generic elements, + attributes, and text. Native data types are used to store the XML + data (for example, integers are stored as integers, not as text). + Validation code is included only for XML Schema constructs that + are used in the application. This results in efficient use of + resources and compact object code.</p> + + <p>Furthermore, static typing helps catch errors at + compile-time rather than at run-time. Automatic code generation + frees you for more interesting tasks (such as doing something + useful with the information stored in the XML documents) and + minimizes the effort needed to adapt your applications to changes + in the document structure. To summarize, the C++/Hybrid object + model has the following key advantages over generic XML access + APIs:</p> + + <ul class="list"> + <li><b>Ease of use.</b> The generated code hides all the complexity + associated with parsing and serializing XML. This includes navigating + the structure and converting between the text representation and + data types suitable for manipulation by the application logic.</li> + + <li><b>Natural representation.</b> The object representation allows + you to access the XML data using your domain vocabulary instead + of generic elements, attributes, and text.</li> + + <li><b>Concise code.</b> With the object representation the + application implementation is simpler and thus easier + to read and understand.</li> + + <li><b>Safety.</b> The generated object model is statically + typed and uses functions instead of strings to access the + information. This helps catch programming errors at compile-time + rather than at runtime.</li> + + <li><b>Maintainability.</b> Automatic code generation minimizes the + effort needed to adapt the application to changes in the + document structure. With static typing, the C++ compiler + can pin-point the places in the client code that need to be + changed.</li> + + <li><b>Efficiency.</b> If the application makes repetitive use + of the data extracted from XML, then the C++/Hybrid object model + is more efficient because the navigation is performed using + function calls rather than string comparisons and the XML + data is extracted only once. The runtime memory + usage is also reduced due to more efficient data storage + (for instance, storing numeric data as integers instead of + strings) as well as the static knowledge of cardinality + constraints. + + <p>Furthermore, the generated XML parsing and serialization code + combines validation and data-to-text conversion in a single step. + This makes the generated code much more efficient than traditional + architectures with separate stages for validation and data + conversion.</p> + </li> + </ul> + + <!-- Hello World Example --> + + + <h1><a name="2">2 Hello World Example</a></h1> + + <p>In this chapter we will examine how to parse, access, modify, and + serialize a very simple XML document using the generated + C++/Hybrid object model as well as the XML parser and serializer. The + code presented in this chapter is based on the <code>hello</code> + example which can be found in the <code>examples/cxx/hybrid/</code> + directory of the XSD/e distribution.</p> + + <h2><a name="2.1">2.1 Writing XML Document and Schema</a></h2> + + <p>First, we need to get an idea about the structure + of the XML documents we are going to process. Our + <code>hello.xml</code>, for example, could look like this:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<hello> + + <greeting>Hello</greeting> + + <name>sun</name> + <name>moon</name> + <name>world</name> + +</hello> + </pre> + + <p>Then we can write a description of the above XML in the + XML Schema language and save it into <code>hello.xsd</code>:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:complexType name="hello"> + <xs:sequence> + <xs:element name="greeting" type="xs:string"/> + <xs:element name="name" type="xs:string" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="hello" type="hello"/> + +</xs:schema> + </pre> + + <p>Even if you are not familiar with XML Schema, it + should be easy to connect declarations in <code>hello.xsd</code> + to elements in <code>hello.xml</code>. The <code>hello</code> type + is defined as a sequence of the nested <code>greeting</code> and + <code>name</code> elements. Note that the term sequence in XML + Schema means that elements should appear in a particular order + as opposed to appearing multiple times. The <code>name</code> + element has its <code>maxOccurs</code> property set to + <code>unbounded</code> which means it can appear multiple times + in an XML document. Finally, the globally-defined <code>hello</code> + element prescribes the root element for our vocabulary. For an + easily-approachable introduction to XML Schema refer to + <a href="http://www.w3.org/TR/xmlschema-0/">XML Schema Part 0: + Primer</a>.</p> + + <p>The above schema is a specification of our XML vocabulary; it tells + everybody what valid documents of our XML-based language should look + like. The next step is to compile the schema to generate the object + model and the parser.</p> + + + <h2><a name="2.2">2.2 Translating Schema to C++</a></h2> + + <p>Now we are ready to translate our <code>hello.xsd</code> to C++. + To do this we invoke the XSD/e compiler from a terminal (UNIX) or + a command prompt (Windows): + </p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-aggregate hello.xsd + </pre> + + <p>This invocation of the XSD/e compiler produces three pairs of C++ files: + <code>hello.hxx</code> and <code>hello.cxx</code>, + <code>hello-pskel.hxx</code> and <code>hello-pskel.cxx</code>, as well as + <code>hello-pimpl.hxx</code> and <code>hello-pimpl.cxx</code>. The + first pair contains the object model classes. The second pair contains + parser skeletons. Parser skeletons are generated by the C++/Parser + mapping which is automatically invoked by C++/Hybrid. + For now we can ignore parser skeletons except that we need to compile + them and link the result to our application. The last pair of files + contains parser implementations. They implement the parser skeletons + to create and populate the object model types from XML data. The generation + of parser skeletons and parser implementations is requested with the + <code>--generate-parser</code> XSD/e compiler option.</p> + + <p>You may be wondering what is the <code>--generate-aggregate</code> + option for. This option instructs the XSD/e compiler to generate + parser and, as we will see later, serializer aggregates. The + generated parser implementation files mentioned above contain + a separate parser implementation class for each type defined + in XML Schema. These parser implementations need to be + instantiated and connected before we can use them to parse an XML document. + When you specify the <code>--generate-aggregate</code> option, + the XSD/e compiler generates a class (in the parser implementation + files), called parser aggregate, for each global element defined + in the schema (you can also generate a parser aggregate for a type + as well as control for which global elements parser aggregates + are generated, see the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a> for more information). A parser + aggregate instantiates and connects all the necessary parser + implementations needed to parse an XML document with a given root + element. We will see how to use the parser aggregate for the + <code>hello</code> root element in the next section.</p> + + <p>The following code fragment is taken from <code>hello.hxx</code>; it + shows what the C++ object model for our "Hello World" XML vocabulary + looks like: + </p> + + <pre class="c++"> +class hello +{ +public: + hello (); + + // greeting + // + const std::string& + greeting () const; + + std::string& + greeting (); + + void + greeting (const std::string&); + + // name + // + typedef xml_schema::string_sequence name_sequence; + typedef name_sequence::iterator name_iterator; + typedef name_sequence::const_iterator name_const_iterator; + + const name_sequence& + name () const; + + name_sequence& + name (); + +private: + ... +}; + </pre> + + <p>The <code>hello</code> C++ class corresponds to the + <code>hello</code> XML Schema type. For each element + in this type a set of accessor and modifier functions + are generated inside the <code>hello</code> class. Note + that the member functions for the <code>greeting</code> and + <code>name</code> elements are different because of the + different cardinalities these two elements have + (<code>greeting</code> is a required single element and + <code>name</code> is a sequence of elements).</p> + + <p>It is also evident that the built-in XML Schema type + <code>string</code> is mapped to <code>std::string</code>. + The <code>string_sequence</code> class that is used in + the <code>name_sequence</code> type definition + has an interface similar to <code>std::vector</code>. The + mapping between the built-in XML Schema types and C++ types + is described in more detail in <a href="#5">Chapter 5, + "Mapping for Built-in XML Schema Types"</a>.</p> + + + <h2><a name="2.3">2.3 Implementing Application Logic</a></h2> + + <p>At this point we have all the parts we need to do something useful + with the information stored in our XML document: + </p> + + <pre class="c++"> +#include <iostream> + +#include "hello.hxx" +#include "hello-pimpl.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + // Parse. + // + hello_paggr hello_p; + xml_schema::document_pimpl doc_p (hello_p.root_parser (), + hello_p.root_name ()); + hello_p.pre (); + doc_p.parse (argv[1]); + hello* h = hello_p.post (); + + // Print what we've got. + // + for (hello::name_const_iterator i = h->name ().begin (); + i != h->name ().end (); + ++i) + { + cout << h->greeting () << ", " << *i << "!" << endl; + } + + delete h; + } + catch (const xml_schema::parser_exception& e) + { + cerr << argv[1] << ":" << e.line () << ":" << e.column () + << ": " << e.text () << endl; + return 1; + } +} + </pre> + + <p>The first part of our application creates a document parser + and parses the XML file specified in the command line to the + object model. The <code>hello_paggr</code> class is the parser + aggregate class we discussed earlier. Parsing is covered in more + detail in <a href="#6">Chapter 6, "Parsing and Serialization"</a>. + The second part uses the returned object model to iterate over + names and print a greeting line for each of them. We also catch + and print the <code>xml_schema::parser_exception</code> exception + in case something goes wrong. + </p> + + <h2><a name="2.4">2.4 Compiling and Running</a></h2> + + <p>After saving our application from the previous section in + <code>driver.cxx</code>, we are ready to compile our first + program and run it on the test XML document. On UNIX + this can be done with the following commands: + </p> + + <pre class="terminal"> +$ c++ -I.../libxsde -c driver.cxx hello.cxx hello-pskel.cxx \ + hello-pimpl.cxx + +$ c++ -o driver driver.o hello.o hello-pskel.o hello-pimpl.o \ + .../libxsde/xsde/libxsde.a + +$ ./driver hello.xml +Hello, sun! +Hello, moon! +Hello, world! + </pre> + + <p>Here <code>.../libxsde</code> represents the path to the + <code>libxsde</code> directory in the XSD/e distribution.</p> + + <p>We can also test the error handling. To test XML well-formedness + checking, we can try to parse <code>hello.hxx</code>:</p> + + <pre class="terminal"> +$ ./driver hello.hxx +hello.hxx:1:0: not well-formed (invalid token) + </pre> + + <p>We can also try to parse a valid XML but not from our + vocabulary, for example <code>hello.xsd</code>:</p> + + <pre class="terminal"> +$ ./driver hello.xsd +hello.xsd:2:57: unexpected element encountered + </pre> + + <h2><a name="2.5">2.5 Adding Serialization</a></h2> + + <p>While parsing and accessing the XML data may be everything + you need, there are applications that require creating new + or modifying existing XML documents. To request the generation + of serialization support we will need to add the + <code>--generate-serializer</code> option to our XSD/e + compiler invocation:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-serializer \ + --generate-aggregate hello.xsd + </pre> + + <p>This will result in two additional pairs of C++ files: + <code>hello-sskel.hxx</code> and <code>hello-sskel.cxx</code>, as well as + <code>hello-simpl.hxx</code> and <code>hello-simpl.cxx</code>. + Similar to the parser files, the first pair contains serializer + skeletons (generated by the C++/Serializer mapping) and the second + pair contains serializer implementations as well as the serializer + aggregate for the <code>hello</code> root element.</p> + + <p>Let us first examine an application that modifies an existing + object model and serializes it back to XML:</p> + + <pre class="c++"> +#include <iostream> + +#include "hello.hxx" +#include "hello-pimpl.hxx" +#include "hello-simpl.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + // Parse. + // + hello_paggr hello_p; + xml_schema::document_pimpl doc_p (hello_p.root_parser (), + hello_p.root_name ()); + hello_p.pre (); + doc_p.parse (argv[1]); + hello* h = hello_p.post (); + + // Change the greeting phrase. + // + h->greeting ("Hi"); + + // Add another entry to the name sequence. + // + h->name ().push_back ("mars"); + + // Serialize the modified object model to XML. + // + hello_saggr hello_s; + xml_schema::document_simpl doc_s (hello_s.root_serializer (), + hello_s.root_name ()); + hello_s.pre (*h); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + hello_s.post (); + + delete h; + } + catch (const xml_schema::parser_exception& e) + { + cerr << argv[1] << ":" << e.line () << ":" << e.column () + << ": " << e.text () << endl; + return 1; + } + catch (const xml_schema::serializer_exception& e) + { + cerr << "error: " << e.text () << endl; + return 1; + } +} + </pre> + + <p>First, our application parses an XML document and obtains its + object model as in the previous example. Then it changes the + greeting string and adds another entry to the list of names. + Finally, it creates a document serializer and serializes the + object model back to XML. The <code>hello_saggr</code> class + is the serializer aggregate class we discussed earlier.</p> + + <p>The resulting XML is written to the standard output (<code>cout</code>) + for us to inspect. We could have also written the result to a + file or memory buffer by creating an instance of <code>std::ofstream</code> + or <code>std::ostringstream</code> and passing it to + <code>serialize()</code> instead of <code>cout</code>. + The second argument in the call to + <code>serialize()</code> is a flag that requests pretty-printing + of the resulting XML document. You would normally specify this flag + during testing to obtain easily-readable XML and remove it + in production to get faster serialization and smaller documents. + Serialization is covered in more detail in <a href="#6">Chapter 6, + "Parsing and Serialization"</a>.</p> + + <p>If we now compile and run this application (don't forget to + compile and link <code>hello-sskel.cxx</code> and + <code>hello-simpl.cxx</code>), we will see the + output as shown in the following listing:</p> + + <pre class="xml"> +<hello> + <greeting>Hi</greeting> + <name>sun</name> + <name>moon</name> + <name>world</name> + <name>mars</name> +</hello> + </pre> + + <p> + We can also test XML Schema validation. We can "accidently" + remove all the names from the object model by adding the following + after: <code>push_back ("mars")</code>:</p> + + <pre class="c++"> +h->name ().clear (); + </pre> + + <p>This will violate our vocabulary specification which requires + at least one <code>name</code> element to be present. If we + make the above change and recompile our application, we will + get the following output:</p> + + <pre class="terminal"> +$ ./driver hello.xml +error: expected element not encountered + </pre> + + <p>It is also possible to create and serialize an object model from + scratch as shown in the following example. For this case we + can remove the <code>--generate-parser</code> option since + we don't need support for XML parsing.</p> + + <pre class="c++"> +#include <sstream> +#include <iostream> + +#include "hello.hxx" +#include "hello-simpl.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + hello h; + h.greeting ("Hi"); + + hello::name_sequence& ns = h.name (); + ns.push_back ("Jane"); + ns.push_back ("John"); + + // Serialize the object model to XML. + // + hello_saggr hello_s; + xml_schema::document_simpl doc_s (hello_s.root_serializer (), + hello_s.root_name ()); + ostringstream ostr; + + hello_s.pre (h); + doc_s.serialize (ostr, xml_schema::document_simpl::pretty_print); + hello_s.post (); + + cout << ostr.str () << endl; + } + catch (const xml_schema::serializer_exception& e) + { + cerr << "error: " << e.text () << endl; + return 1; + } +} + </pre> + + <p>In this example we used the generated default constructor to + create an empty instance of type <code>hello</code>. We then + set greeting and, to reduce typing, we obtained a reference to + the name sequence which we used to add a few names. The + serialization part is identical to the previous example except + this time we first save the XML representation into a string. + If we compile and run this program, it produces the following + output:</p> + + <pre class="xml"> +<hello> + <greeting>Hi</greeting> + <name>Jane</name> + <name>John</name> +</hello> + </pre> + + <h2><a name="2.6">2.6 A Minimal Version</a></h2> + + <p>The previous sections showed a number of examples that relied + on STL for strings, iostream of input/output and C++ exceptions + for error handling. + As was mentioned in the introduction and will be discussed + in further detail in the next chapter, the C++/Hybrid mapping + can be configured only to rely on the minimal subset of C++. + In this section we will implement an example that parses, + prints, modifies and serializes the object model without + relying on STL, iostream, or C++ exceptions.</p> + + <p>The first step is to instruct the XSD/e compiler not to use + any of the above features in the generated code. You may also + need to re-configure and rebuild the XSD/e runtime library + (<code>libxsde.a</code>) to disable STL, iostream, and + exceptions.</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --no-stl --no-iostream --no-exceptions \ + --generate-parser --generate-serializer --generate-aggregate \ + hello.xsd + </pre> + + <p>If you now study the generated <code>hello.hxx</code> file, + you will notice that the use of <code>std::string</code> type + is replaced with <code>char*</code>. When STL is disabled, + built-in XML Schema type <code>string</code> is mapped to a + C string. The following listing presents the content of + <code>driver.cxx</code> in full:</p> + + <pre class="c++"> +#include <stdio.h> + +#include "people.hxx" + +#include "people-pimpl.hxx" +#include "people-simpl.hxx" + +using namespace std; + +struct writer: xml_schema::writer +{ + virtual bool + write (const char* s, size_t n) + { + return fwrite (s, n, 1, stdout) == 1; + } + + virtual bool + flush () + { + return fflush (stdout) == 0; + } +}; + +int +main (int argc, char* argv[]) +{ + // Open the file or use STDIN. + // + FILE* f = fopen (argv[1], "rb"); + + if (f == 0) + { + fprintf (stderr, "%s: unable to open\n", argc); + return 1; + } + + // Parse. + // + using xml_schema::parser_error; + + parser_error pe; + bool io_error = false; + hello* h = 0; + + do + { + hello_paggr hello_p; + xml_schema::document_pimpl doc_p (hello_p.root_parser (), + hello_p.root_name ()); + if (pe = doc_p._error ()) + break; + + hello_p.pre (); + + if (pe = hello_p._error ()) + break; + + char buf[4096]; + + do + { + size_t s = fread (buf, 1, sizeof (buf), f); + + if (s != sizeof (buf) && ferror (f)) + { + io_error = true; + break; + } + + doc_p.parse (buf, s, feof (f) != 0); + pe = doc_p._error (); + + } while (!pe && !feof (f)); + + if (io_error || pe) + break; + + h = hello_p.post (); + pe = hello_p._error (); + + } while (false); + + fclose (f); + + // Handle parsing errors. + // + if (io_error) + { + fprintf (stderr, "%s: read failure\n", argc); + return 1; + } + + if (pe) + { + switch (pe.type ()) + { + case parser_error::sys: + { + fprintf (stderr, "%s: %s\n", argc, pe.sys_text ()); + break; + } + case parser_error::xml: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + argc, pe.line (), pe.column (), pe.xml_text ()); + break; + } + case parser_error::schema: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + argc, pe.line (), pe.column (), pe.schema_text ()); + break; + } + default: + break; + } + + return 1; + } + + // Print what we've got. + // + for (hello::name_const_iterator i = h->name ().begin (); + i != h->name ().end (); + ++i) + { + printf ("%s, %s!\n", h->greeting (), *i); + } + + using xml_schema::strdupx; + + // Change the greeting phrase. + // + char* str = strdupx ("Hi"); + + if (str == 0) + { + fprintf (stderr, "error: no memory\n"); + delete h; + return 1; + } + + h->greeting (str); + + // Add another entry to the name sequence. + // + str = strdupx ("mars"); + + if (str == 0) + { + fprintf (stderr, "error: no memory\n"); + delete h; + return 1; + } + + if (h->name ().push_back (str) != 0) + { + // The sequence has already freed str. + // + fprintf (stderr, "error: no memory\n"); + delete h; + return 1; + } + + // Serialize. + // + using xml_schema::serializer_error; + + serializer_error se; + writer w; + + do + { + hello_saggr hello_s; + xml_schema::document_simpl doc_s (hello_s.root_serializer (), + hello_s.root_name ()); + if (se = doc_s._error ()) + break; + + hello_s.pre (*h); + + if (se = hello_s._error ()) + break; + + doc_s.serialize (w, xml_schema::document_simpl::pretty_print); + + if (se = doc_s._error ()) + break; + + hello_s.post (); + + se = hello_s._error (); + + } while (false); + + delete h; + + // Handle serializer errors. + // + if (se) + { + switch (se.type ()) + { + case serializer_error::sys: + { + fprintf (stderr, "error: %s\n", se.sys_text ()); + break; + } + case serializer_error::xml: + { + fprintf (stderr, "error: %s\n", se.xml_text ()); + break; + } + case serializer_error::schema: + { + fprintf (stderr, "error: %s\n", se.schema_text ()); + break; + } + default: + break; + } + + return 1; + } +} + </pre> + + <p>The parsing and serialization parts of the above example got + quite a bit more complex due to the lack of exceptions and iostream + support. For more information on what's going on there, refer to + <a href="#6">Chapter 6, "Parsing and Serialization"</a>. On the other + hand, the access and modification of the object model stayed + relatively unchanged. The only noticeable change is the use + of the <code>xml_schema::strdupx</code> function to create + C strings from string literals. We have to use this function + because the object model assumes ownership of the strings + passed. We also cannot use the standard C <code>strdup</code> + because the object model expects the strings to be allocated + with C++ operator <code>new[]</code> while C <code>strdup</code> + uses <code>malloc</code> (on most implementations operator + <code>new</code> is implemented in terms of <code>malloc</code> + so you can probably use <code>strdup</code> if you really + want to).</p> + + + <!-- Mapping Configuration --> + + + <h1><a name="3">3 Mapping Configuration</a></h1> + + <p>The Embedded C++/Hybrid mapping has a number of configuration + parameters that determine the overall properties and behavior + of the generated code, such as the use of Standard Template + Library (STL), Input/Output Stream Library (iostream), C++ + exceptions, XML Schema validation, 64-bit integer types, as well as + parser and serializer implementation reuse styles. In the previous + chapter we have already got an overview of the changes to the + generated code that happen when we disable STL, iostream, and C++ + exceptions. In this chapter we will discuss these and other + configuration parameters in more detail.</p> + + <p>In order to enable or disable a particular feature, the corresponding + configuration parameter should be set accordingly in the XSD/e runtime + library as well as specified during schema compilation with the XSD/e + command line options as described in the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a>. + </p> + + <p>While the XML documents can use various encodings, the C++/Hybrid + object model always stores character data in the same encoding, + called application encoding. The application encoding can either be + UTF-8 (default) or ISO-8859-1. To select a particular encoding, configure + the XSD/e runtime library accordingly and pass the <code>--char-encoding</code> + option to the XSD/e compiler when translating your schemas.</p> + + <p>When using ISO-8859-1 as the application encoding, XML documents + being parsed may contain characters with Unicode values greater + than 0xFF which are unrepresentable in the ISO-8859-1 encoding. + By default, in such situations parsing will terminate with + an error. However, you can suppress the error by providing a + replacement character that should be used instead of + unrepresentable characters, for example:</p> + + <pre class="c++"> +xml_schema::iso8859_1::unrep_char ('?'); + </pre> + + <p>To revert to the default behavior, set the replacement character + to <code>'\0'</code>.</p> + + <p>The underlying XML parser used by the mapping includes built-in + support for XML documents encoded in UTF-8, UTF-16, ISO-8859-1, + and US-ASCII. Other encodings can be supported by providing + application-specific decoder functions. The underlying XML + serializer used by C++/Hybrid produces the resulting + XML documents in the UTF-8 encoding.</p> + + <h2><a name="3.1">3.1 Standard Template Library</a></h2> + + <p>To disable the use of STL you will need to configure the XSD/e + runtime without support for STL as well as pass the + <code>--no-stl</code> option to the XSD/e compiler when + translating your schemas.</p> + + <p>When STL is disabled, all string-based XML Schema types + (see <a href="#5">Chapter 5, "Mapping for Built-In XML Schema + Types"</a>) are mapped to C-style <code>char*</code> instead of + <code>std::string</code>. In this configuration when you set an + element or attribute value of a string-based type, the object + model assumes ownership of the string and expects that it was + allocated with operator <code>new[]</code>. To simplify + creation of such strings from string literals, the generated + code provides the <code>strdupx</code> and <code>strndupx</code> + functions in the <code>xml_schema</code> namespace. These functions + are similar to C <code>strdup</code> and <code>strndup</code> except + that they use operator <code>new[]</code> instead of <code>malloc</code> + to allocate the string:</p> + + <pre class="c++"> +namespace xml_schema +{ + char* + strdupx (const char*); + + char* + strndupx (const char*, size_t); +} + </pre> + + <h2><a name="3.2">3.2 Input/Output Stream Library</a></h2> + + <p>To disable the use of iostream you will need to configure the + XSD/e runtime library without support for iostream as well as + pass the <code>--no-iostream</code> option to the XSD/e compiler + when translating your schemas. When iostream is disabled, a + number of overloaded <code>parse()</code> and <code>serialize()</code> + functions in the document parser (<code>xml_schema::document_pimpl</code>) + and document serializer (<code>xml_schema::document_simpl</code>) become + unavailable. See + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#7">Chapter 7, + "Document Parser and Error Handling"</a> in the Embedded + C++/Parser Mapping Getting Started Guide and + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#8">Chapter 8, + "Document Serializer and Error Handling"</a> in the Embedded + C++/Serializer Mapping Getting Started Guide for details. + </p> + + <h2><a name="3.3">3.3 C++ Exceptions</a></h2> + + <p>To disable the use of C++ exceptions, you will need to configure + the XSD/e runtime without support for exceptions as well as pass + the <code>--no-exceptions</code> option to the XSD/e compiler + when translating your schemas. When C++ exceptions are disabled, + the error conditions that may arise while parsing, serializing, + and modifying the object model are indicated with error codes + instead of exceptions. For more information on error handling + during parsing, see + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#7">Chapter 7, + "Document Parser and Error Handling"</a> in the Embedded C++/Parser + Mapping Getting Started Guide. For more information on error handling + during serialization, see + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#8">Chapter 8, + "Document Serializer and Error Handling"</a> in the Embedded + C++/Serializer Mapping Getting Started Guide. For more information on + error handling in the object model, see <a href="#4">Chapter 4, "Working + with Object Models"</a> below. + </p> + + <h2><a name="3.4">3.4 XML Schema Validation</a></h2> + + <p>By default, XML Schema validation is enabled during both parsing + and serialization. To disable validation during parsing, you will + need to configure the XSD/e runtime to disable support for validation + in the C++/Parser mapping as well as pass the <code>--suppress-parser-val</code> + option to the XSD/e compiler when translating your schemas. To disable + validation during serialization, you will need to configure the XSD/e + runtime to disable support for validation in the C++/Serializer mapping + as well as pass the <code>--suppress-serializer-val</code> + option to the XSD/e compiler when translating your schemas. If you + are disabling validation during both parsing and serialization, you + can use the <code>--suppress-validation</code> option instead of the + two options mentioned above.</p> + + <p>Disabling XML Schema validation allows to further increase the + parsing and serialization performance as well as reduce footprint in + cases where the data being parsed and/or serialized is known + to be valid.</p> + + <h2><a name="3.5">3.5 64-bit Integer Type</a></h2> + + <p>By default the 64-bit <code>long</code> and <code>unsignedLong</code> + built-in XML Schema types are mapped to the 64-bit <code>long long</code> + and <code>unsigned long long</code> fundamental C++ types. To + disable the use of these types in the mapping you will need to + configure the XSD/e runtime accordingly as well as pass + the <code>--no-long-long</code> option to the XSD/e compiler + when translating your schemas. When the use of 64-bit integral + C++ types is disabled the <code>long</code> and + <code>unsignedLong</code> XML Schema built-in types are mapped + to <code>long</code> and <code>unsigned long</code> fundamental + C++ types.</p> + + <h2><a name="3.6">3.6 Parser and Serializer Reuse</a></h2> + + <p>When one type in XML Schema inherits from another, it is + often desirable to be able to reuse the parser and serializer + implementations corresponding to the base type in the parser + and serializer implementations corresponding to the derived type. + XSD/e provides support for two reuse styles: the so-called <em>mixin</em> + (generated when the <code>--reuse-style-mixin</code> option + is specified) and <em>tiein</em> (generated by default) styles. + The XSD/e runtime should be configured in accordance with the + reuse style used in the generated code. See <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#5.6">Section 5.6, + "Parser Reuse"</a> in the Embedded C++/Parser Mapping Getting Started + Guide and + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#6.6">Section 6.6, + "Serializer Reuse"</a> in the Embedded C++/Serializer Mapping Getting + Started Guide for details.</p> + + <h2><a name="3.7">3.7 Support for Polymorphism</a></h2> + + <p>By default the XSD/e compiler generates non-polymorphic code. If your + vocabulary uses XML Schema polymorphism in the form of <code>xsi:type</code> + and/or substitution groups, then you will need to configure the XSD/e + runtime with support for polymorphism, compile your schemas with the + <code>--generate-polymorphic</code> option to produce polymorphism-aware + code, as well as pass <code>true</code> as the last argument to the + <code>xml_schema::document_pimpl</code> and + <code>xml_schema::document_simpl</code> constructors (see + <a href="#6">Chapter 6, "Parsing and Serialization"</a> for details). + If some of your schemas do not require support for polymorphism then + you can compile them with the <code>--runtime-polymorphic</code> option + and still use the XSD/e runtime configured with polymorphism support. + </p> + + <p>The XSD/e compiler can often automatically determine which types are + polymorphic based on the substitution group declarations. However, + if your XML vocabulary is not using substitution groups or if + substitution groups are defined in a separate schema, then you will + need to use the <code>--polymorphic-type</code> option to specify + which types are polymorphic. When using this option you only need + to specify the root of a polymorphic type hierarchy and the XSD/e + compiler will assume that all the derived types are also polymorphic. + Also note that you need to specify this option when compiling every + schema file that references the polymorphic type. Consider the following + two schemas as an example:</p> + + <pre class="xml"> +<!-- base.xsd --> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:complexType name="base"> + <xs:sequence> + <xs:element name="b" type="xs:int"/> + </xs:sequence> + </xs:complexType> + + <!-- substitution group root --> + <xs:element name="base" type="base"/> + +</xs:schema> + </pre> + + <pre class="xml"> +<!-- derived.xsd --> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <include schemaLocation="base.xsd"/> + + <xs:complexType name="derived"> + <xs:complexContent> + <xs:extension base="base"> + <xs:sequence> + <xs:element name="d" type="xs:string"/> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + + <xs:element name="derived" type="derived" substitutionGroup="base"/> + +</xs:schema> + </pre> + + <p>In this example we need to specify "<code>--polymorphic-type base</code>" + when compiling both schemas because the substitution group is declared + in a schema other than the one defining type <code>base</code>.</p> + + <p>Another issue that may arise when compiling polymorphic schemas is + the situation where the XSD/e compiler is unaware of all the + derivations of a polymorphic type while generating parser and + serializer aggregates. As a result, the generated code may not + be able to parse and serialize these "invisible" to the compiler + types. The following example will help illustrate this case. + Consider a modified version of <code>base.xsd</code> from the + above example:</p> + + <pre class="xml"> +<!-- base.xsd --> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:complexType name="base"> + <xs:sequence> + <xs:element name="b" type="xs:int"/> + </xs:sequence> + </xs:complexType> + + <!-- substitution group root --> + <xs:element name="base" type="base"/> + + <xs:complexType name="root"> + <xs:sequence> + <xs:element ref="base" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <!-- document root --> + <xs:element name="root" type="root"/> + +</xs:schema> + </pre> + + <p>Suppose we compile this schema as follows:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base \ +--generate-aggregate --root-element root base.xsd + </pre> + + <p>The resulting parser and serializer aggregates for the <code>root</code> + element will not include the parser and serializer for the + <code>derived</code> type that can be used instead of the + <code>base</code> type. This is because the XSD/e compiler + has no knowledge of the <code>derived</code>'s existence when + compiling <code>base.xsd</code>.</p> + + <p>There are two ways to overcome this problem. The easier but + potentially slower approach is to compile all your schemas + at once, for example:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base \ +--generate-aggregate --root-element root base.xsd derived.xsd + </pre> + + <p>This will make sure the XSD/e compiler "sees" all the derivations + of the polymorphic types. The other approach allows + you to explicitly specify, with the <code>--polymorphic-schema</code> + option, additional schemas that may contain derivations of the + polymorphic types. Using this approach we would compile + <code>base.xsd</code> and <code>derived.xsd</code> like this:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base \ +--generate-aggregate --root-element root \ +--polymorphic-schema derived.xsd base.xsd + +$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base derived.xsd + </pre> + + <p>For information on how to use object models with polymorphic types, + refer to <a href="#4.10">Section 4.10, "Polymorphic Object Models"</a>.</p> + + <h2><a name="3.8">3.8 Custom Allocators</a></h2> + + <p>By default the XSD/e runtime and generated code use + the standard operators <code>new</code> and <code>delete</code> + to manage dynamic memory. However, it is possible to instead + use custom allocator functions provided by your application. + To achieve this, configure the XSD/e runtime library to use + custom allocator functions as well as pass the + <code>--custom-allocator</code> option to the XSD/e compiler + when translating your schemas. The signatures of the custom + allocator functions that should be provided by your application + are listed below. Their semantics should be equivalent to the + standard C <code>malloc()</code>, <code>realloc()</code>, and + <code>free()</code> functions.</p> + + <pre class="c++"> +extern "C" void* +xsde_alloc (size_t); + +extern "C" void* +xsde_realloc (void*, size_t); + +extern "C" void +xsde_free (void*); + </pre> + + <p>Note also that when custom allocators are enabled, any + dynamically-allocated object of which the XSD/e runtime + or generated code assume ownership should be allocated + using the custom allocation function. Similarly, if your + application assumes ownership of any dynamically-allocated + object returned by the XSD/e runtime or the generated code, + then such an object should be disposed of using the custom + deallocation function. To help with these tasks the generated + <code>xml_schema</code> namespace defines the following two + helper functions and, if C++ exceptions are enabled, automatic + pointer class:</p> + + <pre class="c++"> +namespace xml_schema +{ + void* + alloc (size_t); + + void + free (void*); + + struct alloc_guard + { + alloc_guard (void*); + ~alloc_guard (); + + void* + get () const; + + void + release (); + + private: + ... + }; +} + </pre> + + <p>If C++ exceptions are disabled, these functions are equivalent + to <code>xsde_alloc()</code> and <code>xsde_free()</code>. + If exceptions are enabled, <code>xml_schema::alloc()</code> + throws <code>std::bad_alloc</code> on memory allocation failure.</p> + + <p>The following code fragment shows how to create and destroy a + dynamically-allocated object with custom allocators when C++ + exceptions are disabled:</p> + + <pre class="c++"> +void* v = xml_schema::alloc (sizeof (type)); + +if (v == 0) +{ + // Handle out of memory condition. +} + +type* x = new (v) type (1, 2); + +... + +if (x) +{ + x->~type (); + xml_schema::free (x); +} + </pre> + + <p>The equivalent code fragment for configurations with C++ exceptions + enabled is shown below:</p> + + <pre class="c++"> +xml_schema::alloc_guard g (xml_schema::alloc (sizeof (type))); +type* x = new (g.get ()) type (1, 2); +g.release (); + +... + +if (x) +{ + x->~type (); + xml_schema::free (x); +} + </pre> + + <p>For a complete example that shows how to use custom allocators, see + the <code>allocator</code> example which can be found in the + <code>examples/cxx/hybrid/</code> directory of the XSD/e distribution.</p> + + <!-- Chapater 4 --> + + + <h1><a name="4">4 Working with Object Models</a></h1> + + <p>As we have seen in the previous chapters, the XSD/e compiler generates + a C++ class for each type defined in XML Schema. Together these classes + constitute an object model for an XML vocabulary. In this chapter we + will take a closer look at different parts that comprise an + object model class as well as how to create, access, and modify + object models.</p> + + <p>In this chapter we will use the following schema that describes a + collection of person records. We save it in <code>people.xsd</code>:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:simpleType name="gender"> + <xs:restriction base="xs:string"> + <xs:enumeration value="male"/> + <xs:enumeration value="female"/> + </xs:restriction> + </xs:simpleType> + + <xs:complexType name="person"> + <xs:sequence> + <xs:element name="first-name" type="xs:string"/> + <xs:element name="middle-name" type="xs:string" minOccurs="0"/> + <xs:element name="last-name" type="xs:string"/> + <xs:element name="gender" type="gender"/> + <xs:element name="age" type="xs:unsignedShort"/> + </xs:sequence> + <xs:attribute name="id" type="xs:unsignedInt" use="required"/> + </xs:complexType> + + <xs:complexType name="people"> + <xs:sequence> + <xs:element name="person" type="person" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="people" type="people"/> + +</xs:schema> + </pre> + + <p>A sample XML instance to go along with this schema is saved + in <code>people.xml</code>:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<people> + + <person id="1"> + <first-name>John</first-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>32</age> + </person> + + <person id="2"> + <first-name>Jane</first-name> + <middle-name>Mary</middle-name> + <last-name>Doe</last-name> + <gender>female</gender> + <age>28</age> + </person> + +</people> + </pre> + + <p>Compiling <code>people.xsd</code> with the XSD/e compiler results + in three generated object model classes: <code>gender</code>, + <code>person</code> and <code>people</code>. Here is how they + look with STL enabled:</p> + + <pre class="c++"> +// gender (fixed-length) +// +class gender +{ +public: + enum value_type + { + male, + female + }; + + gender (); + gender (value_type); + gender (const gender&); + gender& operator= (const gender&); + + void + value (value_type); + + operator value_type () const; + + const char* + string () const; + +private: + ... +}; + +// person (fixed-length) +// +class person +{ +public: + person (); + person (const person&); + person& operator= (const person&); + + // id + // + unsigned int + id () const; + + unsigned int& + id (); + + void + id (unsigned int); + + // first-name + // + const std::string& + first_name () const; + + std::string& + first_name (); + + void + first_name (const std::string&); + + // middle-name + // + bool + middle_name_present () const; + + void + middle_name_present (bool); + + const std::string& + middle_name () const; + + std::string& + middle_name (); + + void + middle_name (const std::string&); + + // last-name + // + const std::string& + last_name () const; + + std::string& + last_name (); + + void + last_name (const std::string&); + + // gender + // + const ::gender& + gender () const; + + ::gender& + gender (); + + void + gender (const ::gender&); + + // age + // + unsigned short + age () const; + + unsigned short& + age (); + + void + age (unsigned short); + +private: + ... +}; + +// people (variable-length) +// +class people +{ +public: + people (); + +private: + people (const people&); + people& operator= (const people&); + +public: + // person + // + typedef xml_schema::fix_sequence<person> person_sequence; + typedef person_sequence::iterator person_iterator; + typedef person_sequence::const_iterator person_const_iterator; + + const person_sequence& + person () const; + + person_sequence& + person (); + +private: + ... +}; + </pre> + + <p>We will examine these classes in detail in the subsequent + sections.</p> + + <h2><a name="4.1">4.1 Namespaces</a></h2> + + <p>XSD/e maps XML namespaces specified in the <code>targetNamespace</code> + attribute in XML Schema to one or more nested C++ namespaces. By + default, a namespace URI is mapped to a sequence of C++ namespace + names by removing the protocol and host parts and splitting the + rest into a sequence of names with <code>'/'</code> as the name + separator. For example, the <code>http://www.codesynthesis.com/cs/my</code> + XML namespace is mapped to the <code>cs::my</code> C++ namespace.</p> + + <p>The default mapping of namespace URIs to C++ namespaces + can be altered using the <code>--namespace-map</code> and + <code>--namespace-regex</code> compiler options. For example, + to map the <code>http://www.codesynthesis.com/my</code> XML + namespace to the <code>cs::my</code> C++ namespace, we can use + the following option:</p> + + <pre class="terminal"> +--namespace-map http://www.codesynthesis.com/my=cs::my + </pre> + + <p>A vocabulary without a namespace is mapped to the global scope. This + also can be altered with the above options by using an empty name + for the XML namespace. For example, we could place the generated + object model classes for the <code>people.xsd</code> schema + into the <code>records</code> C++ namespace by adding the following + option:</p> + + <pre class="terminal"> +--namespace-map =records + </pre> + + + <h2><a name="4.2">4.2 Memory Management</a></h2> + + <p>To ensure that objects are allocated and passed efficiently, + the C++/Hybrid mapping divides all object model types into + fixed-length and variable-length. A type is variable-length + if any of the following is true:</p> + + <ol class="list"> + <li>it is an XML Schema <code>list</code> type</li> + + <li>it is an XML Schema <code>union</code> type and STL is disabled</li> + + <li>it derives from a variable-length type</li> + + <li>it contains an element or attribute of a variable-length type</li> + + <li>it contains an element or compositor (<code>sequence</code> + or <code>choice</code>) with <code>maxOccurs</code> + greater than one</li> + + <li>it is recursive (that is, one of its elements contains + a reference, directly or indirectly, to the type itself)</li> + + <li>it is polymorphic (see <a href="#4.10">Section 4.10, "Polymorphic + Object Models"</a> for details)</li> + </ol> + + <p>The following build-in XML Schema types are variable-length: + <code>base64Binary</code>, <code>hexBinary</code>, <code>NMTOKENS</code>, + and <code>IDREFS</code>. Furthermore, if STL is disabled, all + string-based build-in XML Schema types are variable-length, + namely: <code>string</code>, <code>normalizedString</code>, + <code>token</code>, <code>Name</code>, <code>NMTOKEN</code>, + <code>NCName</code>, <code>language</code>, <code>QName</code>, + <code>ID</code>, <code>IDFER</code>, and <code>anyURI</code>.</p> + + <p>Otherwise, a type is fixed-length. As you might have noticed from + the previous code listings, the XSD/e compiler adds a comment before + each generated object model class that states whether it is fixed or + variable-length. For example, the <code>people</code> type is + variable-length because it contains a sequence of <code>person</code> + elements (<code>maxOccurs="unbounded"</code>). If we recompile + the <code>people.xsd</code> schema with the <code>--no-stl</code> + option, the <code>person</code> type will also become variable-length + since it contains elements of the <code>string</code> built-in type. + And when STL is disabled, <code>string</code> is variable-length.</p> + + <p>The object model uses different methods for storing and passing + around fixed-length and variable-length types. Instances of + fixed-length types are stored and passed by value since it is + cheaper to copy than to allocate them dynamically (in the + STL case, the <code>std::string</code> is expected to support the + referenced-counted copy-on-write optimization, which makes + copying cheap).</p> + + <p>Variable-length types are always allocated dynamically and + are stored and passed as pointers. Because copying an instance + of a variable-length type can be expensive, such types make + their copy constructor and copy assignment operators unavailable.</p> + + <p>When you set a value of an element or attribute of a + variable-length type, the object model assumes ownership of + the pointed to object. Unless you are using custom allocators + (see <a href="#3.8">Section 3.8, "Custom Allocators"</a>), + the object model expects you to allocate such an object with + operator <code>new</code> and will eventually delete it + with operator <code>delete</code>.</p> + + <p>If you wish to make copies of variable-length objects, then + you can request the generation of the object cloning functions + with the <code>--generate-clone</code> compiler + option. When this option is specified, each variable-length + type implements the <code>_clone()</code> function which returns + a dynamically-allocated copy of the object or <code>NULL</code> + if the allocation failed and C++ exceptions are disabled (see + <a href="#3.3">Section 3.3, "C++ Exceptions"</a>). </p> + + <p>You can also request generation of detach functions with the + <code>--generate-detach</code> compiler option. These functions + allow you to detach a variable-length object from the object model. + As an example, let us extend + our <code>people.xsd</code> schema with the following type:</p> + + <pre class="xml"> +<xs:complexType name="staff"> + <xs:sequence> + <xs:element name="permanent" type="people"/> + <xs:element name="contract" type="people"/> + </xs:sequence> +</xs:complexType> + </pre> + + <p>If we compile it with XSD/e and specify the + <code>--generate-clone</code> and <code>--generate-detach</code> + options, we will get the following C++ class:</p> + + <pre class="c++"> +// staff (variable-length) +// +class staff +{ +public: + staff (); + + staff* + _clone () const; + +private: + staff (const staff&); + staff& operator= (const staff&); + +public: + // permanent + // + const people& + permanent () const; + + people& + permanent (); + + void + permanent (people*); + + people* + permanent_detach (); + + // contract + // + const people& + contract () const; + + people& + contract (); + + void + contract (people*); + + people* + contract_detach (); + +private: + ... +}; + </pre> + + <p>Notice that unlike, say, the <code>first_name()</code> modifier + function in the <code>person</code> class, the <code>permanent()</code> + and <code>contract()</code> modifiers expect a pointer to the + <code>people</code> object. The following listing shows how + we can create and populate an instance of the <code>staff</code> + class. The use of smart pointers to hold the results of dynamic + allocations is omitted for brevity:</p> + + <pre class="c++"> +people* per = new people; +people* con = new people; + +// Populate per and con. + +staff s; +s->permanent (per) // Assumes ownership of per. +s->contract (con) // Assumes ownership of con. + </pre> + + <h2><a name="4.3">4.3 Enumerations</a></h2> + + <p>By default, string-based types that use XML Schema restriction by + enumeration are mapped to C++ classes with semantics similar to + C++ enum (you can suppress this mapping and instead get the plain + inheritance by specifying the <code>--suppress-enum</code> compiler + option). The following code fragment again shows the C++ class that + was generated for the <code>gender</code> XML Schema type presented + at the beginning of this chapter:</p> + + <pre class="c++"> +// gender (fixed-length) +// +class gender +{ +public: + enum value_type + { + male, + female + }; + + gender (); + gender (value_type); + gender (const gender&); + gender& operator= (const gender&); + + void + value (value_type); + + operator value_type () const; + + const char* + string () const; + +private: + value_type v_; +}; +</pre> + + <p>The <code>gender</code> class defines the underlying C++ enum type + (<code>value_type</code>) with enumerators corresponding to the + <code>enumeration</code> elements in XML Schema. The class also + defines the default constructor, copy constructor, constructor + with the underlying enum type as its argument, and the assignment + operator. The <code>gender</code> class also supports the implicit + conversion to the underlying enum type and the explicit conversion + to string via the <code>string()</code> function. Finally, it + provides the <code>value()</code> modifier function which allows you + to set the underlying enum value explicitly. Note also that such an + enumeration class is always fixed-length since it only contains the + C++ enum value. The following example shows how we can use the + <code>gender</code> class:</p> + + <pre class="c++"> +gender g = gender::male; +g = gender::female; +g.value (gender::female); // Same as above. + +cerr << g.string () << endl; + +if (g != gender::male) + ... + +switch (g) +{ +case gender::male: + ... +case gender::female: + ... +} + </pre> + + + <h2><a name="4.4">4.4 Attributes and Elements</a></h2> + + <p>As we have seen before, XSD/e generates a different + set of member functions for elements with different cardinalities. + The C++/Hybrid mapping divides all the possible element and attribute + cardinalities into three cardinality classes: + <em>one</em>, <em>optional</em>, and <em>sequence</em>.</p> + + <p>The <em>one</em> cardinality class covers all elements that should + occur exactly once as well as the required attributes. In our + example, the <code>first-name</code>, <code>last-name</code>, + <code>gender</code>, and <code>age</code> elements as well as + the <code>id</code> attribute belong to this cardinality class. + The following code fragment again shows the accessor and modifier + functions that are generated for the <code>first-name</code> element + in the <code>person</code> class:</p> + + <pre class="c++"> +class person +{ + // first-name + // + const std::string& + first_name () const; + + std::string& + first_name (); + + void + first_name (const std::string&); +}; + </pre> + + <p>The first two accessor functions return read-only (constant) and + read-write references to the element's value, respectively. The + modifier function sets the new value for the element. Note that + the signature of the modifier function varies depending on + whether the element or attribute is of a fixed or variable-length + type, as was discussed in the previous section.</p> + + <p>The <em>optional</em> cardinality class covers all elements that + can occur zero or one time as well as optional attributes. In our + example, the <code>middle-name</code> element belongs to this + cardinality class. The following code fragment again shows the + accessor and modifier functions that are generated for this element + in the <code>person</code> class:</p> + + <pre class="c++"> +class person +{ + // middle-name + // + bool + middle_name_present () const; + + void + middle_name_present (bool); + + const std::string& + middle_name () const; + + std::string& + middle_name (); + + void + middle_name (const std::string&); +}; + </pre> + + <p>Compared to the <em>one</em> cardinality class, <em>optional</em> adds + functions for querying and modifying the member's presence status. + The following example shows how we can use these functions:</p> + + <pre class="c++"> +person& p = ... + +if (p.middle_name_present ()) +{ + cout << p.middle_name () << endl; + p.middle_name_present (false); // Reset to the "not present" state. +} + </pre> + + <p>If an optional member is of a variable-length type, then the second + <code>_present()</code> function is omitted. This is done to help + detect programming errors that result from a type becoming + variable-length due to schema changes. In this situation, before + the type becomes variable-length, calling the presence function + with <code>true</code> as its argument and then accessing the + member is valid. Once the type becomes variable-length, the + same sequence of calls would lead to a runtime error. By + omitting the second <code>_present()</code> function for + variable-length types, this kind of errors can be detected + at compile time. To reset an optional member of a variable-length + type you can call the member modifier function with <code>NULL</code> + as its argument. For example, if the <code>middle_name</code> + member was of a variable-length type, then the above code fragment + would look like this:</p> + + <pre class="c++"> +person& p = ... + +if (p.middle_name_present ()) +{ + cout << *p.middle_name () << endl; + p.middle_name (0); // Reset to the "not present" state. +} + </pre> + + + <p>There are two cases in the <em>optional</em> cardinality class that + are handled differently. These are optional attributes with default + and fixed values. When an optional attribute declaration in XML Schema + specifies a default or fixed value and such an attribute is not present + in the XML document, the attribute is assumed to have the default or + fixed value, respectively. Furthermore, if an attribute with the + fixed value is set in the XML document, then the attribute value + should be the same as its fixed value.</p> + + <p>For an optional attribute with a default value, the functions for + querying and modifying the attribute's presence status are replaced + with functions that allow you to determine whether the attribute has + the default value. The accessor functions can be called at any time + since an optional attribute with a default value always has some + value. Also an extra static function is provided to allow you to + obtain the default value. Consider the following modification to + the <code>person</code> type which adds the <code>verified</code> + attribute with the default value:</p> + + <pre class="xml"> +<xs:complexType name="person"> + <xs:sequence> + <xs:element name="first-name" type="xs:string"/> + ... + </xs:sequence> + <xs:attribute name="id" type="xs:unsignedInt" use="required"/> + <xs:attribute name="verified" type="xs:boolean" default="false"/> +</xs:complexType> + </pre> + + <p>The code fragment below shows the accessor and modifier functions + that are generated for this new attribute in the <code>person</code> + class:</p> + + <pre class="c++"> +class person +{ + // verified + // + bool + verified_default () const; + + void + verified_default (bool); + + bool + verified () const; + + bool& + verified (); + + void + verified (bool); + + static bool + verified_default_value (); +}; + </pre> + + <p>When we create an object of the <code>person</code> class, the + <code>verified</code> member is automatically initialized to the + default value. The following example shows how we can manipulate + the <code>verified</code> attribute value:</p> + + <pre class="c++"> +person p; // verified is set to the default value (false). + +if (p.verified_default ()) + p.verified (true); +else + p.verified_default (true); // Revert to the default value. + +bool v = p.verified (); // Ok, can always be called. +bool vd = person::verified_default_value (); + </pre> + + <p>Note that modifying an attribute of a variable-length type via + the reference when the attribute is set to the default value is + illegal since this will modify the default value shared by all + instances. For example:</p> + + <pre class="c++"> +type& x = ... + +if (x.foo_default ()) +{ + foo& f = x.foo (); // foo is variable-length, for example NMTOKENS + f.push_back ("aaa"); // Illegal. +} + +if (x.foo_default ()) +{ + foo* f = new foo; + f->push_back ("aaa"); + x.foo (f); // Ok. +} + </pre> + + <p>Because an attribute with a fixed value can only be set to that + value, only the read-only (constant) accessor and the static + function for obtaining the fixed value are provided for such + attributes. Similar to the default values, members with fixed + values of a newly created object are automatically initialized + to their respective fixed values. Consider the following + modification to the <code>verified</code> attribute from the + schema above:</p> + + <pre class="xml"> +<xs:complexType name="person"> + ... + <xs:attribute name="verified" type="xs:boolean" fixed="true"/> +</xs:complexType> + </pre> + + <p>The code fragment below shows the accessor functions that are + generated for this attribute in the <code>person</code> + class:</p> + + <pre class="c++"> +class person +{ + // verified + // + bool + verified () const; + + static bool + verified_fixed_value (); +}; + </pre> + + <p>During serialization, attributes that are set to default and fixed + values are explicitly specified in the resulting XML document. + You can use the <code>--omit-default-attributes</code> XSD/e + compiler option to omit such attributes from the serialized XML.</p> + + <p>The <em>sequence</em> cardinality class covers all elements + that can occur more than once. In our example, the + <code>person</code> element in the <code>people</code> type + belongs to this cardinality class. The following code fragment shows + again the type definitions as well as the accessor and modifier + functions that are generated for this element in the <code>people</code> + class:</p> + + <pre class="c++"> +class people +{ + // person + // + typedef xml_schema::fix_sequence<person> person_sequence; + typedef person_sequence::iterator person_iterator; + typedef person_sequence::const_iterator person_const_iterator; + + const person_sequence& + person () const; + + person_sequence& + person (); +}; + </pre> + + <p>The <code>person_sequence</code> type is a sequence container for the + element's values. It has an interface similar to <code>std::vector</code> + and we will discuss it in more detail shortly. The <code>person_iterator</code> + and <code>person_const_iterator</code> types are read-write and read-only + (constant) iterators for the <code>person_sequence</code> + container.</p> + + <p>Unlike other two cardinality classes, the <em>sequence</em> class + only provides accessor functions that return read-only (constant) + and read-write references to the sequence container. The + modification of the element values is performed my manipulating + the returned sequence container and elements that it contains.</p> + + <p>In the remainder of this section we will examine the interfaces + of the sequence containers which differ slightly depending on + whether the element type is fixed or variable-length and whether + C++ exceptions are enabled. Also, when STL is disabled, string + sequences have a special interface which is also discussed + below.</p> + + <p>When exceptions are enabled, the fixed-length type sequences + are implemented in terms of the following class template:</p> + + <pre class="c++"> +namespace xml_schema +{ + template <typename T> + class fix_sequence + { + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T* iterator; + typedef const T* const_iterator; + + public: + fix_sequence (); + + void + swap (fix_sequence&); + + private: + fix_sequence (const fix_sequence&); + + fix_sequence& + operator= (fix_sequence&); + + public: + iterator + begin (); + + const_iterator + begin () const; + + iterator + end (); + + const_iterator + end () const; + + T& + front (); + + const T& + front () const; + + T& + back (); + + const T& + back () const; + + T& + operator[] (size_t); + + const T& + operator[] (size_t) const; + + public: + bool + empty () const; + + size_t + size () const; + + size_t + capacity () const; + + size_t + max_size () const; + + public: + void + clear (); + + void + pop_back (); + + iterator + erase (iterator); + + void + push_back (const T&); + + iterator + insert (iterator, const T&); + + void + reserve (size_t); + + void + assign (const T* src, size_t n); + }; +} + </pre> + + <p>When C++ exceptions are disabled, the signatures of the + <code>push_back()</code>, <code>insert()</code>, + <code>reserve()</code>, and <code>assign()</code> functions + change as follows:</p> + + <pre class="c++"> +namespace xml_schema +{ + template <typename T> + class fix_sequence + { + public: + enum error + { + error_none, + error_no_memory + }; + + ... + + public: + error + push_back (const T&); + + error + insert (iterator, const T&); + + error + insert (iterator, const T&, iterator& result); + + error + reserve (size_t); + + error + assign (const T* src, size_t n); + }; +} + </pre> + + <p>That is, the functions that may require memory allocation + now return an error code that you will need to check in + order to detect the out of memory condition.</p> + + <p>When exceptions are enabled, the variable-length type sequences + are implemented in terms of the following class template:</p> + + <pre class="c++"> +namespace xml_schema +{ + template <typename T> + class var_sequence + { + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef <implementation details> iterator; + typedef <implementation details> const_iterator; + + public: + var_sequence (); + + void + swap (var_sequence&); + + private: + var_sequence (const var_sequence&); + + var_sequence& + operator= (var_sequence&); + + public: + iterator + begin (); + + const_iterator + begin () const; + + iterator + end (); + + const_iterator + end () const; + + T& + front (); + + const T& + front () const; + + T& + back (); + + const T& + back () const; + + T& + operator[] (size_t); + + const T& + operator[] (size_t) const; + + public: + bool + empty () const; + + size_t + size () const; + + size_t + capacity () const; + + size_t + max_size () const; + + public: + void + clear (); + + void + push_back (T*); + + iterator + insert (iterator, T*); + + void + pop_back (); + + iterator + erase (iterator); + + void + reserve (size_t); + + T* + detach (iterator); + + void + attach (iterator, T*); + }; +} + </pre> + + <p>Most of this interface is identical to the fixed-length type + version except for the <code>push_back()</code>, and + <code>insert()</code> functions. Similar to the modifier + functions for elements and attributes of variable-length + types, these two functions expect a pointer to the + dynamically-allocated instance of the type and assume + ownership of the passed object. To simplify error handling, + these two functions delete the passed object if the reallocation + of the underlying sequence buffer fails. The <code>var_sequence</code> + class template also provides the <code>detach()</code> and <code>attach()</code> + functions. The <code>detach()</code> function allows you to detach + the contained object at the specified position. A detached object + should eventually be deallocated with operator <code>delete</code>. + Similarly, the <code>attach()</code> function allows you to attach + a new object at the specified position.</p> + + <p>When C++ exceptions are disabled, the <code>push_back()</code>, + <code>insert()</code>, and <code>reserve()</code> functions + return an error code to signal the out of memory condition:</p> + + <pre class="c++"> +namespace xml_schema +{ + template <typename T> + class var_sequence + { + public: + enum error + { + error_none, + error_no_memory + }; + + ... + + public: + error + push_back (T*); + + error + insert (iterator, T*); + + error + insert (iterator, T*, iterator& result); + + error + reserve (size_t); + }; +} + </pre> + + + <p>When STL is enabled, the <code>string_sequence</code> class has + the same interface as <code>fix_sequence<std::string></code>. When + STL is disabled and strings are mapped to <code>char*</code>, + <code>string_sequence</code> has a special interface. When C++ + exceptions are enabled, it has the following definition:</p> + + <pre class="c++"> +namespace xml_schema +{ + class string_sequence + { + public: + typedef char* value_type; + typedef char** pointer; + typedef const char** const_pointer; + typedef char* reference; + typedef const char* const_reference; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef char** iterator; + typedef const char* const* const_iterator; + + string_sequence (); + + void + swap (string_sequence&); + + private: + string_sequence (string_sequence&); + + string_sequence& + operator= (string_sequence&); + + public: + iterator + begin (); + + const_iterator + begin () const; + + iterator + end (); + + const_iterator + end () const; + + char* + front (); + + const char* + front () const; + + char* + back (); + + const char* + back () const; + + char* + operator[] (size_t); + + const char* + operator[] (size_t) const; + + public: + bool + empty () const; + + size_t + size () const; + + size_t + capacity () const; + + size_t + max_size () const; + + public: + void + clear (); + + void + pop_back (); + + iterator + erase (iterator); + + void + push_back (char*); + + void + push_back_copy (const char*); + + iterator + insert (iterator, char*); + + void + reserve (size_t); + + char* + detach (iterator); + + void + attach (iterator, char*); + }; +} + </pre> + + <p>The <code>push_back()</code> and <code>insert()</code> functions + assume ownership of the passed string which should be allocated + with operator <code>new[]</code> and will be deallocated + with operator <code>delete[]</code> by the <code>string_sequence</code> + object. Similar to <code>var_sequence</code>, these two functions + free the passed string if the reallocation of the underlying + sequence buffer fails. The <code>push_back_copy()</code> + function makes a copy of the passed string. + The <code>string_sequence</code> class also provides the + <code>detach()</code> and <code>attach()</code> functions. + The <code>detach()</code> function allows you to detach + the contained string at the specified position. A detached string + should eventually be deallocated with operator <code>delete[]</code>. + Similarly, the <code>attach()</code> function allows you to attach + a new string at the specified position.</p> + + <p>When C++ exceptions are disabled, the signatures of the + <code>push_back()</code>, <code>push_back_copy()</code>, + <code>insert()</code>, and <code>reserve()</code> functions + in the <code>string_sequence</code> class change as follows:</p> + + <pre class="c++"> +namespace xml_schema +{ + class string_sequence + { + public: + enum error + { + error_none, + error_no_memory + }; + + ... + + public: + error + push_back (char*); + + error + push_back_copy (const char*); + + error + insert (iterator, char*); + + error + insert (iterator, char*, iterator& result); + + error + reserve (size_t); + }; +} + </pre> + + <h2><a name="4.5">4.5 Compositors</a></h2> + + <p>The XML Schema language provides three compositor constructs that + are used to group elements: <code>all</code>, <code>sequence</code>, + and <code>choice</code>. If a compositor has an <em>optional</em> + or <em>sequence</em> cardinality class (see <a href="#4.4">Section + 4.4, "Attributes and Elements"</a>) or if a compositor is + inside <code>choice</code>, then the C++/Hybrid mapping generates + a nested class for such a compositor as well as a set of accessor + and modifier functions similar to the ones defined for elements + and attributes. Otherwise, the member functions, corresponding + to elements defined in a compositor, are generated directly in + the containing class.</p> + + <p>Compositor classes are either fixed or variable-length and + obey the same storage and passing rules as object model + classes corresponding to XML Schema types (see <a href="#4.2">Section + 4.2, "Memory Management"</a>). Consider the following schema + fragment as an example:</p> + + <pre class="xml"> +<complexType name="type"> + <sequence> + <sequence minOccurs="0"> + <element name="a" type="int"/> + <element name="b" type="string" maxOccurs="unbounded"/> + </sequence> + <sequence maxOccurs="unbounded"> + <element name="c" type="int"/> + <element name="d" type="string"/> + </sequence> + </sequence> +</complexType> + </pre> + + <p>The corresponding object model class is shown below:</p> + + <pre class="c++"> +// type (variable-length) +// +class type +{ +public: + type (); + +private: + type (const type&); + type& operator= (const type&); + +public: + // sequence (variable-length) + // + class sequence_type + { + public: + sequence_type (); + + private: + sequence_type (const sequence_type&); + sequence_type& operator= (const sequence_type&); + + public: + // a + // + int + a () const; + + int& + a (); + + void + a (int); + + // b + // + typedef xml_schema::string_sequence b_sequence; + typedef b_sequence::iterator b_iterator; + typedef b_sequence::const_iterator b_const_iterator; + + const b_sequence& + b () const; + + b_sequence& + b (); + + private: + ... + }; + + bool + sequence_present () const; + + const sequence_type& + sequence () const; + + sequence_type& + sequence (); + + void + sequence (sequence_type*); + + // sequence1 (fixed-length) + // + class sequence1_type + { + public: + sequence1_type (); + sequence1_type (const sequence1_type&); + sequence1_type& operator= (const sequence1_type&); + + // c + // + int + c () const; + + int& + c (); + + void + c (int); + + // d + // + const std::string& + d () const; + + std::string& + d (); + + void + d (const std::string&); + + private: + ... + }; + + typedef xml_schema::fix_sequence<sequence1_type> sequence1_sequence; + typedef sequence1_sequence::iterator sequence1_iterator; + typedef sequence1_sequence::const_iterator sequence1_const_iterator; + + const sequence1_sequence& + sequence1 () const; + + sequence1_sequence& + sequence1 (); + +private: + ... +}; + </pre> + + <p>The content of the outer <code>sequence</code> compositor is + generated in-line since this compositor belongs to the <em>one</em> + cardinality class. The first nested <code>sequence</code> compositor + is optional (<code>minOccurs="0"</code>), which results in a corresponding + nested class. Notice that the <code>sequence_type</code> is + variable-length and the accessor and modifier functions corresponding + to this <code>sequence</code> compositor are the same as for an + optional element or attribute. Similarly, the second nested + compositor is of the <em>sequence</em> cardinality class + (<code>maxOccurs="unbounded"</code>), which also results in a + nested class and a set of accessor functions.</p> + + <p>Generated code corresponding to an <code>all</code> and + <code>sequence</code> compositor, whether in-line or as a + nested class, simply define accessor and modifier functions + for the elements that this compositor contains. For the + <code>choice</code> compositor, on the other hand, + additional types and functions are generated to support + querying and selecting the choice arm that is in effect. + Consider the following simple example:</p> + + <pre class="xml"> +<complexType name="type"> + <choice> + <element name="a" type="int"/> + <element name="b" type="string"/> + <element name="c" type="boolean"/> + </choice> +</complexType> + </pre> + + + <p>The corresponding object model class is shown next:</p> + + <pre class="c++"> +// type (fixed-length) +// +class type +{ +public: + type (); + type (const type&); + type& operator= (const type&); + + // choice + // + enum choice_arm_tag + { + a_tag, + b_tag, + c_tag + }; + + choice_arm_tag + choice_arm () const; + + void + choice_arm (choice_arm_tag); + + // a + // + int + a () const; + + int& + a (); + + void + a (int); + + // b + // + const std::string& + b () const; + + std::string& + b (); + + void + b (const std::string&); + + // c + // + bool + c () const; + + bool& + c (); + + void + c (bool); + +private: + ... +}; + </pre> + + <p>The extra type is the <code>choice_arm_tag</code> enumeration + which defines a set of tags corresponding to each choice arm. + There are also the <code>choice_arm()</code> accessor and modifier + functions that can be used to query and set the current choice arm. + The following code fragment shows how we can use this class:</p> + + <pre class="c++"> +type& x = ... + +switch (x.choice_arm ()) +{ +case type::a_tag: + { + cout << "a: " << x.a () << endl; + break; + } +case type::b_tag: + { + cout << "b: " << x.b () << endl; + break; + } +case type::c_tag: + { + cout << "c: " << x.c () << endl; + break; + } +} + +// Modifiers automatically set the corresponding arm. +// +x.a (10); + +// For accessors we need to select the arm explicitly. +// +x.choice_arm (type::b_tag); +x.b () = "b"; + </pre> + + <p>The following slightly more complex example triggers the generation of + nested classes for the <code>choice</code> compositor as well as for + the <code>sequence</code> compositor inside <code>choice</code>. + Notice that the nested class for <code>sequence</code> is generated + because it is in <code>choice</code> even though its cardinality + class is <em>one</em>.</p> + + <pre class="xml"> +<complexType name="type"> + <choice maxOccurs="unbounded"> + <sequence> + <element name="a" type="int"/> + <element name="b" type="string"/> + </sequence> + <element name="c" type="boolean"/> + </choice> +</complexType> + </pre> + + <p>The corresponding object model class is shown next:</p> + + <pre class="c++"> +// type (variable-length) +// +class type +{ +public: + type (); + +private: + type (const type&); + type& operator= (const type&); + +public: + // choice (fixed-length) + // + class choice_type + { + public: + choice_type (); + choice_type (const choice_type&); + choice_type& operator= (const choice_type&); + + enum choice_arm_tag + { + sequence_tag, + c_tag + }; + + choice_arm_tag + choice_arm () const; + + void + choice_arm (choice_arm_tag); + + // sequence (fixed-length) + // + class sequence_type + { + public: + sequence_type (); + sequence_type (const sequence_type&); + sequence_type& operator= (const sequence_type&); + + // a + // + int + a () const; + + int& + a (); + + void + a (int); + + // b + // + const std::string& + b () const; + + std::string& + b (); + + void + b (const std::string&); + + private: + ... + }; + + const sequence_type& + sequence () const; + + sequence_type& + sequence (); + + void + sequence (const sequence_type&); + + // c + // + bool + c () const; + + bool& + c (); + + void + c (bool); + + private: + ... + }; + + typedef xml_schema::fix_sequence<choice_type> choice_sequence; + typedef choice_sequence::iterator choice_iterator; + typedef choice_sequence::const_iterator choice_const_iterator; + + const choice_sequence& + choice () const; + + choice_sequence& + choice (); + +private: + ... +}; + </pre> + + <h2><a name="4.6">4.6 Accessing the Object Model</a></h2> + + <p>In this section we will examine how to get to the information + stored in the object model for the person records vocabulary + introduced at the beginning of this chapter. The following + application accesses and prints the contents of the + <code>people.xml</code> file:</p> + + <pre class="c++"> +#include <memory> +#include <iostream> + +#include "people.hxx" +#include "people-pimpl.hxx" + +using namespace std; + +int +main () +{ + // Parse. + // + people_paggr people_p; + xml_schema::document_pimpl doc_p (people_p.root_parser (), + people_p.root_name ()); + people_p.pre (); + doc_p.parse ("people.xml"); + auto_ptr<people> ppl (people_p.post ()); + + // Iterate over individual person records. + // + people::person_sequence& ps = ppl->person (); + + for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) + { + person& p = *i; + + // Print names: first-name and last-name are required elements, + // middle-name is optional. + // + cout << "name: " << p.first_name () << " "; + + if (p.middle_name_present ()) + cout << p.middle_name () << " "; + + cout << p.last_name () << endl; + + // Print gender, age, and id which are all required. + // + cout << "gender: " << p.gender ().string () << endl + << "age: " << p.age () << endl + << "id: " << p.id () << endl + << endl; + } +} + </pre> + + <p>This code shows common patterns of accessing elements and attributes + with different cardinality classes. For the sequence element + (<code>person</code> in the <code>people</code> type) we first obtain a + reference to the container and then iterate over individual + records. The values of elements and attributes with the + <em>one</em> cardinality class (<code>first-name</code>, + <code>last-name</code>, <code>gender</code>, <code>age</code>, + and <code>id</code>) can be obtained directly by calling the + corresponding accessor functions. For the optional + <code>middle-name</code> element we first check if the value is present + and only then call the corresponding accessor to retrieve it.</p> + + <p>Note that when we want to reduce typing by creating a variable + representing a fragment of the object model that we are currently + working with (<code>ps</code> and <code>p</code> above), we obtain + a reference to that fragment instead of making a copy. This is + generally a good rule to follow when creating efficient + applications.</p> + + <p>If we run the above application on our sample + <code>people.xml</code>, the output looks as follows:</p> + + <pre class="terminal"> +name: John Doe +gender: male +age: 32 +id: 1 + +name: Jane Mary Doe +gender: female +age: 28 +id: 2 + </pre> + + + <h2><a name="4.7">4.7 Modifying the Object Model</a></h2> + + <p>In this section we will examine how to modify the information + stored in the object model for our person records vocabulary. + The following application changes the contents of the + <code>people.xml</code> file:</p> + + <pre class="c++"> +#include <memory> +#include <iostream> + +#include "people.hxx" +#include "people-pimpl.hxx" +#include "people-simpl.hxx" + +using namespace std; + +int +main () +{ + // Parse. + // + people_paggr people_p; + xml_schema::document_pimpl doc_p (people_p.root_parser (), + people_p.root_name ()); + people_p.pre (); + doc_p.parse ("people.xml"); + auto_ptr<people> ppl (people_p.post ()); + + // Iterate over individual person records and increment + // the age. + // + people::person_sequence& ps = ppl->person (); + + for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) + { + i->age ()++; // Alternative way: i->age (i->age () + 1) + } + + // Add middle-name to the first record and remove it from + // the second. + // + person& john = ps[0]; + person& jane = ps[1]; + + john.middle_name ("Mary"); + jane.middle_name_present (false); + + // Add another John record. + // + ps.push_back (john); + + // Serialize the modified object model to XML. + // + people_saggr people_s; + xml_schema::document_simpl doc_s (people_s.root_serializer (), + people_s.root_name ()); + people_s.pre (*ppl); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + people_s.post (); +} + </pre> + + <p>The first modification the above application performs is iterating + over person records and incrementing the age value. This code + fragment shows how to modify the value of a required attribute + or element. The next modification shows how to set a new value + for the optional <code>middle-name</code> element as well + as clear its value. Finally, the example adds a copy of the + John Doe record to the <code>person</code> element sequence.</p> + + <p>Note that in this case using references for the <code>ps</code>, + <code>john</code>, and <code>jane</code> variables is no longer + a performance improvement but a requirement for the application + to function correctly. If we hadn't used references, all our changes + would have been made on copies without affecting the object model.</p> + + <p>If we run the above application on our sample <code>people.xml</code>, + the output looks as follows:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<people> + + <person id="1"> + <first-name>John</first-name> + <middle-name>Mary</middle-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>33</age> + </person> + + <person id="2"> + <first-name>Jane</first-name> + <last-name>Doe</last-name> + <gender>female</gender> + <age>29</age> + </person> + + <person id="1"> + <first-name>John</first-name> + <middle-name>Mary</middle-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>33</age> + </person> + +</people> + </pre> + + <h2><a name="4.8">4.8 Creating the Object Model from Scratch</a></h2> + + <p>In this section we will examine how to create a new object model + for our person records vocabulary. The following application + recreates the content of the original <code>people.xml</code> + file:</p> + + <pre class="c++"> +#include <iostream> + +#include "people.hxx" +#include "people-simpl.hxx" + +using namespace std; + +int +main () +{ + people ppl; + people::person_sequence& ps = ppl.person (); + + // John + // + { + person p; + p.first_name ("John"); + p.last_name ("Doe"); + p.gender (gender::male); + p.age (32); + p.id (1); + + ps.push_back (p); + } + + // Jane + // + { + person p; + p.first_name ("Jane"); + p.middle_name ("Mary"); + p.last_name ("Doe"); + p.gender (gender::female); + p.age (28); + p.id (2); + + ps.push_back (p); + } + + // Serialize the object model to XML. + // + people_saggr people_s; + xml_schema::document_simpl doc_s (people_s.root_serializer (), + people_s.root_name ()); + people_s.pre (ppl); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + people_s.post (); +} + </pre> + + <p>The only new part in the above application is the calls + to the <code>people</code> and <code>person</code> + constructors. As a general rule, a newly created instance + does not assign any values to its elements and attributes. + That is, members with the <em>one</em> cardinality + class are left uninitialized, members with the <em>optional</em> + cardinality class are set to the "not present" state, + and members with the <em>sequence</em> cardinality class + have empty containers. After the instance has been + created, we can set its element and attribute values + using the modifier functions.</p> + + <p>The above application produces the following output:</p> + + <pre class="xml"> +<?xml version="1.0" ?> +<people> + + <person id="1"> + <first-name>John</first-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>32</age> + </person> + + <person id="2"> + <first-name>Jane</first-name> + <middle-name>Mary</middle-name> + <last-name>Doe</last-name> + <gender>female</gender> + <age>28</age> + </person> + +</people> + </pre> + + <h2><a name="4.9">4.9 Customizing the Object Model</a></h2> + + <p>Sometimes it is desirable to add extra, application-specific + data or functionality to some object model classes or + nested compositor classes. Cases where this may be required + include handling of typeless content matched by XML Schema + wildcards as well as a need for an application to pass extra + data or provide custom functions as part of the object model. + The C++/Hybrid mapping provides two mechanisms for accomplishing + this: custom data and custom types. Custom data is a light-weight + mechanism for storing application-specific data by allowing you + to add a sequence of opaque objects, stored as <code>void*</code>, + to select generated classes. Type customization is a more + powerful mechanism that allows you to provide custom implementations + for select object model classes. You have the option of either extending + the generated version of the class (for example, by adding extra data + members and/or functions) or providing your own implementation from + scratch. The latter approach essentially allows you to change the + mapping of XML Schema to C++ on a case by case basis.</p> + + <p>It is also possible to customize the parsing and serialization code, + for example, to populate the custom data sequence or custom data + members during parsing and later serialize them to XML. See + <a href="#6.1">Section 6.1, "Customizing Parsers and + Serializers"</a> for details. The remainder of this section discusses + the custom data and custom types mechanisms in more detail.</p> + + <p>To instruct the XSD/e compiler to include custom data + in a specific object model class, we need to use the + <code>--custom-data</code> option with the corresponding + XML Schema type name as its argument. To include custom + data into a nested compositor class, use its qualified + name starting with the XML Schema type, for example + <code>type::sequence1</code>. If we would like to + add the ability to store custom data in the generated + <code>person</code> class from our person records + vocabulary, we can compile <code>people.xsd</code> + like this:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --custom-data person people.xsd + </pre> + + <p>The resulting <code>person</code> class will have the + following extra set of type definitions and functions:</p> + + + <pre class="c++"> +// person (variable-length) +// +class person +{ +public: + + ... + + // Custom data. + // + typedef xml_schema::data_sequence custom_data_sequence; + typedef custom_data_sequence::iterator custom_data_iterator; + typedef custom_data_sequence::const_iterator custom_data_const_iterator; + + const custom_data_sequence& + custom_data () const; + + custom_data_sequence& + custom_data (); +}; + </pre> + + <p>Notice also that the <code>person</code> class is now variable-length + since it contains a sequence. When C++ exceptions are enabled, the + custom data sequence has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class data_sequence + { + public: + typedef void* value_type; + typedef void** pointer; + typedef const void** const_pointer; + typedef void* reference; + typedef const void* const_reference; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef void** iterator; + typedef const void* const* const_iterator; + + typedef void (*destroy_func) (void* data, size_t pos); + typedef void* (*clone_func) (void* data, size_t pos); + + public: + data_sequence (); + + void + destructor (destroy_func); + + void + clone (clone_func); + + void + swap (data_sequence&); + + private: + data_sequence (const data_sequence&); + + data_sequence& + operator= (data_sequence&); + + public: + iterator + begin (); + + const_iterator + begin () const; + + iterator + end (); + + const_iterator + end () const; + + void* + front (); + + const void* + front () const; + + void* + back (); + + const void* + back () const; + + void* + operator[] (size_t); + + const void* + operator[] (size_t) const; + + public: + bool + empty () const; + + size_t + size () const; + + size_t + capacity () const; + + size_t + max_size () const; + + public: + void + clear (); + + void + pop_back (); + + iterator + erase (iterator); + + void + push_back (void*); + + iterator + insert (iterator, void*); + + void + reserve (size_t); + }; +} + </pre> + + <p>The <code>destructor()</code> modifier allows you to specify + the clean up function used to free the sequence elements. + Similarly, the <code>clone()</code> modifier allows you to specify + the cloning function used to copy the sequence elements. + The second argument in these functions is the position + of the element in the sequence. This allows you to store objects + of different types in the same custom + data sequence.</p> + + <p>The <code>push_back()</code> and <code>insert()</code> functions + free the passed object if the reallocation of the underlying + sequence buffer fails. When exceptions are disabled, the + <code>push_back()</code>, + <code>insert()</code>, and <code>reserve()</code> functions + return an error code to signal the out of memory condition:</p> + + <pre class="c++"> +namespace xml_schema +{ + class data_sequence + { + public: + enum error + { + error_none, + error_no_memory + }; + + ... + + public: + error + push_back (void*); + + error + insert (iterator, void*); + + error + insert (iterator, void*, iterator& result); + + error + reserve (size_t); + }; +} + </pre> + + <p>The following code fragment shows how we can store and retrieve + custom data in the <code>person</code> class:</p> + + <pre class="c++"> +class data +{ + ... +}; + +void +destroy_data (void* p, size_t) +{ + delete static_cast<data*> (p); +} + +person& = ...; +person::custom_data_sequence& cd = p.custom_data (); + +cd.destructor (&destroy_data); + +// Store. +// +data* d = new data; +cd.push_back (d); + +// Retrieve. +// +for (person::custom_data_iterator i = cd.begin (); i != cd.end (); ++i) +{ + data* d = static_cast<data*> (*i); +} + </pre> + + <p>To instruct the XSD/e compiler to use a custom implementation + for a specific object model class, we need to use the + <code>--custom-type</code> option. The argument format for this + option is <code>name[=[flags][/[type][/[base][/include]]]]</code>. + The <code><i>name</i></code> component is the XML Schema type name being + customized. Optional <code><i>flags</i></code> allow you to specify whether + the custom class is fixed or variable-length since customization can + alter this property, normally from fixed-length to + variable-length. The <code>f</code> flag indicates the type is + fixed-length and the <code>v</code> flag indicates the type is + variable-length. If omitted, the default rules are used to determine + the type length (see <a href="#4.2">Section 4.2, "Memory Management"</a>). + + Optional <code><i>type</i></code> is a C++ type name, potentially qualified, + that should be used as a custom implementation. If specified, the + object model type is defined as a <code>typedef</code> alias for + this C++ type. Optional <code><i>base</i></code> is a C++ name that should + be given to the generated version. It is normally used as a base for + the custom implementation. Optional <code><i>include</i></code> is the header + file that defines the custom implementation. It is <code>#include</code>'ed + into the generated code immediately after (if <code><i>base</i></code> is + specified) or instead of the generated version. The following + examples show how we can use this option:</p> + + <pre class="terminal"> +--custom-type foo +--custom-type foo=///foo.hxx +--custom-type foo=v///foo.hxx +--custom-type foo=f/int +--custom-type foo=//foo_base/my/foo.hxx +--custom-type foo=v/wrapper<foo_base>/foo_base + </pre> + + <p>The first version instructs the XSD/e compiler not to generate + the object model class for the <code>foo</code> XML Schema + type. The generated code simply forward-declares <code>foo</code> + as a class and leaves it to you to provide the implementation. + + The second version is similar to the first, except now we specify + the header file which defines the custom implementation. + This file is automatically included into the generated header + file instead of the standard implementation. + + The third version is similar to the second, except now we specify + that the <code>foo</code> type is variable-length. In the previous + two cases the type length was determined automatically based on the + type definition in the schema. + + In the fourth version we specify that schema type <code>foo</code> + is fixed-length and should be mapped to <code>int</code>. + + The fifth version instructs the XSD/e compiler to generate + the object model class for type <code>foo</code> but call it + <code>foo_base</code>. It also tells the compiler to generate + the <code>#include</code> directive with the <code>my/foo.hxx</code> + file (which presumably defines <code>foo</code>) right after the + <code>foo_base</code> class. + + Finally, the last version specifies that schema type <code>foo</code> + is variable-length and should be mapped to <code>wrapper<foo_base></code>. + The compiler is also instructed to generate the standard object + model class for type <code>foo</code> but call it <code>foo_base</code>. + + If you omit the last component (<code><i>include</i></code>), as in the + final version, then you can provide the custom type definitions using + one of the prologue or epilogue XSD/e compiler options. See the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a> for details.</p> + + <p>Note also that if the type length you specified with the + <code>--custom-type</code> option differs from the default type + length that would have been determined by the XSD/e compiler, + then you need to specify this <code>--custom-type</code> option + when compiling every schema file that includes or imports the + schema that defines the type being customized.</p> + + <p>As an example, let us add a flag to the <code>person</code> class + from our person records vocabulary. This flag can be used by the + application to keep track of whether a particular person record + has been verified. To customize the <code>person</code> type we + can compile <code>people.xsd</code> like this:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --custom-type person=//person_base/person.hxx \ +people.xsd + </pre> + + <p>The relevant code fragment from the generated header file + looks like this:</p> + + <pre class="c++"> +// person_base (fixed-length) +// +class person_base +{ + ... +}; + +#include "person.hxx" + +// people (variable-length) +// +class people +{ + ... + + // person + // + typedef xml_schema::fix_sequence<person> person_sequence; + typedef person_sequence::iterator person_iterator; + typedef person_sequence::const_iterator person_const_iterator; + + const person_sequence& + person () const; + + person_sequence& + person (); + +private: + ... +}; + </pre> + + <p>We base our custom implementation of the <code>person</code> + class on generated <code>person_base</code> and save it to + <code>person.hxx</code>:</p> + + <pre class="c++"> +class person: public person_base +{ +public: + person () + : verified_ (false) + { + } + + bool + verified () const + { + return verified_; + } + + void + verified (bool v) + { + verified_ = v; + } + +private: + bool verified_; +}; + </pre> + + <p>The client code can use our custom implementation as if the + flag was part of the vocabulary:</p> + + <pre class="c++"> +people::person_sequence& ps = ...; + +for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) +{ + if (!i->verified ()) + { + // Verify the record. + + ... + + i->verified (true); + } +} + </pre> + + + <h2><a name="4.10">4.10 Polymorphic Object Models</a></h2> + + <p>When generating polymorphism-aware code (see <a href="#3.7">Section + 3.7, "Support for Polymorphism"</a>), some objects + in the resulting object model will be polymorphic. By polymorphic + we mean that the object's (static) type as specified in the + object model's interface may differ from the object's actual + (dynamic) type. Because of this, it may be necessary to discover + the object's actual type at runtime and cast it to this type to + gain access to the object's extended interface. Consider the + following schema as an example:</p> + + <pre class="xml"> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:complexType name="person"> + <xs:sequence> + <xs:element name="name" type="xs:string"/> + </xs:sequence> + </xs:complexType> + + <!-- substitution group root --> + <xs:element name="person" type="person"/> + + <xs:complexType name="superman"> + <xs:complexContent> + <xs:extension base="person"> + <xs:attribute name="can-fly" type="xs:boolean"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + + <xs:element name="superman" + type="superman" + substitutionGroup="person"/> + + <xs:complexType name="batman"> + <xs:complexContent> + <xs:extension base="superman"> + <xs:attribute name="wing-span" type="xs:unsignedInt"/> + </xs:extension> + </xs:complexContent> + </xs:complexType> + + <xs:element name="batman" + type="batman" + substitutionGroup="superman"/> + + <xs:complexType name="supermen"> + <xs:sequence> + <xs:element ref="person" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="supermen" type="supermen"/> + +</xs:schema> + </pre> + + <p>Conforming XML documents can use the <code>superman</code> + and <code>batman</code> types in place of the <code>person</code> + type either by specifying the type with the <code>xsi:type</code> + attributes or by using the elements from the substitution + group, for instance:</p> + + + <pre class="xml"> +<supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + <person> + <name>John Doe</name> + </person> + + <superman can-fly="false"> + <name>James "007" Bond</name> + </superman> + + <superman can-fly="true" wing-span="10" xsi:type="batman"> + <name>Bruce Wayne</name> + </superman> + +</supermen> + </pre> + + <p>When compiling the schema above with the + <code>--generate-polymorphic</code> option, the XSD/e compiler + automatically detects that the type hierarchy starting with + the <code>person</code> type is polymorphic. A polymorphic + type is always variable-length which means objects of polymorphic + types are allocated dynamically and are stored and passed around + as pointers or references. A polymorphic type also defines a + virtual <code>_clone()</code> function (see <a href="#4.2">Section 4.2, + "Memory Management"</a>) and a virtual destructor + which allow you to copy and delete an instance of a + polymorphic type via a pointer to its base. The following code + fragment shows how we can parse, access, modify, and serialize + the above XML document:</p> + + <pre class="c++"> +// Parse. +// +supermen_paggr supermen_p; + +// The last argument to the document's constructor indicates that we +// are parsing polymorphic XML documents. +// +xml_schema::document_pimpl doc_p ( + supermen_p.root_parser (), + supermen_p.root_name (), + true); + +supermen_p.pre (); +doc_p.parse ("supermen.xml"); +auto_ptr<supermen> sm (supermen_p.post ()); + +// Print what we've got. +// +for (supermen::person_iterator i = sm->person ().begin (); + i != sm->person ().end (); + ++i) +{ + person& p = *i; + + if (batman* b = dynamic_cast<batman*> (&p)) + { + cerr << b->name () << ", batman, wing span " << + b->wing_span () << endl; + } + else if (superman* s = dynamic_cast<superman*> (&p)) + { + cerr << s->name () << ", "; + + if (s->can_fly ()) + cerr << "flying "; + + cerr << "superman" << endl; + } + else + { + cerr << p.name () << ", ordinary person" << endl; + } +} + +// Add another superman entry. +// +auto_ptr<superman> s (new superman); +s->name ("Clark Kent"); +s->can_fly (true); +sm->person ().push_back (s.release ()); + +// Serialize. +// +supermen_saggr supermen_s; + +// The last argument to the document's constructor indicates that we +// are serializing polymorphic XML documents. +// +xml_schema::document_simpl doc_s ( + supermen_s.root_serializer (), + supermen_s.root_name (), + true); + +doc_s.add_no_namespace_schema ("supermen.xsd"); + +supermen_s.pre (*sm); +doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); +supermen_s.post (); + </pre> + + <p>In the example above we used the standard C++ RTTI mechanism + to detect the object's actual (dynamic) type. If RTTI is not + available on your platform, then you can request the generation + of custom runtime type information for polymorphic types + with the <code>--generate-typeinfo</code> XSD/e compiler + option. When this option is specified, each polymorphic + type provides the following two public functions:</p> + + <pre class="c++"> +virtual const std::string& +_dynamic_type () const; + +static const std::string& +_static_type (); + </pre> + + <p>Or, if STL is disabled (<a href="#3.1">Section 3.1, "Standard Template + Library"</a>), the following two functions:</p> + + <pre class="c++"> +virtual const char* +_dynamic_type () const; + +static const char* +_static_type (); + </pre> + + <p>The <code>_dynamic_type()</code> function returns the object's + dynamic type id. The <code>_static_type()</code> function + returns the type's static id that can be compared to the + dynamic id. The following code fragment shows how + we can change the previous example to use custom type information + instead of C++ RTTI:</p> + + <pre class="c++"> +for (supermen::person_iterator i = sm->person ().begin (); + i != sm->person ().end (); + ++i) +{ + person& p = *i; + const string& dt = p._dynamic_type (); + + if (dt == batman::_static_type ()) + { + batman& b = static_cast<batman&> (p) + cerr << b.name () << ", batman, wing span " << + b.wing_span () << endl; + } + else if (dt == superman::_static_type ()) + { + superman& s = static_cast<superman&> (p) + cerr << s.name () << ", "; + + if (s.can_fly ()) + cerr << "flying "; + + cerr << "superman" << endl; + } + else + { + cerr << p.name () << ", ordinary person" << endl; + } +} + </pre> + + <p>Most of the code presented in this section is taken from the + <code>polymorphism</code> example which can be found in the + <code>examples/cxx/hybrid/</code> directory of the XSD/e distribution. + Handling of <code>xsi:type</code> and substitution groups when used + on root elements requires a number of special actions as shown in + the <code>polyroot</code> example.</p> + + + <!-- Built-in XML Schema Type Parsers --> + + + <h1><a name="5">5 Mapping for Built-In XML Schema Types</a></h1> + + <p>In XML Schema, built-in types, such as <code>int</code>, + <code>string</code>, etc., are defined in the XML Schema namespace. + By default this namespace is mapped to C++ namespace + <code>xml_schema</code> (this mapping can be altered + with the <code>--namespace-map</code> option). The following table + summarizes the mapping of XML Schema built-in types to C++ types + in the C++/Hybrid mapping. Declarations for these types are + automatically included into each generated header file.</p> + + <!-- border="1" is necessary for html2ps --> + <table id="builtin" border="1"> + <tr> + <th>XML Schema type</th> + <th>Alias in the <code>xml_schema</code> namespace</th> + <th>C++ type</th> + </tr> + + <tr> + <th colspan="3">fixed-length integral types</th> + </tr> + <!-- 8-bit --> + <tr> + <td><code>byte</code></td> + <td><code>byte</code></td> + <td><code>signed char</code></td> + </tr> + <tr> + <td><code>unsignedByte</code></td> + <td><code>unsigned_byte</code></td> + <td><code>unsigned char</code></td> + </tr> + + <!-- 16-bit --> + <tr> + <td><code>short</code></td> + <td><code>short_</code></td> + <td><code>short</code></td> + </tr> + <tr> + <td><code>unsignedShort</code></td> + <td><code>unsigned_short</code></td> + <td><code>unsigned short</code></td> + </tr> + + <!-- 32-bit --> + <tr> + <td><code>int</code></td> + <td><code>int_</code></td> + <td><code>int</code></td> + </tr> + <tr> + <td><code>unsignedInt</code></td> + <td><code>unsigned_int</code></td> + <td><code>unsigned int</code></td> + </tr> + + <!-- 64-bit --> + <tr> + <td><code>long</code></td> + <td><code>long_</code></td> + <td><code>long</code> or<br/> <code>long long</code><br/> + <a href="#3.5">Section 3.5, "64-bit Integer Type"</a></td> + </tr> + <tr> + <td><code>unsignedLong</code></td> + <td><code>unsigned_long</code></td> + <td><code>unsigned long</code> or + <code>unsigned long long</code><br/> + <a href="#3.5">Section 3.5, "64-bit Integer Type"</a></td> + </tr> + + <tr> + <th colspan="3">arbitrary-length integral types</th> + </tr> + <tr> + <td><code>integer</code></td> + <td><code>integer</code></td> + <td><code>long</code></td> + </tr> + <tr> + <td><code>nonPositiveInteger</code></td> + <td><code>non_positive_integer</code></td> + <td><code>long</code></td> + </tr> + <tr> + <td><code>nonNegativeInteger</code></td> + <td><code>non_negative_integer</code></td> + <td><code>unsigned long</code></td> + </tr> + <tr> + <td><code>positiveInteger</code></td> + <td><code>positive_integer</code></td> + <td><code>unsigned long</code></td> + </tr> + <tr> + <td><code>negativeInteger</code></td> + <td><code>negative_integer</code></td> + <td><code>long</code></td> + </tr> + + <tr> + <th colspan="3">boolean types</th> + </tr> + <tr> + <td><code>boolean</code></td> + <td><code>boolean</code></td> + <td><code>bool</code></td> + </tr> + + <tr> + <th colspan="3">fixed-precision floating-point types</th> + </tr> + <tr> + <td><code>float</code></td> + <td><code>float_</code></td> + <td><code>float</code></td> + </tr> + <tr> + <td><code>double</code></td> + <td><code>double_</code></td> + <td><code>double</code></td> + </tr> + + <tr> + <th colspan="3">arbitrary-precision floating-point types</th> + </tr> + <tr> + <td><code>decimal</code></td> + <td><code>decimal</code></td> + <td><code>double</code></td> + </tr> + + <tr> + <th colspan="3">string types</th> + </tr> + <tr> + <td><code>string</code></td> + <td><code>string</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>normalizedString</code></td> + <td><code>normalized_string</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>token</code></td> + <td><code>token</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>Name</code></td> + <td><code>name</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>NMTOKEN</code></td> + <td><code>nmtoken</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>NMTOKENS</code></td> + <td><code>nmtokens</code></td> + <td><a href="#5.2">Section 5.2, "Mapping for <code>NMTOKENS</code> and <code>IDREFS</code>"</a></td> + </tr> + <tr> + <td><code>NCName</code></td> + <td><code>ncname</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>language</code></td> + <td><code>language</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + + <tr> + <th colspan="3">qualified name</th> + </tr> + <tr> + <td><code>QName</code></td> + <td><code>qname</code></td> + <td><a href="#5.1">Section 5.1, "Mapping for <code>QName</code>"</a></td> + </tr> + + <tr> + <th colspan="3">ID/IDREF types</th> + </tr> + <tr> + <td><code>ID</code></td> + <td><code>id</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>IDREF</code></td> + <td><code>idref</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>IDREFS</code></td> + <td><code>idrefs</code></td> + <td><a href="#5.2">Section 5.2, "Mapping for <code>NMTOKENS</code> and <code>IDREFS</code>"</a></td> + </tr> + + <tr> + <th colspan="3">URI types</th> + </tr> + <tr> + <td><code>anyURI</code></td> + <td><code>uri</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + + <tr> + <th colspan="3">binary types</th> + </tr> + <tr> + <td><code>base64Binary</code></td> + <td><code>base64_binary</code></td> + <td><a href="#5.3">Section 5.3, "Mapping for <code>base64Binary</code> and <code>hexBinary</code>"</a></td> + </tr> + <tr> + <td><code>hexBinary</code></td> + <td><code>hex_binary</code></td> + <td><a href="#5.3">Section 5.3, "Mapping for <code>base64Binary</code> and <code>hexBinary</code>"</a></td> + </tr> + + <tr> + <th colspan="3">date/time types</th> + </tr> + <tr> + <td><code>date</code></td> + <td><code>date</code></td> + <td><a href="#5.5">Section 5.5, "Mapping for <code>date</code>"</a></td> + </tr> + <tr> + <td><code>dateTime</code></td> + <td><code>date_time</code></td> + <td><a href="#5.6">Section 5.6, "Mapping for <code>dateTime</code>"</a></td> + </tr> + <tr> + <td><code>duration</code></td> + <td><code>duration</code></td> + <td><a href="#5.7">Section 5.7, "Mapping for <code>duration</code>"</a></td> + </tr> + <tr> + <td><code>gDay</code></td> + <td><code>gday</code></td> + <td><a href="#5.8">Section 5.8, "Mapping for <code>gDay</code>"</a></td> + </tr> + <tr> + <td><code>gMonth</code></td> + <td><code>gmonth</code></td> + <td><a href="#5.9">Section 5.9, "Mapping for <code>gMonth</code>"</a></td> + </tr> + <tr> + <td><code>gMonthDay</code></td> + <td><code>gmonth_day</code></td> + <td><a href="#5.10">Section 5.10, "Mapping for <code>gMonthDay</code>"</a></td> + </tr> + <tr> + <td><code>gYear</code></td> + <td><code>gyear</code></td> + <td><a href="#5.11">Section 5.11, "Mapping for <code>gYear</code>"</a></td> + </tr> + <tr> + <td><code>gYearMonth</code></td> + <td><code>gyear_month</code></td> + <td><a href="#5.12">Section 5.12, "Mapping for <code>gYearMonth</code>"</a></td> + </tr> + <tr> + <td><code>time</code></td> + <td><code>time</code></td> + <td><a href="#5.13">Section 5.13, "Mapping for <code>time</code>"</a></td> + </tr> + + <tr> + <th colspan="3">anyType and anySimpleType</th> + </tr> + <tr> + <td><code>anyType</code></td> + <td><code>any_type</code></td> + <td><a href="#5.14">Section 5.14, "Mapping for <code>anyType</code>"</a></td> + </tr> + <tr> + <td><code>anySimpleType</code></td> + <td><code>any_simple_type</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#3.1">Section 3.1, "Standard Template Library"</a></td> + </tr> + </table> + + <p>As you can see from the table above a number of built-in + XML Schema types are mapped to fundamental C++ types such + as <code>int</code> or <code>bool</code>. All string-based + XML Schema types are mapped to either <code>std::string</code> + or <code>char*</code>, depending on whether the use of STL is + enabled or not. A number of built-in types, such as + <code>QName</code>, the binary types, and the date/time types, + do not have suitable fundamental or standard C++ types to map to. + These types are implemented from scratch in the XSD/e runtime + and are discussed in more detail in the subsequent sections.</p> + + <p>In cases where the schema calls for an inheritance from a built-in + type which is mapped to a fundamental C++ type, a special base + type corresponding to the fundamental type and defined in the + <code>xml_schema</code> namespace is used (C++ does not allow + inheritance from fundamental types). For example:</p> + + <pre class="xml"> +<complexType name="measure"> + <simpleContent> + <extension base="int"> + <attribute name="unit" type="string" use="required"/> + </extension> + </simpleContent> +</complexType> + </pre> + + <p>The corresponding object model class is shown below:</p> + + <pre class="c++"> +// measure (fixed-length) +// +class measure: public xml_schema::int_base +{ +public: + measure (); + measure (const measure&); + measure& operator= (const measure&); + + // unit + // + const std::string& + unit () const; + + std::string& + unit (); + + void + unit (const std::string&); + +private: + ... +}; + </pre> + + <p>The <code>xml_schema::int_base</code> class has the following + interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class int_base + { + public: + int_base (); + + int_base& + operator= (int); + + public: + int + base_value () const; + + int& + base_value (); + + void + base_value (int); + + operator const int& () const; + operator int& (); + }; +} + </pre> + + <p>All other base types for fundamental C++ types have similar + interfaces. The only exception is the base type for string + types when STL is disabled:</p> + + <pre class="c++"> +namespace xml_schema +{ + class string_base + { + public: + string_base (); + + string_base& + operator= (char* x) + + public: + const char* + base_value () const; + + char* + base_value (); + + void + base_value (char* x); + + char* + base_value_detach (); + + operator const char* () const; + operator char* (); + }; +} + </pre> + + <p>Note that the <code>string_base</code> object assumes ownership + of the strings passed to the assignment operator and the + <code>base_value()</code> modifier. If you detach the + string value then it should eventually be deallocated with + operator <code>delete[]</code>.</p> + + <h2><a name="5.1">5.1 Mapping for <code>QName</code></a></h2> + + <p>The <code>QName</code> built-in XML Schema type is mapped to the + <code>qname</code> class which represents an XML qualified name. + With STL enabled (<a href="#3.1">Section 3.1, "Standard Template + Library"</a>), it has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class qname + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + qname (); + + explicit + qname (const std::string& name); + qname (const std::string& prefix, const std::string& name); + + void + swap (qname&); + + const std::string& + prefix () const; + + std::string& + prefix (); + + void + prefix (const std::string&); + + const std::string& + name () const; + + std::string& + name (); + + void + name (const std::string&); + }; + + bool + operator== (const qname&, const qname&); + + bool + operator!= (const qname&, const qname&); +} + </pre> + + <p>When STL is disabled and C++ exceptions are enabled + (<a href="#3.3">Section 3.3, "C++ Exceptions"</a>), the + <code>qname</code> type has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class qname + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + qname (); + + explicit + qname (char* name); + qname (char* prefix, char* name); + + void + swap (qname&); + + private: + qname (const qname&); + + qname& + operator= (const qname&); + + public: + char* + prefix (); + + const char* + prefix () const; + + void + prefix (char*); + + void + prefix_copy (const char*); + + char* + prefix_detach (); + + public: + char* + name (); + + const char* + name () const; + + void + name (char*); + + void + name_copy (const char*); + + char* + name_detach (); + }; + + bool + operator== (const qname&, const qname&); + + bool + operator!= (const qname&, const qname&); +} +</pre> + + <p>The modifier functions and constructors that have the <code>char*</code> + argument assume ownership of the passed strings which should be allocated + with operator <code>new char[]</code> and will be deallocated with + operator <code>delete[]</code> by the <code>qname</code> object. + If you detach the underlying prefix or name strings, then they + should eventually be deallocated with operator <code>delete[]</code>. + </p> + + <p>Finally, if both STL and C++ exceptions are disabled, the + <code>qname</code> type has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class qname + { + public: + enum error + { + error_none, + error_no_memory + }; + + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + qname (); + + explicit + qname (char* name); + qname (char* prefix, char* name); + + void + swap (qname&); + + private: + qname (const qname&); + + qname& + operator= (const qname&); + + public: + char* + prefix (); + + const char* + prefix () const; + + void + prefix (char*); + + error + prefix_copy (const char*); + + char* + prefix_detach (); + + public: + char* + name (); + + const char* + name () const; + + void + name (char*); + + error + name_copy (const char*); + + char* + name_detach (); + }; + + bool + operator== (const qname&, const qname&); + + bool + operator!= (const qname&, const qname&); +} + </pre> + + <h2><a name="5.2">5.2 Mapping for <code>NMTOKENS</code> and <code>IDREFS</code></a></h2> + + <p>The <code>NMTOKENS</code> and <code>IDREFS</code> built-in + XML Schema types are mapped to the string sequence type which + is discussed in <a href="#4.4">Section 4.4, "Attributes and + Elements"</a>.</p> + + <h2><a name="5.3">5.3 Mapping for <code>base64Binary</code> and <code>hexBinary</code></a></h2> + + <p>The <code>base64Binary</code> and <code>hexBinary</code> built-in + XML Schema types are mapped to the <code>buffer</code> class. + With C++ exceptions enabled (<a href="#3.3">Section 3.3, "C++ + Exceptions"</a>), it has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class buffer + { + public: + class bounds {}; // Out of bounds exception. + + public: + buffer (); + + explicit + buffer (size_t size); + buffer (size_t size, size_t capacity); + buffer (const void* data, size_t size); + buffer (const void* data, size_t size, size_t capacity); + + enum ownership_value { assume_ownership }; + + // This constructor assumes ownership of the memory passed. + // + buffer (void* data, size_t size, size_t capacity, ownership_value); + + private: + buffer (const buffer&); + + buffer& + operator= (const buffer&); + + public: + void + assign (void* data, size_t size); + + void + attach (void* data, size_t size, size_t capacity); + + void* + detach (); + + + void + swap (buffer&); + + public: + size_t + capacity () const; + + bool + capacity (size_t); + + public: + size_t + size () const; + + bool + size (size_t); + + public: + const char* + data () const; + + char* + data (); + + const char* + begin () const; + + char* + begin (); + + const char* + end () const; + + char* + end (); + }; + + bool + operator== (const buffer&, const buffer&); + + bool + operator!= (const buffer&, const buffer&); +} + </pre> + + <p>The last constructor and the <code>attach()</code> member function + make the <code>buffer</code> instance assume the ownership of the + memory block pointed to by the <code>data</code> argument and + eventually release it by calling <code>operator delete()</code>. + The <code>detach()</code> member function detaches and returns the + underlying memory block which should eventually be released by + calling <code>operator delete()</code>. + </p> + + <p>The <code>capacity()</code> and <code>size()</code> modifier functions + return <code>true</code> if the underlying buffer has moved. The + <code>bounds</code> exception is thrown if the constructor or + <code>attach()</code> member function arguments violate the + <code>(size <= capacity)</code> constraint.</p> + + <p>If C++ exceptions are disabled, the <code>buffer</code> class has + the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class buffer + { + public: + enum error + { + error_none, + error_bounds, + error_no_memory + }; + + buffer (); + + private: + buffer (const buffer&); + + buffer& + operator= (const buffer&); + + public: + error + assign (void* data, size_t size); + + error + attach (void* data, size_t size, size_t capacity); + + void* + detach (); + + void + swap (buffer&); + + public: + size_t + capacity () const; + + error + capacity (size_t); + + error + capacity (size_t, bool& moved); + + public: + size_t + size () const; + + error + size (size_t); + + error + size (size_t, bool& moved); + + public: + const char* + data () const; + + char* + data (); + + const char* + begin () const; + + char* + begin (); + + const char* + end () const; + + char* + end (); + }; + + bool + operator== (const buffer&, const buffer&); + + bool + operator!= (const buffer&, const buffer&); +} + </pre> + + <h2><a name="5.4">5.4 Time Zone Representation</a></h2> + + <p>The <code>date</code>, <code>dateTime</code>, <code>gDay</code>, + <code>gMonth</code>, <code>gMonthDay</code>, <code>gYear</code>, + <code>gYearMonth</code>, and <code>time</code> XML Schema built-in + types all include an optional time zone component. The following + <code>time_zone</code> base class is used to represent this + information:</p> + + <pre class="c++"> +namespace xml_schema +{ + class time_zone + { + public: + time_zone (); + time_zone (short hours, short minutes); + + bool + zone_present () const; + + void + zone_reset (); + + short + zone_hours () const; + + void + zone_hours (short); + + short + zone_minutes () const; + + void + zone_minutes (short); + }; + + bool + operator== (const time_zone&, const time_zone&); + + bool + operator!= (const time_zone&, const time_zone&); +} + </pre> + + <p>The <code>zone_present()</code> accessor function returns <code>true</code> + if the time zone is specified. The <code>zone_reset()</code> modifier + function resets the time zone object to the "not specified" + state. If the time zone offset is negative then both hours and + minutes components should be negative.</p> + + <h2><a name="5.5">5.5 Mapping for <code>date</code></a></h2> + + <p>The <code>date</code> built-in XML Schema type is mapped to the + <code>date</code> class which represents a year, a day, and a month + with an optional time zone. Its interface is presented below. For + more information on the base <code>xml_schema::time_zone</code> + class refer to <a href="#5.4">Section 5.4, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class date: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + date (); + + date (int year, unsigned short month, unsigned short day); + + date (int year, unsigned short month, unsigned short day, + short zone_hours, short zone_minutes); + + int + year () const; + + void + year (int); + + unsigned short + month () const; + + void + month (unsigned short); + + unsigned short + day () const; + + void + day (unsigned short); + }; + + bool + operator== (const date&, const date&); + + bool + operator!= (const date&, const date&); +} + </pre> + + <h2><a name="5.6">5.6 Mapping for <code>dateTime</code></a></h2> + + <p>The <code>dateTime</code> built-in XML Schema type is mapped to the + <code>date_time</code> class which represents a year, a month, a day, + hours, minutes, and seconds with an optional time zone. Its interface + is presented below. For more information on the base + <code>xml_schema::time_zone</code> class refer to <a href="#5.4">Section + 5.4, "Time Zone Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class date_time: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + date_time (); + + date_time (int year, unsigned short month, unsigned short day, + unsigned short hours, unsigned short minutes, + double seconds); + + date_time (int year, unsigned short month, unsigned short day, + unsigned short hours, unsigned short minutes, + double seconds, short zone_hours, short zone_minutes); + + int + year () const; + + void + year (int); + + unsigned short + month () const; + + void + month (unsigned short); + + unsigned short + day () const; + + void + day (unsigned short); + + unsigned short + hours () const; + + void + hours (unsigned short); + + unsigned short + minutes () const; + + void + minutes (unsigned short); + + double + seconds () const; + + void + seconds (double); + }; + + bool + operator== (const date_time&, const date_time&); + + bool + operator!= (const date_time&, const date_time&); +} + </pre> + + <h2><a name="5.7">5.7 Mapping for <code>duration</code></a></h2> + + <p>The <code>duration</code> built-in XML Schema type is mapped to the + <code>duration</code> class which represents a potentially + negative duration in the form of years, months, days, hours, minutes, + and seconds. Its interface is presented below.</p> + + <pre class="c++"> +namespace xml_schema +{ + class duration + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + duration (); + + duration (bool negative, + unsigned int years, unsigned int months, unsigned int days, + unsigned int hours, unsigned int minutes, double seconds); + + bool + negative () const; + + void + negative (bool); + + unsigned int + years () const; + + void + years (unsigned int); + + unsigned int + months () const; + + void + months (unsigned int); + + unsigned int + days () const; + + void + days (unsigned int); + + unsigned int + hours () const; + + void + hours (unsigned int); + + unsigned int + minutes () const; + + void + minutes (unsigned int); + + double + seconds () const; + + void + seconds (double); + }; + + bool + operator== (const duration&, const duration&); + + bool + operator!= (const duration&, const duration&); +} + </pre> + + + <h2><a name="5.8">5.8 Mapping for <code>gDay</code></a></h2> + + <p>The <code>gDay</code> built-in XML Schema type is mapped to the + <code>gday</code> class which represents a day of the month with + an optional time zone. Its interface is presented below. For + more information on the base <code>xml_schema::time_zone</code> + class refer to <a href="#5.4">Section 5.4, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class gday: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + gday (); + + explicit + gday (unsigned short day); + + gday (unsigned short day, short zone_hours, short zone_minutes); + + unsigned short + day () const; + + void + day (unsigned short); + }; + + bool + operator== (const gday&, const gday&); + + bool + operator!= (const gday&, const gday&); +} + </pre> + + <h2><a name="5.9">5.9 Mapping for <code>gMonth</code></a></h2> + + <p>The <code>gMonth</code> built-in XML Schema type is mapped to the + <code>gmonth</code> class which represents a month of the year + with an optional time zone. Its interface is presented below. For + more information on the base <code>xml_schema::time_zone</code> + class refer to <a href="#5.4">Section 5.4, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class gmonth: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + gmonth (); + + explicit + gmonth (unsigned short month); + + gmonth (unsigned short month, + short zone_hours, short zone_minutes); + + unsigned short + month () const; + + void + month (unsigned short); + }; + + bool + operator== (const gmonth&, const gmonth&); + + bool + operator!= (const gmonth&, const gmonth&); +} + </pre> + + <h2><a name="5.10">5.10 Mapping for <code>gMonthDay</code></a></h2> + + <p>The <code>gMonthDay</code> built-in XML Schema type is mapped to the + <code>gmonth_day</code> class which represents a day and a month of + the year with an optional time zone. Its interface is presented below. + For more information on the base <code>xml_schema::time_zone</code> + class refer to <a href="#5.4">Section 5.4, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class gmonth_day: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + gmonth_day (); + + gmonth_day (unsigned short month, unsigned short day); + + gmonth_day (unsigned short month, unsigned short day, + short zone_hours, short zone_minutes); + + unsigned short + month () const; + + void + month (unsigned short); + + unsigned short + day () const; + + void + day (unsigned short); + }; + + bool + operator== (const gmonth_day&, const gmonth_day&); + + bool + operator!= (const gmonth_day&, const gmonth_day&); +} + </pre> + + <h2><a name="5.11">5.11 Mapping for <code>gYear</code></a></h2> + + <p>The <code>gYear</code> built-in XML Schema type is mapped to the + <code>gyear</code> class which represents a year with + an optional time zone. Its interface is presented below. + For more information on the base <code>xml_schema::time_zone</code> + class refer to <a href="#5.4">Section 5.4, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class gyear: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + gyear (); + + explicit + gyear (int year); + + gyear (int year, short zone_hours, short zone_minutes); + + int + year () const; + + void + year (int); + }; + + bool + operator== (const gyear&, const gyear&); + + bool + operator!= (const gyear&, const gyear&); +} + </pre> + + <h2><a name="5.12">5.12 Mapping for <code>gYearMonth</code></a></h2> + + <p>The <code>gYearMonth</code> built-in XML Schema type is mapped to the + <code>gyear_month</code> class which represents a year and a month + with an optional time zone. Its interface is presented below. + For more information on the base <code>xml_schema::time_zone</code> + class refer to <a href="#5.4">Section 5.4, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class gyear_month: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + gyear_month (); + + gyear_month (int year, unsigned short month); + + gyear_month (int year, unsigned short month, + short zone_hours, short zone_minutes); + + int + year () const; + + void + year (int); + + unsigned short + month () const; + + void + month (unsigned short); + }; + + bool + operator== (const gyear_month&, const gyear_month&); + + bool + operator!= (const gyear_month&, const gyear_month&); +} + </pre> + + + <h2><a name="5.13">5.13 Mapping for <code>time</code></a></h2> + + <p>The <code>time</code> built-in XML Schema type is mapped to the + <code>time</code> class which represents hours, minutes, + and seconds with an optional time zone. Its interface is presented below. + For more information on the base <code>xml_schema::time_zone</code> + class refer to <a href="#5.4">Section 5.4, "Time Zone + Representation"</a>.</p> + + <pre class="c++"> +namespace xml_schema +{ + class time: public time_zone + { + public: + // The default constructor creates an uninitialized object. + // Use modifiers to initialize it. + // + time (); + + time (unsigned short hours, unsigned short minutes, double seconds); + + time (unsigned short hours, unsigned short minutes, double seconds, + short zone_hours, short zone_minutes); + + unsigned short + hours () const; + + void + hours (unsigned short); + + unsigned short + minutes () const; + + void + minutes (unsigned short); + + double + seconds () const; + + void + seconds (double); + }; + + bool + operator== (const time&, const time&); + + bool + operator!= (const time&, const time&); +} + </pre> + + <h2><a name="5.14">5.14 Mapping for <code>anyType</code></a></h2> + + <p>The <code>anyType</code> built-in XML Schema type is mapped to + the <code>any_type</code> class in the <code>xml_schema</code> + namespace. With C++ exceptions enabled (<a href="#3.3">Section 3.3, + "C++ Exceptions"</a>), it has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class any_type + { + public: + // Custom data. + // + typedef xml_schema::data_sequence custom_data_sequence; + typedef custom_data_sequence::iterator custom_data_iterator; + typedef custom_data_sequence::const_iterator custom_data_const_iterator; + + void + allocate_custom_data (); + + const custom_data_sequence& + custom_data () const; + + custom_data_sequence& + custom_data (); + }; +} + </pre> + + <p>If C++ exceptions are disabled, the <code>any_type</code> class has + the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class any_type + { + public: + // Custom data. + // + typedef xml_schema::data_sequence custom_data_sequence; + typedef custom_data_sequence::iterator custom_data_iterator; + typedef custom_data_sequence::const_iterator custom_data_const_iterator; + + bool + allocate_custom_data (); + + const custom_data_sequence& + custom_data () const; + + custom_data_sequence& + custom_data (); + }; +} + </pre> + + <p>The <code>allocate_custom_data()</code> function allocates the + custom data sequence. With C++ exceptions disabled, it returns + <code>false</code> if memory allocation has failed and <code>true</code> + otherwise. For more information on custom data, refer to + <a href="#4.9">Section 4.9, "Customizing the Object Model"</a>.</p> + + <p>The default parser and serializer implementations for the + <code>anyType</code> built-in type ignore all its content and + return an empty <code>any_type</code> instance. If your application + needs to access this content, then you will need to provide your + own implementations of these parser and serializer and use the + custom data sequence to store the extracted data.</p> + + <!-- Parsing and Serialization --> + + <h1><a name="6">6 Parsing and Serialization</a></h1> + + <p>As was mentioned in the introduction, the C++/Hybrid mapping + uses the C++/Parser and C++/Serializer mappings for XML parsing + and serialization. If your parsing and serialization requirements + are fairly basic, for example, parsing from and serializing to + a file or a memory buffer, then you don't need to concern yourself + with these two underlying mappings. On the other hand, the C++/Parser + and C++/Serializer mappings provide well-defined APIs which allow + a great amount of flexibility that may be useful in certain situations. + In such cases, you may need to get an understanding of how the + C++/Parser and C++/Serializer mappings work. See the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml">Embedded + C++/Parser Mapping Getting Started Guide</a> and the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml">Embedded + C++/Serializer Mapping Getting Started Guide</a> for more detailed + information on these mappings.</p> + + <p>For each type defined in XML Schema, the C++/Parser and + C++/Serializer mappings generate a parser skeleton class and + serializer skeleton class, respectively. These classes manage + parsing/serialization state, convert data between text + and C++ types, and perform XML Schema validation, if enabled. + Parser skeletons deliver the parsed data and serializer + skeletons request the data to be serialized with callbacks. + These callbacks are implemented by parser and serializer + implementation classes that are derived from the skeletons. + If the application uses the C++/Parser and C++/Serializer + mappings directly, these implementation classes are normally + written by the application developer to perform some + application-specific actions. In case of the C++/Hybrid mapping, + these implementations are automatically generated by the XSD/e + compiler to parse XML to object models and to serialize object + models to XML. + To request the generation of parser skeletons and + implementations, you need to specify the <code>--generate-parser</code> + XSD/e command line option. Similarly, to generate serializer + skeletons and implementations, you will need to use the + <code>--generate-serializer</code> option.</p> + + <p>Before an XML document can be parsed or serialized, the + individual parser and serializer implementations need to + be instantiated and connected to each other. Again, if the + application uses the C++/Parser and C++/Serializer mappings + directly, this is done by the application developer. While + you can also do this with the generated C++/Hybrid parser and + serializer implementations, it is easier to request the + generation of parser and serializer aggregate classes with + the <code>--generate-aggregate</code> options. Aggregate + classes instantiate and connect all the necessary individual + parser and serializer implementations for a particular root + element or type. Consider again the <code>hello.xsd</code> + schema from <a href="#2">Chapter 2, "Hello World Example"</a>:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:complexType name="hello"> + <xs:sequence> + <xs:element name="greeting" type="xs:string"/> + <xs:element name="name" type="xs:string" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="hello" type="hello"/> + +</xs:schema> + </pre> + + <p>If we compile this schema with the <code>--generate-parser</code>, + <code>--generate-serializer</code>, and <code>--generate-aggregate</code> + options, we will have two aggregate classes, <code>hello_paggr</code> + and <code>hello_saggr</code>, generated for the root <code>hello</code> + element. The interface of the <code>hello_paggr</code> class is + presented below:</p> + + <pre class="c++"> +class hello_paggr +{ +public: + hello_paggr (); + + void + pre (); + + hello* + post (); + + hello_pimpl& + root_parser (); + + static const char* + root_name (); + + static const char* + root_namespace (); +}; + </pre> + + <p>The <code>pre()</code> and <code>post()</code> functions + call the corresponding callbacks on the root parser + implementation. The <code>root_parser()</code> function + returns the root parser implementation. The <code>root_name()</code> + and <code>root_namespace()</code> functions return the + root element name and namespace, respectively.</p> + + <p>As was shown in <a href="#2">Chapter 2, "Hello World Example"</a>, + we can use this parser aggregate to create the document parser + (supplied by the C++/Parser mapping) and perform the parsing:</p> + + <pre class="c++"> +hello_paggr hello_p; +xml_schema::document_pimpl doc_p (hello_p.root_parser (), + hello_p.root_name ()); +hello_p.pre (); +doc_p.parse ("hello.xml"); +hello* h = hello_p.post (); + </pre> + + <p>For more information on the <code>document_pimpl</code> class, + including the other variants of the <code>parse()</code> function + as well as error handling during parsing, see + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/index.xhtml#7">Chapter 7, + "Document Parser and Error Handling"</a> in the Embedded C++/Parser + Mapping Getting Started Guide.</p> + + <p>The interface of the <code>hello_saggr</code> serializer aggregate + mirrors that of <code>hello_paggr</code> and is presented below:</p> + + <pre class="c++"> +class hello_saggr +{ +public: + hello_saggr (); + + void + pre (const hello&); + + void + post (); + + hello_simpl& + root_serializer (); + + static const char* + root_name (); + + static const char* + root_namespace (); +}; + </pre> + + <p>The <code>pre()</code> and <code>post()</code> functions + call the corresponding callbacks on the root serializer + implementation. The <code>root_serializer()</code> function + returns the root serializer implementation. The + <code>root_name()</code> and <code>root_namespace()</code> + functions return the root element name and namespace, + respectively.</p> + + <p>As was shown in <a href="#2">Chapter 2, "Hello World Example"</a>, + we can use this serializer aggregate to create the document + serializer (supplied by the C++/Serializer mapping) and perform + the serialization:</p> + + <pre class="c++"> +hello_saggr hello_s; +xml_schema::document_simpl doc_s (hello_s.root_serializer (), + hello_s.root_name ()); +hello_s.pre (*h); +doc_s.serialize (std::cout, xml_schema::document_simpl::pretty_print); +hello_s.post (); + </pre> + + <p>For more information on the <code>document_simpl</code> class, + including the other variants of the <code>serialize()</code> + function as well as error handling during serialization, see + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/index.xhtml#8">Chapter 8, + "Document Serializer and Error Handling"</a> in the Embedded + C++/Serializer Mapping Getting Started Guide.</p> + + <h2><a name="6.1">6.1 Customizing Parsers and Serializers</a></h2> + + <p>The C++/Hybrid mapping allows you to customize the generated + parser and serializer implementations. This mechanism can be + used, for example, to implement filtering, partially + event-driven XML processing, as well as parsing of content + matched by XML Schema wildcards. Filtering allows only parts + of the XML document to be parsed into the object model or only + parts of the object model to be serialized to XML. With + partially event-driven parsing and serialization, we can + process parts of the document as they become available as + well as handle documents that are too large to fit into + memory. This section expects you to have an understanding + of the C++/Parser and C++/Serializer programming models.</p> + + <p>To request customization of a parser or serializer + implementation, you will need to specify the + <code>--custom-parser</code> or <code>--custom-serializer</code> + option, respectively. The argument format for these two options + is <code>name[=[base][/include]]]</code>. The <code><i>name</i></code> + component is the XML Schema type name being customized. Optional + <code><i>base</i></code> is a C++ name that should be given to the + generated version. It is normally used as a base for the custom + implementation. Optional <code><i>include</i></code> is the header file + that defines the custom implementation. It is <code>#include</code>'ed + into the generated code immediately after (if <code><i>base</i></code> + is specified) or instead of the generated version. The following + examples show how we can use these options:</p> + + <pre class="terminal"> +--custom-parser foo +--custom-parser foo=foo_base_pimpl +--custom-parser foo=foo_base_pimpl/foo/foo-custom.hxx +--custom-parser foo=/foo/foo-custom.hxx + </pre> + + <p>The first version instructs the XSD/e compiler not to generate + the parser implementation for the <code>foo</code> XML Schema + type. The second version instructs the compiler to generate + the parser implementation for type <code>foo</code> but call + it <code>foo_base_pimpl</code>. The third version is similar to the + second except that the compiler generates the <code>#include</code> + directive with the <code>foo/foo-custom.hxx</code> file (which + presumably defines <code>foo_pimpl</code>) right after the + <code>foo_base_pimpl</code> class. The last version instructs + the XSD/e compiler to include <code>foo/foo-custom.hxx</code> + instead of generating the parser implementation for + <code>foo</code>. If you omit the last component + (<code><i>include</i></code>), then + you can include the custom parser/serializer definitions + using one of the prologue or epilogue XSD/e compiler options. + See the <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a> for details.</p> + + <p>Once you specify the <code>--custom-parser</code> or + <code>--custom-serializer</code> option, you will need to + provide the custom implementation. You have a choice of either + basing it on the generated version and overriding some + callbacks or implementing it from scratch.</p> + + <p>In the remainder of this section we will examine how to + customize the <code>people</code> parser and serializer + implementations from the example presented in <a href="#4">Chapter 4, + "Working with Object Models"</a>. Our custom parser + implementation will filter the records being parsed + based on a person's age. Similarly, the serializer will + only serialize records of a specific gender. The code + presented below is taken from the <code>filter</code> + example in the XSD/e distribution. Other examples + related to parser/serializer customization are + <code>wildcard</code> and <code>streaming</code>.</p> + + <p>First, we compile the <code>people.xsd</code> schema + and instruct the XSD/e compiler to customize the + parser and serializer implementations for the <code>people</code> + XML Schema type:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--custom-parser people=people_base_pimpl/people-custom-pimpl.hxx \ +--custom-serializer people=people_base_simpl/people-custom-simpl.hxx \ +--generate-aggregate people.xsd + </pre> + + <p>The custom <code>people_pimpl</code> parser implementation + is based on the generated version and is saved to + <code>people-custom-pimpl.hxx</code>:</p> + + <pre class="c++"> +class people_pimpl: public people_base_pimpl +{ +public: + void + age_filter (unsigned short min, unsigned short max) + { + min_age_ = min; + max_age_ = max; + } + + virtual void + person (const ::person& p) + { + // Check if the age constraints are met. + // + unsigned short age = p.age (); + + if (age >= min_age_ && age <= max_age_) + people_base_pimpl::person (p); + } + +private: + unsigned short min_age_; + unsigned short max_age_; +}; + </pre> + + <p>Here we override the <code>person()</code> callback and, + if the filter conditions are satisfied, call the original + version which adds the person record to the object model. + Note that if the <code>person</code> object model class + were variable-length, then the instance would be + dynamically allocated and passed as a pointer. In this + situation, if we don't use the object, we need to delete it, + for example:</p> + +<pre class="c++"> +virtual void +person (const ::person* p) +{ + unsigned short age = p->age (); + + if (age >= min_age_ && age <= max_age_) + people_base_pimpl::person (p); + else + delete p; +} + </pre> + + <p>The custom <code>people_simpl</code> parser implementation + is also based on the generated version and is saved to + <code>people-custom-simpl.hxx</code>:</p> + + <pre class="c++"> +class people_simpl: public people_base_simpl +{ +public: + void + gender_filter (gender g) + { + gender_ = g; + } + + virtual bool + person_next () + { + // See if we have any more person records with the gender we + // are interested in. + // + people::person_const_iterator& i = people_base_simpl_state_.person_; + people::person_const_iterator& e = people_base_simpl_state_.person_end_; + + for (; i != e; ++i) + { + if (i->gender () == gender_) + break; + } + + return i != e; + } + +private: + gender gender_; +}; + </pre> + + <p>Here we override the <code>person_next()</code> callback + where we locate the next record that satisfies the filter + conditions. Note that we use the serialization state + provided by the generated <code>people_base_simpl</code> + implementation.</p> + + <p>The following code fragment shows a test driver that uses + the above implementations to filter the data during parsing + and serialization:</p> + + <pre class="c++"> +#include <memory> +#include <iostream> + +#include "people.hxx" + +#include "people-pimpl.hxx" +#include "people-simpl.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + // Parse. + // + people_paggr people_p; + people_pimpl& root_p = people_p.root_parser (); + + // Initialize the filter. + // + root_p.age_filter (1, 30); + + xml_schema::document_pimpl doc_p (root_p, people_p.root_name ()); + + people_p.pre (); + doc_p.parse (argv[1]); + auto_ptr<people> ppl (people_p.post ()); + + // Print what we've got. + // + people::person_sequence& ps = ppl->person (); + + for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) + { + cerr << "first: " << i->first_name () << endl + << "last: " << i->last_name () << endl + << "gender: " << i->gender ().string () << endl + << "age: " << i->age () << endl + << endl; + } + + // Serialize. + // + people_saggr people_s; + people_simpl& root_s = people_s.root_serializer (); + + // Initialize the filter. + // + root_s.gender_filter (gender::female); + + xml_schema::document_simpl doc_s (root_s, people_s.root_name ()); + + people_s.pre (*ppl); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + people_s.post (); +} + </pre> + + <p>If we run this test driver on the following XML document:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<people> + + <person> + <first-name>John</first-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>32</age> + </person> + + <person> + <first-name>Jane</first-name> + <last-name>Doe</last-name> + <gender>female</gender> + <age>28</age> + </person> + + <person> + <first-name>Joe</first-name> + <last-name>Dirt</last-name> + <gender>male</gender> + <age>25</age> + </person> + +</people> + </pre> + + <p>We will get the following output:</p> + + <pre class="terminal"> +first: Jane +last: Doe +gender: female +age: 28 + +first: Joe +last: Dirt +gender: male +age: 25 + +<people> + <person> + <first-name>Jane</first-name> + <last-name>Doe</last-name> + <gender>female</gender> + <age>28</age> + </person> +</people> + </pre> + + + <!-- Binary Representations --> + + <h1><a name="7">7 Binary Representation</a></h1> + + <p>Besides reading from and writing to XML, the C++/Hybrid mapping + also allows you to save the object model to and load it from a + number of predefined as well as custom data representation + formats. The predefined binary formats are CDR (Common Data + Representation) and XDR (eXternal Data Representation). A + custom format can easily be supported by providing + insertion and extraction operators for basic types.</p> + + <p>Binary representations contain only the data without any meta + information or markup. Consequently, saving to and loading + from a binary representation can be an order of magnitude + faster as well as result in a much smaller footprint compared + to parsing and serializing the same data in XML. Furthermore, + the resulting representation is normally several times smaller + than the equivalent XML representation. These properties make a + binary representation ideal for internal data exchange and storage. + A typical application that uses this facility stores the data and + communicates within the system using a binary format and reads/writes + the data in XML when communicating with the outside world.</p> + + <p>In order to request the generation of insertion and extraction + operators for a specific predefined or custom data representation + stream, you will need to use the <code>--generate-insertion</code> + and <code>--generate-extraction</code> compiler options. See the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a> for more information.</p> + + <p>The XSD/e runtime provides implementations of the base insertion + and extraction operators for the ACE (Adaptive Communication + Environment) CDR streams and the XDR API. The XDR API is available + out of the box on most POSIX systems as part of Sun RPC. On other + platforms you may need to install a third-party library which + provides the XDR API. + + The XSD/e compiler recognizes two special argument values to the + <code>--generate-insertion</code> and <code>--generate-extraction</code> + options: <code>CDR</code> and <code>XDR</code>. When one of these + arguments is specified, the corresponding implementation from the + XSD/e runtime is automatically used. The following two sections + describe each of these two formats in more detail. It is also + possible to add support for saving the object model to and loading + it from custom data representation formats as discussed in the + last section of this chapter.</p> + + <p>The saving of the object model types to a representation stream + is implemented with stream insertion operators + (<code>operator<<</code>). Similarly, loading of the object + model from a representation stream is implemented with stream + extraction operators (<code>operator>></code>). The insertion + and extraction operators for the built-in XML Schema types as + well as the sequence templates are provided by the stream + implementation (that is, by the XSD/e runtime in case of CDR and + XDR and by you for custom formats). The XSD/e compiler automatically + generates insertion and extraction operators for the generated object + model types.</p> + + <p>When C++ exceptions are enabled (<a href="#3.3">Section 3.3, "C++ + Exceptions"</a>), the signatures of the insertion and extraction + operators are as follows:</p> + + <pre class="c++"> +void +operator<< (ostream&, const type&); + +void +operator>> (istream&, type&); + </pre> + + <p>The insertion and extraction errors are indicated by throwing + stream-specific exceptions. When C++ exceptions are disabled, + the signatures of the insertion and extraction operators are + as follows:</p> + + <pre class="c++"> +bool +operator<< (ostream&, const type&); + +bool +operator>> (istream&, type&); + </pre> + + <p>In this case the insertion and extraction operators return + <code>true</code> if the operation was successful and + <code>false</code> otherwise. The stream object may + provide additional error information.</p> + + + <h2><a name="7.1">7.1 CDR (Common Data Representation)</a></h2> + + <p>When you request the generation of CDR stream insertion and extraction + operators, the <code>ocdrstream</code> and <code>icdrstream</code> + types are defined in the <code>xml_schema</code> namespace. Additionally, + if C++ exceptions are enabled, the <code>cdr_exception</code> exception + is also defined in <code>xml_schema</code>. The <code>icdrstream</code> + and <code>ocdrstream</code> types are simple wrappers for the + ACE_InputCDR and ACE_OutputCDR streams. The following code fragment + shows how we can use these types when C++ exceptions are enabled:</p> + + <pre class="c++"> +try +{ + const type& x = ... // Object model. + + // Save to a CDR stream. + // + ACE_OutputCDR ace_ocdr; + xml_schema::ocdrstream ocdr (ace_ocdr); + + ocdr << x; + + // Load from a CDR stream. + // + ACE_InputCDR ace_icdr (buf, size); + xml_schema::icdrstream icdr (ace_icdr); + + type copy; + icdr >> copy; +} +catch (const xml_schema::cdr_exception&) +{ + cerr << "CDR operation failed" << endl; +} + </pre> + + <p>The same code fragment but when C++ exceptions are disabled:</p> + + <pre class="c++"> +const type& x = ... // Object model. + +// Save to a CDR stream. +// +ACE_OutputCDR ace_ocdr; +xml_schema::ocdrstream ocdr (ace_ocdr); + +if (!(ocdr << x)) +{ + cerr << "CDR operation failed" << endl; +} + +// Load from a CDR stream. +// +ACE_InputCDR ace_icdr (buf, size); +xml_schema::icdrstream icdr (ace_icdr); + +type copy; + +if (!(icdr >> copy)) +{ + cerr << "CDR operation failed" << endl; +} + </pre> + + <p>The <code>cdr</code> example which can be found in the + <code>examples/cxx/hybrid/binary/</code> directory of the XSD/e + distribution includes complete source code that shows how to + save the object model to and load it from the CDR format.</p> + + <h2><a name="7.2">7.2 XDR (eXternal Data Representation)</a></h2> + + <p>When you request the generation of XDR stream insertion and extraction + operators, the <code>oxdrstream</code> and <code>xcdrstream</code> + types are defined in the <code>xml_schema</code> namespace. Additionally, + if C++ exceptions are enabled, the <code>xdr_exception</code> exception + is also defined in <code>xml_schema</code>. The <code>ixdrstream</code> + and <code>oxdrstream</code> types are simple wrappers for the XDR + API. The following code fragment shows how we can use these types + when C++ exceptions are enabled:</p> + + <pre class="c++"> +try +{ + const type& x = ... // Object model. + + // Save to a XDR stream. + // + XDR xdr; + xdrrec_create (&xdr, ...); + xml_schema::oxdrstream oxdr (xdr); + + oxdr << x; + + // Load from a XDR stream. + // + xdrrec_create (&xdr, ...); + xml_schema::ixdrstream ixdr (xdr); + + type copy; + ixdr >> copy; +} +catch (const xml_schema::xdr_exception&) +{ + cerr << "XDR operation failed" << endl; +} + </pre> + + <p>The same code fragment but when C++ exceptions are disabled:</p> + + <pre class="c++"> +const type& x = ... // Object model. + +// Save to a XDR stream. +// +XDR xdr; +xdrrec_create (&xdr, ...); +xml_schema::oxdrstream oxdr (xdr); + +if (!(oxdr << x)) +{ + cerr << "XDR operation failed" << endl; +} + +// Load from a XDR stream. +// +xdrrec_create (&xdr, ...); +xml_schema::ixdrstream ixdr (xdr); + +type copy; + +if (!(ixdr >> copy)) +{ + cerr << "XDR operation failed" << endl; +} + </pre> + + <p>The <code>xdr</code> example which can be found in the + <code>examples/cxx/hybrid/binary/</code> directory of the XSD/e + distribution includes complete source code that shows how to + save the object model to and load it from the XDR format.</p> + + + <h2><a name="7.3">7.3 Custom Representations</a></h2> + + <p>To add support for saving the object model to and loading it + from a custom format, you will need to perform the following + general steps:</p> + + <ol class="list"> + <li>Generate a header file corresponding to the XML Schema + namespace using the <code>--generate-xml-schema</code> + compiler option.</li> + + <li>Implement custom stream insertion and extraction operators + for the built-in XML Schema types and sequence templates. + Include the header file obtained in the previous step to + get definitions for these types.</li> + + <li>Compile your schemas with the <code>--generate-insertion</code> + and <code>--generate-extraction</code> options. The arguments + to these options will be your custom output and input stream + types, respectively. Use the <code>--hxx-prologue</code> + option to include the definitions for these stream types + into the generated code. Also use the + <code>--extern-xml-schema</code> option to include the + header file obtained in the first step instead of generating + the same code directly.</li> + </ol> + + <p>The <code>custom</code> example which can be found in the + <code>examples/cxx/hybrid/binary/</code> directory of the XSD/e + distribution includes complete source code that shows how to + save the object model to and load it from a custom format using + the raw binary representation as an example. You can use the + source code from this example as a base to implement support + for your own format.</p> + + </div> +</div> + + +</body> +</html> diff --git a/doc/cxx/hybrid/guide/makefile b/doc/cxx/hybrid/guide/makefile new file mode 100644 index 0000000..296a745 --- /dev/null +++ b/doc/cxx/hybrid/guide/makefile @@ -0,0 +1,48 @@ +# file : doc/cxx/hybrid/guide/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2006-2011 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +default := $(out_base)/ +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +cleandoc := $(out_base)/.cleandoc + +# Build. +# +$(default): $(out_base)/cxx-hybrid-e-guide.ps \ + $(out_base)/cxx-hybrid-e-guide.pdf + + +$(out_base)/cxx-hybrid-e-guide.ps: $(src_base)/index.xhtml \ + $(src_base)/figure-1.png \ + $(src_base)/guide.html2ps \ + | $(out_base)/. + $(call message,html2ps $<,html2ps -f $(src_base)/guide.html2ps -o $@ $<) + +$(out_base)/cxx-hybrid-e-guide.pdf: $(out_base)/cxx-hybrid-e-guide.ps | $(out_base)/. + $(call message,ps2pdf $<,ps2pdf14 $< $@) + +# Dist. +# +$(dist): path := $(subst $(src_root)/,,$(src_base)) +$(dist): $(out_base)/cxx-hybrid-e-guide.ps $(out_base)/cxx-hybrid-e-guide.pdf + $(call install-data,$(src_base)/figure-1.png,$(dist_prefix)/$(path)/figure-1.png) + $(call install-data,$(src_base)/index.xhtml,$(dist_prefix)/$(path)/index.xhtml) + $(call install-data,$(out_base)/cxx-hybrid-e-guide.ps,$(dist_prefix)/$(path)/cxx-hybrid-e-guide.ps) + $(call install-data,$(out_base)/cxx-hybrid-e-guide.pdf,$(dist_prefix)/$(path)/cxx-hybrid-e-guide.pdf) + +$(dist-win): $(dist) + + +# Clean. +# +$(cleandoc): + $(call message,rm $$1,rm -f $$1,$(out_base)/cxx-hybrid-e-guide.ps) + $(call message,rm $$1,rm -f $$1,$(out_base)/cxx-hybrid-e-guide.pdf) + +# How to. +# +$(call include,$(bld_root)/install.make) |