diff options
Diffstat (limited to 'doc/cxx')
-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 | ||||
-rw-r--r-- | doc/cxx/makefile | 20 | ||||
-rw-r--r-- | doc/cxx/parser/guide/figure-1.png | bin | 0 -> 34195 bytes | |||
-rw-r--r-- | doc/cxx/parser/guide/figure-1.svg | 373 | ||||
-rw-r--r-- | doc/cxx/parser/guide/guide.html2ps | 65 | ||||
-rw-r--r-- | doc/cxx/parser/guide/index.xhtml | 5383 | ||||
-rw-r--r-- | doc/cxx/parser/guide/makefile | 48 | ||||
-rw-r--r-- | doc/cxx/serializer/guide/figure-1.png | bin | 0 -> 30198 bytes | |||
-rw-r--r-- | doc/cxx/serializer/guide/figure-1.svg | 372 | ||||
-rw-r--r-- | doc/cxx/serializer/guide/guide.html2ps | 65 | ||||
-rw-r--r-- | doc/cxx/serializer/guide/index.xhtml | 6542 | ||||
-rw-r--r-- | doc/cxx/serializer/guide/makefile | 48 |
16 files changed, 19767 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) diff --git a/doc/cxx/makefile b/doc/cxx/makefile new file mode 100644 index 0000000..4704c60 --- /dev/null +++ b/doc/cxx/makefile @@ -0,0 +1,20 @@ +# file : doc/cxx/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 + +mappings := hybrid/guide parser/guide serializer/guide + +default := $(out_base)/ +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +cleandoc := $(out_base)/.cleandoc + +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(mappings))) +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(mappings))) +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(mappings))) +$(cleandoc): $(addprefix $(out_base)/,$(addsuffix /.cleandoc,$(mappings))) + +$(foreach m,$(mappings),$(call import,$(src_base)/$m/makefile)) diff --git a/doc/cxx/parser/guide/figure-1.png b/doc/cxx/parser/guide/figure-1.png Binary files differnew file mode 100644 index 0000000..15d1723 --- /dev/null +++ b/doc/cxx/parser/guide/figure-1.png diff --git a/doc/cxx/parser/guide/figure-1.svg b/doc/cxx/parser/guide/figure-1.svg new file mode 100644 index 0000000..d994a79 --- /dev/null +++ b/doc/cxx/parser/guide/figure-1.svg @@ -0,0 +1,373 @@ +<?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://web.resource.org/cc/" + 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="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/tmp" + sodipodi:docname="figure-1.svg" + inkscape:export-filename="/home/boris/tmp/figure-1.png" + inkscape:export-xdpi="76.195885" + inkscape:export-ydpi="76.195885"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Lend" + style="overflow:visible;"> + <path + id="path2934" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.8) rotate(180) translate(12.5,0)" /> + </marker> + <marker + inkscape:stockid="Dot_l" + orient="auto" + refY="0.0" + refX="0.0" + id="Dot_l" + style="overflow:visible"> + <path + id="path2875" + d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none" + transform="scale(0.8) translate(7.4, 1)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path2928" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <marker + inkscape:stockid="Dot_m" + orient="auto" + refY="0.0" + refX="0.0" + id="Dot_m" + style="overflow:visible"> + <path + id="path2872" + d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none" + transform="scale(0.4) translate(7.4, 1)" /> + </marker> + <marker + inkscape:stockid="Arrow1Lstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Lstart" + style="overflow:visible"> + <path + id="path2937" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.8) translate(12.5,0)" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow2Mend" + style="overflow:visible;"> + <path + id="path2910" + style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(0.6) rotate(180) translate(0,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="328.23027" + inkscape:cy="733.01096" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="1280" + inkscape:window-height="991" + inkscape:window-x="154" + inkscape:window-y="44" /> + <metadata + id="metadata7"> + <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"> + <g + id="g3902"> + <rect + y="194.64178" + x="24.142784" + height="106.2678" + width="149.70432" + id="rect1872" + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.29799986;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <text + sodipodi:linespacing="125%" + id="text3038" + y="219.99649" + x="28.284279" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;color:black;fill:black;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:Monospace" + xml:space="preserve"><tspan + y="219.99649" + x="28.284279" + id="tspan3064" + sodipodi:role="line">class people_pimpl</tspan><tspan + y="236.24649" + x="28.284279" + id="tspan3066" + sodipodi:role="line">{</tspan><tspan + y="252.49649" + x="28.284279" + id="tspan3068" + sodipodi:role="line"> void </tspan><tspan + y="268.74649" + x="28.284279" + id="tspan3070" + sodipodi:role="line"> person ();</tspan><tspan + y="284.99649" + x="28.284279" + id="tspan3072" + sodipodi:role="line">};</tspan></text> + </g> + <g + id="g3881"> + <rect + y="124.93772" + x="252.43373" + height="245.67592" + width="180.01601" + id="rect5750" + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:9.12976837;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <text + sodipodi:linespacing="100%" + id="text5752" + y="148.27567" + x="257.5889" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:black;fill:black;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:Monospace" + xml:space="preserve"><tspan + y="148.27567" + x="257.5889" + id="tspan5900" + sodipodi:role="line">class person_pimpl</tspan><tspan + y="161.27567" + x="257.5889" + id="tspan5902" + sodipodi:role="line">{</tspan><tspan + y="174.27567" + x="257.5889" + id="tspan5904" + sodipodi:role="line"> void</tspan><tspan + y="187.27567" + x="257.5889" + id="tspan5906" + sodipodi:role="line"> first_name (string);</tspan><tspan + y="200.27567" + x="257.5889" + id="tspan5908" + sodipodi:role="line" /><tspan + y="213.27567" + x="257.5889" + id="tspan5910" + sodipodi:role="line"> void</tspan><tspan + y="226.27567" + x="257.5889" + id="tspan5912" + sodipodi:role="line"> last_name (string);</tspan><tspan + y="239.27567" + x="257.5889" + id="tspan5914" + sodipodi:role="line" /><tspan + y="252.27567" + x="257.5889" + id="tspan5916" + sodipodi:role="line"> void</tspan><tspan + y="265.27567" + x="257.5889" + id="tspan5918" + sodipodi:role="line"> gender ();</tspan><tspan + y="278.27567" + x="257.5889" + id="tspan5920" + sodipodi:role="line" /><tspan + y="291.27567" + x="257.5889" + id="tspan5922" + sodipodi:role="line"> void</tspan><tspan + y="304.27567" + x="257.5889" + id="tspan5924" + sodipodi:role="line"> age (short);</tspan><tspan + y="317.27567" + x="257.5889" + id="tspan5926" + sodipodi:role="line"> </tspan><tspan + y="330.27567" + x="257.5889" + id="tspan5928" + sodipodi:role="line"> void</tspan><tspan + y="343.27567" + x="257.5889" + id="tspan5930" + sodipodi:role="line"> post_person ();</tspan><tspan + y="356.27567" + x="257.5889" + id="tspan5932" + sodipodi:role="line">};</tspan></text> + </g> + <g + id="g3845"> + <rect + y="77.741814" + x="506.28357" + height="99.610825" + width="151.1286" + id="rect5955" + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.69227886;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <flowRoot + transform="translate(-5.050762,12.10153)" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + id="flowRoot5957" + xml:space="preserve"><flowRegion + id="flowRegion5959"><rect + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + y="74.534515" + x="516.18793" + height="88.893425" + width="143.44167" + id="rect5961" /></flowRegion><flowPara + id="flowPara5965">class string_pimpl</flowPara><flowPara + id="flowPara5967">{</flowPara><flowPara + id="flowPara5969"> string</flowPara><flowPara + id="flowPara5971"> post_string ();</flowPara><flowPara + id="flowPara5973">};</flowPara><flowPara + id="flowPara5975" /></flowRoot> </g> + <g + id="g3857"> + <rect + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.69227886;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect5977" + width="151.1286" + height="99.610825" + x="506.28357" + y="316.15808" /> + <flowRoot + xml:space="preserve" + id="flowRoot5979" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + transform="translate(-5.050761,250.5178)" + inkscape:export-filename="/tmp/figure-1.png" + inkscape:export-xdpi="546.53815" + inkscape:export-ydpi="546.53815"><flowRegion + id="flowRegion5981"><rect + id="rect5983" + width="143.44167" + height="88.893425" + x="516.18793" + y="74.534515" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" /></flowRegion><flowPara + id="flowPara5985">class short_pimpl</flowPara><flowPara + id="flowPara5987">{</flowPara><flowPara + id="flowPara5989"> short</flowPara><flowPara + id="flowPara5991"> post_short ();</flowPara><flowPara + id="flowPara5993">};</flowPara><flowPara + id="flowPara5995" /></flowRoot> </g> + <g + id="g3869"> + <rect + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.69227886;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect6023" + width="151.1286" + height="99.610825" + x="505.7785" + y="196.93977" /> + <flowRoot + xml:space="preserve" + id="flowRoot6025" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + transform="translate(-5.555838,129.2792)"><flowRegion + id="flowRegion6027"><rect + id="rect6029" + width="143.44167" + height="88.893425" + x="516.18793" + y="74.534515" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" /></flowRegion><flowPara + id="flowPara6031">class gender_pimpl</flowPara><flowPara + id="flowPara6033">{</flowPara><flowPara + id="flowPara6035"> void</flowPara><flowPara + id="flowPara6037"> post_gender ();</flowPara><flowPara + id="flowPara6039">};</flowPara><flowPara + id="flowPara6041" /></flowRoot> </g> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;marker-start:url(#Dot_l);marker-end:url(#Arrow1Lend)" + d="M 265.67011,339.69956 L 210.41811,339.34242 L 210.77124,264.14332 L 127.7843,264.4432" + id="path6051" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cccs" /> + <path + sodipodi:nodetypes="cccc" + inkscape:connector-type="polyline" + id="path6077" + d="M 518.20825,383.6412 L 471.23616,384.14628 L 471.4887,300.55615 L 368.70568,300.80869" + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" + d="M 517.1981,262.42289 L 353.55339,262.42289" + id="path6081" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cccs" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" + d="M 518.57143,145.93361 L 470.35714,146.14281 L 470.53572,183.07646 L 431.42857,183.79075" + id="path6089" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" + d="M 470.46175,178.43361 L 470.89286,222.36218 L 423.21428,222.71932" + id="path6091" + inkscape:connector-type="polyline" + sodipodi:nodetypes="ccc" /> + </g> +</svg> diff --git a/doc/cxx/parser/guide/guide.html2ps b/doc/cxx/parser/guide/guide.html2ps new file mode 100644 index 0000000..bfeca9e --- /dev/null +++ b/doc/cxx/parser/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++/Parser 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/parser/guide/index.xhtml'>XHTML</a>, + <a href='http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/cxx-parser-e-guide.pdf'>PDF</a>, and + <a href='http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/cxx-parser-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/parser/guide/index.xhtml b/doc/cxx/parser/guide/index.xhtml new file mode 100644 index 0000000..d070c5a --- /dev/null +++ b/doc/cxx/parser/guide/index.xhtml @@ -0,0 +1,5383 @@ +<?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++/Parser 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,parser,validation,embedded,mobile"/> + <meta name="description" content="Embedded C++/Parser Mapping Getting Started Guide"/> + + <link rel="stylesheet" type="text/css" href="../../../default.css" /> + +<style type="text/css"> + pre { + padding : 0 0 0 0em; + margin : 0em 0em 0em 0; + + font-size : 102% + } + + body { + min-width: 48em; + } + + h1 { + font-weight: bold; + font-size: 200%; + line-height: 1.2em; + } + + h2 { + font-weight : bold; + font-size : 150%; + + padding-top : 0.8em; + } + + h3 { + font-size : 140%; + padding-top : 0.8em; + } + + /* Adjust indentation for three levels. */ + #container { + max-width: 48em; + } + + #content { + padding: 0 0.1em 0 4em; + /*background-color: red;*/ + } + + #content h1 { + margin-left: -2.06em; + } + + #content h2 { + margin-left: -1.33em; + } + + /* Title page */ + + #titlepage { + padding: 2em 0 1em 0; + border-bottom: 1px solid black; + } + + #titlepage .title { + font-weight: bold; + font-size: 200%; + text-align: center; + } + + #titlepage #first-title { + padding: 1em 0 0.4em 0; + } + + #titlepage #second-title { + padding: 0.4em 0 2em 0; + } + + /* Lists */ + ul.list li { + padding-top : 0.3em; + padding-bottom : 0.3em; + } + + ol.steps { + padding-left : 1.8em; + } + + ol.steps 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; + } + + /* XML Schema features table. */ + #features { + margin: 2em 0 2em 0; + + border-collapse : collapse; + border : 1px solid; + border-color : #000000; + + font-size : 11px; + line-height : 14px; + } + + #features th, #features td { + border: 1px solid; + padding : 0.6em 0.6em 0.6em 0.6em; + } + + #features th { + background : #cde8f6; + } + + #features 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++/Parser 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/parser/guide/index.xhtml">XHTML</a>, + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/cxx-parser-e-guide.pdf">PDF</a>, and + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/parser/guide/cxx-parser-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> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">Parser Skeletons</a> + <table class="toc"> + <tr><th>3.1</th><td><a href="#3.1">Implementing the Gender Parser</a></td></tr> + <tr><th>3.2</th><td><a href="#3.2">Implementing the Person Parser</a></td></tr> + <tr><th>3.3</th><td><a href="#3.3">Implementing the People Parser</a></td></tr> + <tr><th>3.4</th><td><a href="#3.4">Connecting the Parsers Together</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>4</th><td><a href="#4">Type Maps</a> + <table class="toc"> + <tr><th>4.1</th><td><a href="#4.1">Object Model</a></td></tr> + <tr><th>4.2</th><td><a href="#4.2">Type Map File Format</a></td></tr> + <tr><th>4.3</th><td><a href="#4.3">Parser Implementations</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>5</th><td><a href="#5">Mapping Configuration</a> + <table class="toc"> + <tr><th>5.1</th><td><a href="#5.1">Standard Template Library</a></td></tr> + <tr><th>5.2</th><td><a href="#5.2">Input/Output Stream Library</a></td></tr> + <tr><th>5.3</th><td><a href="#5.3">C++ Exceptions</a></td></tr> + <tr><th>5.4</th><td><a href="#5.4">XML Schema Validation</a></td></tr> + <tr><th>5.5</th><td><a href="#5.5">64-bit Integer Type</a></td></tr> + <tr><th>5.6</th><td><a href="#5.6">Parser Reuse</a></td></tr> + <tr><th>5.7</th><td><a href="#5.7">Support for Polymorphism</a></td></tr> + <tr><th>5.8</th><td><a href="#5.8">Custom Allocators</a></td></tr> + <tr><th>5.9</th><td><a href="#5.9">A Minimal Example</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>6</th><td><a href="#6">Built-In XML Schema Type Parsers</a> + <table class="toc"> + <tr><th>6.1</th><td><a href="#6.1"><code>QName</code> Parser</a></td></tr> + <tr><th>6.2</th><td><a href="#6.2"><code>NMTOKENS</code> and <code>IDREFS</code> Parsers</a></td></tr> + <tr><th>6.3</th><td><a href="#6.3"><code>base64Binary</code> and <code>hexBinary</code> Parsers</a></td></tr> + <tr><th>6.4</th><td><a href="#6.4">Time Zone Representation</a></td></tr> + <tr><th>6.5</th><td><a href="#6.5"><code>date</code> Parser</a></td></tr> + <tr><th>6.6</th><td><a href="#6.6"><code>dateTime</code> Parser</a></td></tr> + <tr><th>6.7</th><td><a href="#6.7"><code>duration</code> Parser</a></td></tr> + <tr><th>6.8</th><td><a href="#6.8"><code>gDay</code> Parser</a></td></tr> + <tr><th>6.9</th><td><a href="#6.9"><code>gMonth</code> Parser</a></td></tr> + <tr><th>6.10</th><td><a href="#6.10"><code>gMonthDay</code> Parser</a></td></tr> + <tr><th>6.11</th><td><a href="#6.11"><code>gYear</code> Parser</a></td></tr> + <tr><th>6.12</th><td><a href="#6.12"><code>gYearMonth</code> Parser</a></td></tr> + <tr><th>6.13</th><td><a href="#6.13"><code>time</code> Parser</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>7</th><td><a href="#7">Document Parser and Error Handling</a> + <table class="toc"> + <tr><th>7.1</th><td><a href="#7.1">Document Parser</a></td></tr> + <tr><th>7.2</th><td><a href="#7.2">Exceptions</a></td></tr> + <tr><th>7.3</th><td><a href="#7.3">Error Codes</a></td></tr> + <tr><th>7.4</th><td><a href="#7.4">Reusing Parsers after an Error</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th></th><td><a href="#A">Appendix A — Supported XML Schema Constructs</a></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++/Parser 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>The <code>INSTALL</code> file in the XSD/e distribution provides + build instructions for various platforms.</li> + + <li>The <code>examples/cxx/parser/</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++/Parser 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++/Parser mapping. + XSD/e is a dependency-free W3C XML Schema to C++ compiler for mobile, + embedded, and light-weight applications. Embedded C++/Parser is an + XML Schema to C++ mapping that represents an XML vocabulary as a set + of parser skeletons which you can implement to perform XML processing + as required by your application logic. + </p> + + <h2><a name="1.1">1.1 Mapping Overview</a></h2> + + <p>The Embedded C++/Parser mapping provides event-driven, stream-oriented + XML parsing, XML Schema validation, and C++ data binding. It 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 + parsers are 2-10 times faster than general-purpose validating + XML parsers while at the same time maintaining extremely low static + and dynamic memory footprints. For example, a validating parser + executable can be as small as 120KB in size. The size can be + further reduced by disabling support for 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 C++ templates.</p> + + <p>To speed up application development, the C++/Parser mapping + can be instructed to generate sample parser implementations + and a test driver which can then be filled with the application + logic code. The mapping also provides a wide range of + mechanisms for controlling and customizing the generated code.</p> + + <p>The next chapter shows how to create a simple application + that uses the Embedded C++/Parser mapping to parse, validate, + and extract data from a simple XML instance document. The + following chapters describe the Embedded C++/Parser 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>Text-based representation results in inefficient use of + resources.</li> + + <li>Extra validation code that is not used by the application.</li> + + <li>Generic representation of XML in terms of elements, attributes, + and text forces an application developer to write a substantial + amount of bridging code that identifies and transforms pieces + of information encoded in XML to a representation more suitable + for consumption by the application logic.</li> + + <li>String-based flow control defers error detection to runtime. + It also reduces code readability and maintainability.</li> + + <li>Lack of type safety because all information is represented + as text.</li> + + <li>Resulting applications are hard to debug, change, and + maintain.</li> + </ul> + + <p>In contrast, statically-typed, vocabulary-specific parser + skeletons produced by the Embedded C++/Parser mapping use + native data representations (for example, integers are passed as + integers, not as text) and include validation code 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, the parser skeletons allow you to operate in your + domain terms instead of the generic elements, attributes, and + text. Static typing helps catch errors at compile-time rather + than at run-time. Automatic code generation frees you for more + interesting tasks (such as doing something useful with the + information stored in the XML documents) and minimizes the + effort needed to adapt your applications to changes in the + document structure. To summarize, the C++/Parser mapping 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 recreating the document structure, maintaining the + dispatch state, and converting the data from the text representation + to data types suitable for manipulation by the application logic. + Parser skeletons also provide a convenient mechanism for building + custom in-memory representations.</li> + + <li><b>Natural representation.</b> The generated parser skeletons + implement parser callbacks as virtual functions with names + corresponding to elements and attributes in XML. As a result, + you process the XML data using your domain vocabulary instead + of generic elements, attributes, and text. + </li> + + <li><b>Concise code.</b> With a separate parser skeleton for each + XML Schema type, the application implementation is + simpler and thus easier to read and understand.</li> + + <li><b>Safety.</b> The XML data is delivered to parser callbacks as + statically typed objects. The parser callbacks themselves are virtual + functions. 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 application code that need to be + changed.</li> + + <li><b>Efficiency.</b> The generated parser skeletons use native + data representations and combine data extraction, validation, + and even dispatching in a single step. This makes them much + more efficient than traditional architectures with separate + stages for validation and data extraction/dispatch.</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 a very simple XML + document using the XSD/e-generated C++/Parser skeletons. + + All the code presented in this chapter is based on the <code>hello</code> + example which can be found in the <code>examples/cxx/parser/</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 the XML Schema language, 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>unbounde</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 vocabulary; it tells + everybody what valid XML instances of our vocabulary should look + like. The next step is to compile this schema to generate C++ parser + skeletons.</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++ parser + skeletons. To do this we invoke the XSD/e compiler from a terminal + (UNIX) or a command prompt (Windows): + </p> + + <pre class="terminal"> +$ xsde cxx-parser hello.xsd + </pre> + + <p>The XSD/e compiler produces two C++ files: <code>hello-pskel.hxx</code> + and <code>hello-pskel.cxx</code>. The following code fragment is taken + from <code>hello-pskel.hxx</code>; it should give you an idea about what + gets generated: + </p> + + <pre class="c++"> +class hello_pskel +{ +public: + // Parser callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual void + greeting (const std::string&); + + virtual void + name (const std::string&); + + virtual void + post_hello (); + + // Parser construction API. + // + void + greeting_parser (xml_schema::string_pskel&); + + void + name_parser (xml_schema::string_pskel&); + + void + parsers (xml_schema::string_pskel& /* greeting */, + xml_schema::string_pskel& /* name */); + +private: + ... +}; + </pre> + + <p>The first four member functions shown above are called parser + callbacks. You would normally override them in your implementation + of the parser to do something useful. Let's go through all of + them one by one.</p> + + <p>The <code>pre()</code> function is an initialization callback. It is + called when a new element of type <code>hello</code> is about + to be parsed. You would normally use this function to allocate a new + instance of the resulting type or clear accumulators that are used + to gather information during parsing. The default implementation + of this function does nothing.</p> + + <p>The <code>post_hello()</code> function is a finalization callback. Its + name is constructed by adding the parser skeleton name to the + <code>post_</code> prefix. The finalization callback is called when + parsing of the element is complete and the result, if any, should + be returned. Note that in our case the return type of + <code>post_hello()</code> is <code>void</code> which means there + is nothing to return. More on parser return types later. + </p> + + <p>You may be wondering why the finalization callback is called + <code>post_hello()</code> instead of <code>post()</code> just + like <code>pre()</code>. The reason for this is that + finalization callbacks can have different return types and + result in function signature clashes across inheritance + hierarchies. To prevent this, the signatures of finalization + callbacks are made unique by adding the type name to their names.</p> + + <p>The <code>greeting()</code> and <code>name()</code> functions are + called when the <code>greeting</code> and <code>name</code> elements + have been parsed, respectively. Their arguments are of type + <code>std::string</code> and contain the data extracted from XML.</p> + + <p>The last three functions are for connecting parsers to each other. + For example, there is a predefined parser for built-in XML Schema type + <code>string</code> in the XSD/e runtime. We will be using + it to parse the contents of <code>greeting</code> and + <code>name</code> elements, as shown in the next section.</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 XML documents. The first step is + to implement the parser: + </p> + + <pre class="c++"> +#include <iostream> +#include "hello-pskel.hxx" + +class hello_pimpl: public hello_pskel +{ +public: + virtual void + greeting (const std::string& g) + { + greeting_ = g; + } + + virtual void + name (const std::string& n) + { + std::cout << greeting_ << ", " << n << "!" << std::endl; + } + +private: + std::string greeting_; +}; + </pre> + + <p>We left both <code>pre()</code> and <code>post_hello()</code> with the + default implementations; we don't have anything to initialize or + return. The rest is pretty straightforward: we store the greeting + in a member variable and later, when parsing names, use it to + say hello.</p> + + <p>An observant reader my ask what happens if the <code>name</code> + element comes before <code>greeting</code>? Don't we need to + make sure <code>greeting_</code> was initialized and report + an error otherwise? The answer is no, we don't have to do + any of this. The <code>hello_pskel</code> parser skeleton + performs validation of XML according to the schema from which + it was generated. As a result, it will check the order + of the <code>greeting</code> and <code>name</code> elements + and report an error if it is violated.</p> + + <p>Now it is time to put this parser implementation to work:</p> + + <pre class="c++"> +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + // Construct the parser. + // + xml_schema::string_pimpl string_p; + hello_pimpl hello_p; + + hello_p.greeting_parser (string_p); + hello_p.name_parser (string_p); + + // Parse the XML instance. + // + xml_schema::document_pimpl doc_p (hello_p, "hello"); + + hello_p.pre (); + doc_p.parse (argv[1]); + hello_p.post_hello (); + } + 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 this code snippet instantiates individual parsers + and assembles them into a complete vocabulary parser. + <code>xml_schema::string_pimpl</code> is an implementation of a parser + for built-in XML Schema type <code>string</code>. It is provided by + the XSD/e runtime along with parsers for other built-in types (for + more information on the built-in parsers see <a href="#6">Chapter 6, + "Built-In XML Schema Type Parsers"</a>). We use <code>string_pimpl</code> + to parse the <code>greeting</code> and <code>name</code> elements as + indicated by the calls to <code>greeting_parser()</code> and + <code>name_parser()</code>. + </p> + + <p>Then we instantiate a document parser (<code>doc_p</code>). The + first argument to its constructor is the parser for + the root element (<code>hello_p</code> in our case). The + second argument is the root element name. + </p> + + <p>The final piece is the calls to <code>pre()</code>, <code>parse()</code>, + and <code>post_hello()</code>. The call to <code>parse()</code> + perform the actual XML parsing while the calls to <code>pre()</code> and + <code>post_hello()</code> make sure that the parser for the root + element can perform proper initialization and cleanup.</p> + + <p>While our parser implementation and test driver are pretty small and + easy to write by hand, for bigger XML vocabularies it can be a + substantial effort. To help with this task XSD/e can automatically + generate sample parser implementations and a test driver from your + schemas. You can request the generation of a sample implementation with + empty function bodies by specifying the <code>--generate-noop-impl</code> + option. Or you can generate a sample implementation that prints the + data store in XML by using the <code>--generate-print-impl</code> + option. To request the generation of a test driver you can use the + <code>--generate-test-driver</code> option. For more information + on these options refer to the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a>. The <code>'generated'</code> example + in the XSD/e distribution shows the sample implementation generation + feature in action.</p> + + + <h2><a name="2.4">2.4 Compiling and Running</a></h2> + + <p>After saving all the parts from the previous section in + <code>driver.cxx</code>, we are ready to compile our first + application 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-pskel.cxx +$ c++ -o driver driver.o hello-pskel.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. + We can also test the error handling. To test XML well-formedness + checking, we can try to parse <code>hello-pskel.hxx</code>:</p> + + <pre class="terminal"> +$ ./driver hello-pskel.hxx +hello-pskel.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> + + + <!-- Chapater 3 --> + + + <h1><a name="3">3 Parser Skeletons</a></h1> + + <p>As we have seen in the previous chapter, the XSD/e compiler generates + a parser skeleton class for each type defined in XML Schema. In + this chapter we will take a closer look at different functions + that comprise a parser skeleton as well as the way to connect + our implementations of these parser skeletons to create a complete + parser.</p> + + <p>In this and subsequent chapters we will use the following schema + that describes a collection of person records. We save it in + <code>people.xsd</code>:</p> + + <pre class="xml"> +<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:simpleType name="gender"> + <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="last-name" type="xs:string"/> + <xs:element name="gender" type="gender"/> + <xs:element name="age" type="xs:short"/> + </xs:sequence> + </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> + <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> +</people> + </pre> + + <p>Compiling <code>people.xsd</code> with the XSD/e compiler results + in three parser skeletons being generated: <code>gender_pskel</code>, + <code>person_pskel</code>, and <code>people_pskel</code>. We are going + to examine and implement each of them in the subsequent sections.</p> + + <h2><a name="3.1">3.1 Implementing the Gender Parser</a></h2> + + <p>The generated <code>gender_pskel</code> parser skeleton looks like + this:</p> + + <pre class="c++"> +class gender_pskel: public xml_schema::string_pskel +{ +public: + gender_pskel (xml_schema::string_pskel* base_impl); + + // Parser callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual void + post_gender (); +}; + </pre> + + <p>Notice that <code>gender_pskel</code> inherits from + <code>xml_schema::string_pskel</code> which is a parser skeleton + for built-in XML Schema type <code>string</code> and is + predefined in the XSD/e runtime library. This is an example + of the general rule that parser skeletons follow: if a type + in XML Schema inherits from another then there will be an + equivalent inheritance between the corresponding parser + skeleton classes. The <code>gender_pskel</code> class also + declares a constructor which expects a pointer to the base + parser skeleton. We will discuss the purpose of this + constructor shortly.</p> + + <p>The <code>pre()</code> and <code>post_gender()</code> callbacks + should look familiar from the previous chapter. Let's now + implement the parser. Our implementation will simply print + the gender to <code>cout</code>:</p> + + + <pre class="c++"> +class gender_pimpl: public gender_pskel +{ +public: + gender_pimpl () + : gender_pskel (&base_impl_) + { + } + + virtual void + post_gender () + { + std::string s = post_string (); + cout << "gender: " << s << endl; + } + +private: + xml_schema::string_pimpl base_impl_; +}; + </pre> + + <p>While the code is quite short, there is a lot going on. First, + notice that we define a member variable <code>base_impl_</code> + of type <code>xml_schema::string_pimpl</code> and then pass + it to the <code>gender_pskel</code>'s constructor. We have + encountered <code>xml_schema::string_pimpl</code> already; it is an + implementation of the <code>xml_schema::string_pskel</code> parser + skeleton for built-in XML Schema type <code>string</code>. By + passing <code>base_impl_</code> to the <code>gender_pskel</code>'s + constructor we provide an implementation for the part of the + parser skeleton that is inherited from <code>string_pskel</code>.</p> + + <p>This is another common theme in the C++/Parser programming model: + reusing implementations of the base parsers in the derived ones. + In our case, <code>string_pimpl</code> will do all the dirty work + of extracting the data and we can just get it at the end with the + call to <code>post_string()</code>. For more information on parser + implementation reuse refer to <a href="#5.6">Section 5.6, + "Parser Reuse"</a>.</p> + + <p>In case you are curious, here are the definitions for + <code>xml_schema::string_pskel</code> and + <code>xml_schema::string_pimpl</code>:</p> + + <pre class="c++"> +namespace xml_schema +{ + class string_pskel: public parser_simple_content + { + public: + virtual std::string + post_string () = 0; + }; + + class string_pimpl: public string_pskel + { + public: + virtual void + _pre (); + + virtual void + _characters (const xml_schema::ro_string&); + + virtual std::string + post_string (); + + protected: + std::string str_; + }; +} + </pre> + + <p>There are three new pieces in this code that we haven't seen yet. + Those are the <code>parser_simple_content</code> class and + the <code>_pre()</code> and <code>_characters()</code> functions. + The <code>parser_simple_content</code> class is defined in the XSD/e + runtime and is a base class for all parser skeletons that conform + to the simple content model in XML Schema. Types with the + simple content model cannot have nested elements—only text + and attributes. There is also the <code>parser_complex_content</code> + class which corresponds to the complex content mode (types with + nested elements, for example, <code>person</code> from + <code>people.xsd</code>).</p> + + <p>The <code>_pre()</code> function is a parser callback. Remember we + talked about the <code>pre()</code> and <code>post_*()</code> callbacks + in the previous chapter? There are actually two more callbacks + with similar roles: <code>_pre()</code> and <code>_post ()</code>. + As a result, each parser skeleton has four special callbacks:</p> + + <pre class="c++"> + virtual void + pre (); + + virtual void + _pre (); + + virtual void + _post (); + + virtual void + post_name (); + </pre> + + <p><code>pre()</code> and <code>_pre()</code> are initialization + callbacks. They get called in that order before a new instance of the type + is about to be parsed. The difference between <code>pre()</code> and + <code>_pre()</code> is conventional: <code>pre()</code> can + be completely overridden by a derived parser. The derived + parser can also override <code>_pre()</code> but has to always call + the original version. This allows you to partition initialization + into customizable and required parts.</p> + + <p>Similarly, <code>_post()</code> and <code>post_name()</code> are + finalization callbacks with exactly the same semantics: + <code>post_name()</code> can be completely overridden by the derived + parser while the original <code>_post()</code> should always be called. + </p> + + <p>The final bit we need to discuss in this section is the + <code>_characters()</code> function. As you might have guessed, it + is also a callback. A low-level one that delivers raw character content + for the type being parsed. You will seldom need to use this callback + directly. Using implementations for the built-in parsers provided by + the XSD/e runtime is usually a simpler and more convenient + alternative.</p> + + <p>At this point you might be wondering why some <code>post_*()</code> + callbacks, for example <code>post_string()</code>, return some data + while others, for example <code>post_gender()</code>, have + <code>void</code> as a return type. This is a valid concern + and it will be addressed in the next chapter.</p> + + <h2><a name="3.2">3.2 Implementing the Person Parser</a></h2> + + <p>The generated <code>person_pskel</code> parser skeleton looks like + this:</p> + + <pre class="c++"> +class person_pskel: public xml_schema::parser_complex_content +{ +public: + // Parser callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual void + first_name (const std::string&); + + virtual void + last_name (const std::string&); + + virtual void + gender (); + + virtual void + age (short); + + virtual void + post_person (); + + // Parser construction API. + // + void + first_name_parser (xml_schema::string_pskel&); + + void + last_name_parser (xml_schema::string_pskel&); + + void + gender_parser (gender_pskel&); + + void + age_parser (xml_schema::short_pskel&); + + void + parsers (xml_schema::string_pskel& /* first-name */, + xml_schema::string_pskel& /* last-name */, + gender_pskel& /* gender */, + xml_schema::short_pskel& /* age */); +}; + </pre> + + + <p>As you can see, we have a parser callback for each of the nested + elements found in the <code>person</code> XML Schema type. + The implementation of this parser is straightforward:</p> + + <pre class="c++"> +class person_pimpl: public person_pskel +{ +public: + virtual void + first_name (const std::string& n) + { + cout << "first: " << f << endl; + } + + virtual void + last_name (const std::string& l) + { + cout << "last: " << l << endl; + } + + virtual void + age (short a) + { + cout << "age: " << a << endl; + } +}; + </pre> + + <p>Notice that we didn't override the <code>gender()</code> callback + because all the printing is done by <code>gender_pimpl</code>.</p> + + <h2><a name="3.3">3.3 Implementing the People Parser</a></h2> + + <p>The generated <code>people_pskel</code> parser skeleton looks like + this:</p> + + <pre class="c++"> +class people_pskel: public xml_schema::parser_complex_content +{ +public: + // Parser callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual void + person (); + + virtual void + post_people (); + + // Parser construction API. + // + void + person_parser (person_pskel&); + + void + parsers (person_pskel& /* person */); +}; + </pre> + + <p>The <code>person()</code> callback will be called after parsing each + <code>person</code> element. While <code>person_pimpl</code> does + all the printing, one useful thing we can do in this callback is to + print an extra newline after each person record so that our + output is more readable:</p> + + <pre class="c++"> +class people_pimpl: public people_pskel +{ +public: + virtual void + person () + { + cout << endl; + } +}; + </pre> + + <p>Now it is time to put everything together.</p> + + + <h2><a name="3.4">3.4 Connecting the Parsers Together</a></h2> + + <p>At this point we have all the individual parsers implemented + and can proceed to assemble them into a complete parser + for our XML vocabulary. The first step is to instantiate + all the individual parsers that we will need:</p> + + <pre class="c++"> +xml_schema::short_pimpl short_p; +xml_schema::string_pimpl string_p; + +gender_pimpl gender_p; +person_pimpl person_p; +people_pimpl people_p; + </pre> + + <p>Notice that our schema uses two built-in XML Schema types: + <code>string</code> for the <code>first-name</code> and + <code>last-name</code> elements as well as <code>short</code> + for <code>age</code>. We will use predefined parsers that + come with the XSD/e runtime to handle these types. The next + step is to connect all the individual parsers. We do this + with the help of functions defined in the parser + skeletons and marked with the "Parser Construction API" + comment. One way to do it is to connect each individual + parser by calling the <code>*_parser()</code> functions:</p> + + <pre class="c++"> +person_p.first_name_parser (string_p); +person_p.last_name_parser (string_p); +person_p.gender_parser (gender_p); +person_p.age_parser (short_p); + +people_p.person_parser (person_p); + </pre> + + <p>You might be wondering what happens if you do not provide + a parser by not calling one of the <code>*_parser()</code> functions. + In that case the corresponding XML content will be skipped, + including validation. This is an efficient way to ignore parts + of the document that you are not interested in.</p> + + + <p>An alternative, shorter, way to connect the parsers is by using + the <code>parsers()</code> functions which connects all the parsers + for a given type at once:</p> + + <pre class="c++"> +person_p.parsers (string_p, string_p, gender_p, short_p); +people_p.parsers (person_p); + </pre> + + <p>The following figure illustrates the resulting connections. Notice + the correspondence between return types of the <code>post_*()</code> + functions and argument types of element callbacks that are connected + by the arrows.</p> + + <!-- align=center is needed for html2ps --> + <div class="img" align="center"><img src="figure-1.png"/></div> + + <p>The last step is the construction of the document parser and + invocation of the complete parser on our sample XML instance:</p> + + <pre class="c++"> +xml_schema::document_pimpl doc_p (people_p, "people"); + +people_p.pre (); +doc_p.parse ("people.xml"); +people_p.post_people (); + </pre> + + <p>Let's consider <code>xml_schema::document_pimpl</code> in + more detail. While the exact definition of this class + varies depending on the mapping configuration, here is + the part relevant to our example:</p> + + <pre class="c++"> +namespace xml_schema +{ + class document_pimpl + { + public: + document_pimpl (xml_schema::parser_base&, + const std::string& root_element_name); + + document_pimpl (xml_schema::parser_base&, + const std::string& root_element_namespace, + const std::string& root_element_name); + + void + parse (const std::string& file); + + void + parse (std::istream&); + + void + parse (const void* data, size_t size, bool last); + }; +} + </pre> + + <p><code>xml_schema::document_pimpl</code> is a root parser for + the vocabulary. The first argument to its constructors is the + parser for the type of the root element (<code>people_pimpl</code> + in our case). Because a type parser is only concerned with + the element's content and not with the element's name, we need + to specify the root element name somewhere. That's + what is passed as the second and third arguments to the + <code>document_pimpl</code>'s constructors.</p> + + <p>There are also three overloaded <code>parse()</code> function + defined in the <code>document_pimpl</code> class. The first version + parses a local file identified by a name. The second version + reads the data from an input stream. The last version allows + you to parse the data directly from a buffer, one chunk at a + time. You can call this function multiple times with the final + call having the <code>last</code> argument set to true. For more + information on the <code>xml_schema::document_pimpl</code> class + refer to <a href="#7">Chapter 7, "Document Parser and Error + Handling"</a>.</p> + + <p>Let's now consider a step-by-step list of actions that happen + as we parse through <code>people.xml</code>. The content of + <code>people.xml</code> is repeated below for convenience.</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> +</people> + </pre> + + + <ol class="steps"> + <li><code>people_p.pre()</code> is called from + <code>main()</code>. We did not provide any implementation + for this callback so this call is a no-op.</li> + + <li><code>doc_p.parse("people.xml")</code> is called from + <code>main()</code>. The parser opens the file and starts + parsing its content.</li> + + <li>The parser encounters the root element. <code>doc_p</code> + verifies that the root element is correct and calls + <code>_pre()</code> on <code>people_p</code> which is also + a no-op. Parsing is now delegated to <code>people_p</code>.</li> + + <li>The parser encounters the <code>person</code> element. + <code>people_p</code> determines that <code>person_p</code> + is responsible for parsing this element. <code>pre()</code> + and <code>_pre()</code> callbacks are called on <code>person_p</code>. + Parsing is now delegated to <code>person_p</code>.</li> + + <li>The parser encounters the <code>first-name</code> element. + <code>person_p</code> determines that <code>string_p</code> + is responsible for parsing this element. <code>pre()</code> + and <code>_pre()</code> callbacks are called on <code>string_p</code>. + Parsing is now delegated to <code>string_p</code>.</li> + + <li>The parser encounters character content consisting of + <code>"John"</code>. The <code>_characters()</code> callback is + called on <code>string_p</code>.</li> + + <li>The parser encounters the end of <code>first-name</code> + element. The <code>_post()</code> and <code>post_string()</code> + callbacks are called on <code>string_p</code>. The + <code>first_name()</code> callback is called on <code>person_p</code> + with the return value of <code>post_string()</code>. The + <code>first_name()</code> implementation prints + <code>"first: John"</code> to <code>cout</code>. + Parsing is now returned to <code>person_p</code>.</li> + + <li>Steps analogous to 5-7 are performed for the <code>last-name</code>, + <code>gender</code>, and <code>age</code> elements.</li> + + <li>The parser encounters the end of <code>person</code> + element. The <code>_post()</code> and <code>post_person()</code> + callbacks are called on <code>person_p</code>. The + <code>person()</code> callback is called on <code>people_p</code>. + The <code>person()</code> implementation prints a new line + to <code>cout</code>. Parsing is now returned to + <code>people_p</code>.</li> + + <li>Steps 4-9 are performed for the second <code>person</code> + element.</li> + + <li>The parser encounters the end of <code>people</code> + element. The <code>_post()</code> callback is called on + <code>people_p</code>. The <code>doc_p.parse("people.xml")</code> + call returns to <code>main()</code>.</li> + + <li><code>people_p.post_people()</code> is called from + <code>main()</code> which is a no-op.</li> + + </ol> + + + <!-- Chpater 4 --> + + + <h1><a name="4">4 Type Maps</a></h1> + + <p>There are many useful things you can do inside parser callbacks as they + are right now. There are, however, times when you want to propagate + some information from one parser to another or to the caller of the + parser. One common task that would greatly benefit from such a + possibility is building a tree-like in-memory object model of the + data stored in XML. During execution, each individual sub-parser + would create a sub-tree and return it to its <em>parent</em> parser + which can then incorporate this sub-tree into the whole tree.</p> + + <p>In this chapter we will discuss the mechanisms offered by the + C++/Parser mapping for returning information from individual + parsers and see how to use them to build an object model + of our people vocabulary.</p> + + <h2><a name="4.1">4.1 Object Model</a></h2> + + <p>An object model for our person record example could + look like this (saved in the <code>people.hxx</code> file):</p> + + <pre class="c++"> +#include <string> +#include <vector> + +enum gender +{ + male, + female +}; + +class person +{ +public: + person (const std::string& first, + const std::string& last, + ::gender gender, + short age) + : first_ (first), last_ (last), + gender_ (gender), age_ (age) + { + } + + const std::string& + first () const + { + return first_; + } + + const std::string& + last () const + { + return last_; + } + + ::gender + gender () const + { + return gender_; + } + + short + age () const + { + return age_; + } + +private: + std::string first_; + std::string last_; + ::gender gender_; + short age_; +}; + +typedef std::vector<person> people; + </pre> + + <p>While it is clear which parser is responsible for which part of + the object model, it is not exactly clear how, for + example, <code>gender_pimpl</code> will deliver <code>gender</code> + to <code>person_pimpl</code>. You might have noticed that + <code>string_pimpl</code> manages to deliver its value to the + <code>first_name()</code> callback of <code>person_pimpl</code>. Let's + see how we can utilize the same mechanism to propagate our + own data.</p> + + <p>There is a way to tell the XSD/e compiler that you want to + exchange data between parsers. More precisely, for each + type defined in XML Schema, you can tell the compiler two things. + First, the return type of the <code>post_*()</code> callback + in the parser skeleton generated for this type. And, second, + the argument type for callbacks corresponding to elements and + attributes of this type. For example, for XML Schema type + <code>gender</code> we can specify the return type for + <code>post_gender()</code> in the <code>gender_pskel</code> + skeleton and the argument type for the <code>gender()</code> callback + in the <code>person_pskel</code> skeleton. As you might have guessed, + the generated code will then pass the return value from the + <code>post_*()</code> callback as an argument to the element or + attribute callback.</p> + + <p>The way to tell the XSD/e compiler about these XML Schema to + C++ mappings is with type map files. Here is a simple type + map for the <code>gender</code> type from the previous paragraph.</p> + + <pre class="type-map"> +include "people.hxx"; +gender ::gender ::gender; + </pre> + + <p>The first line indicates that the generated code must include + <code>people.hxx</code> in order to get the definition for the + <code>gender</code> type. The second line specifies that both + argument and return types for the <code>gender</code> + XML Schema type should be the <code>::gender</code> C++ enum + (we use fully-qualified C++ names to avoid name clashes). + The next section will describe the type map format in detail. + We save this type map in <code>people.map</code> and + then translate our schemas with the <code>--type-map</code> + option to let the XSD/e compiler know about our type map:</p> + + <pre class="terminal"> +$ xsde cxx-parser --type-map people.map people.xsd + </pre> + + <p>If we now look at the generated <code>people-pskel.hxx</code>, + we will see the following changes in the <code>gender_pskel</code> and + <code>person_pskel</code> skeletons:</p> + + <pre class="c++"> +#include "people.hxx" + +class gender_pskel: public xml_schema::string_pskel +{ + virtual ::gender + post_gender () = 0; + + ... +}; + +class person_pskel: public xml_schema::parser_complex_content +{ + virtual void + gender (::gender); + + ... +}; + </pre> + + <p>Notice that <code>#include "people.hxx"</code> was added to + the generated header file from the type map to provide the + definition for the <code>gender</code> enum.</p> + + <h2><a name="4.2">4.2 Type Map File Format</a></h2> + + <p>Type map files are used to define a mapping between XML Schema + and C++ types. The compiler uses this information + to determine return types of <code>post_*()</code> + callbacks in parser skeletons corresponding to XML Schema + types as well as argument types for callbacks corresponding + to elements and attributes of these types.</p> + + <p>The compiler has a set of predefined mapping rules that map the + built-in XML Schema types to suitable C++ types (discussed + below) and all other types to <code>void</code>. + By providing your own type maps you can override these predefined + rules. The format of the type map file is presented below: + </p> + + <pre class="type-map"> +namespace <schema-namespace> [<cxx-namespace>] +{ + (include <file-name>;)* + ([type] <schema-type> <cxx-ret-type> [<cxx-arg-type>];)* +} + </pre> + + <p>Both <code><i><schema-namespace></i></code> and + <code><i><schema-type></i></code> are regex patterns while + <code><i><cxx-namespace></i></code>, + <code><i><cxx-ret-type></i></code>, and + <code><i><cxx-arg-type></i></code> are regex pattern + substitutions. All names can be optionally enclosed in + <code>" "</code>, for example, to include white-spaces.</p> + + <p><code><i><schema-namespace></i></code> determines XML + Schema namespace. Optional <code><i><cxx-namespace></i></code> + is prefixed to every C++ type name in this namespace declaration. + <code><i><cxx-ret-type></i></code> is a C++ type name that is + used as a return type for the <code>post_*()</code> callback. + Optional <code><i><cxx-arg-type></i></code> is an argument + type for callbacks corresponding to elements and attributes + of this type. If <code><i><cxx-arg-type></i></code> is not + specified, it defaults to <code><i><cxx-ret-type></i></code> + if <code><i><cxx-ret-type></i></code> ends with <code>*</code> or + <code>&</code> (that is, it is a pointer or a reference) and + <code>const <i><cxx-ret-type></i>&</code> + otherwise. + <code><i><file-name></i></code> is a file name either in the + <code>" "</code> or <code>< ></code> format + and is added with the <code>#include</code> directive to + the generated code.</p> + + <p>The <code><b>#</b></code> character starts a comment that ends + with a new line or end of file. To specify a name that contains + <code><b>#</b></code> enclose it in <code><b>" "</b></code>. + For example:</p> + + <pre> +namespace http://www.example.com/xmlns/my my +{ + include "my.hxx"; + + # Pass apples by value. + # + apple apple; + + # Pass oranges as pointers. + # + orange orange_t*; +} + </pre> + + <p>In the example above, for the + <code>http://www.example.com/xmlns/my#orange</code> + XML Schema type, the <code>my::orange_t*</code> C++ type will + be used as both return and argument types.</p> + + <p>Several namespace declarations can be specified in a single + file. The namespace declaration can also be completely + omitted to map types in a schema without a namespace. For + instance:</p> + + <pre class="type-map"> +include "my.hxx"; +apple apple; + +namespace http://www.example.com/xmlns/my +{ + orange "const orange_t*"; +} + </pre> + + <p>The compiler has a number of predefined mapping rules for + the built-in XML Schema types which can be presented as the + following map files:</p> + + <pre class="type-map"> +namespace http://www.w3.org/2001/XMLSchema +{ + boolean bool bool; + + byte "signed char" "signed char"; + unsignedByte "unsigned char" "unsigned char"; + + short short short; + unsignedShort "unsigned short" "unsigned short"; + + int int int; + unsignedInt "unsigned int" "unsigned int"; + + long "long long" "long long"; + unsignedLong "unsigned long long" "unsigned long long"; + + integer long long; + + negativeInteger long long; + nonPositiveInteger long long; + + positiveInteger "unsigned long" "unsigned long"; + nonNegativeInteger "unsigned long" "unsigned long"; + + float float float; + double double double; + decimal double double; + + NMTOKENS xml_schema::string_sequence*; + IDREFS xml_schema::string_sequence*; + + base64Binary xml_schema::buffer*; + hexBinary xml_schema::buffer*; + + date xml_schema::date; + dateTime xml_schema::date_time; + duration xml_schema::duration; + gDay xml_schema::gday; + gMonth xml_schema::gmonth; + gMonthDay xml_schema::gmonth_day; + gYear xml_schema::gyear; + gYearMonth xml_schema::gyear_month; + time xml_schema::time; +} + </pre> + + <p>If STL is enabled (<a href="#5.1">Section 5.1, "Standard Template + Library"</a>), the following mapping is used for the string-based + XML Schema built-in types:</p> + + <pre class="type-map"> +namespace http://www.w3.org/2001/XMLSchema +{ + include <string>; + + anySimpleType std::string; + + string std::string; + normalizedString std::string; + token std::string; + Name std::string; + NMTOKEN std::string; + NCName std::string; + ID std::string; + IDREF std::string; + language std::string; + anyURI std::string; + + QName xml_schema::qname; +} + </pre> + + <p>Otherwise, a C string-based mapping is used:</p> + + <pre class="type-map"> +namespace http://www.w3.org/2001/XMLSchema +{ + anySimpleType char*; + + string char*; + normalizedString char*; + token char*; + Name char*; + NMTOKEN char*; + NCName char*; + ID char*; + IDREF char*; + language char*; + anyURI char*; + + QName xml_schema::qname*; +} + </pre> + + <p>For more information about the mapping of the built-in XML Schema types + to C++ types refer to <a href="#6">Chapter 6, "Built-In XML Schema Type + Parsers"</a>. The last predefined rule maps anything that wasn't + mapped by previous rules to <code>void</code>:</p> + + <pre class="type-map"> +namespace .* +{ + .* void void; +} + </pre> + + + <p>When you provide your own type maps with the + <code>--type-map</code> option, they are evaluated first. This + allows you to selectively override any + of the predefined rules. Note also that if you change the mapping + of a built-in XML Schema type then it becomes your responsibility + to provide the corresponding parser skeleton and implementation + in the <code>xml_schema</code> namespace. You can include the + custom definitions into the generated header file using the + <code>--hxx-prologue-*</code> options.</p> + + <h2><a name="4.3">4.3 Parser Implementations</a></h2> + + <p>With the knowledge from the previous section, we can proceed + with creating a type map that maps types in the <code>people.xsd</code> + schema to our object model classes in + <code>people.hxx</code>. In fact, we already have the beginning + of our type map file in <code>people.map</code>. Let's extend + it with the rest of the types:</p> + + <pre class="type-map"> +include "people.hxx"; + +gender ::gender ::gender; +person ::person; +people ::people; + </pre> + + <p>A few things to note about this type map. We did not + provide the argument types for <code>person</code> and + <code>people</code> because the default constant reference is + exactly what we need. We also did not provide any mappings + for built-in XML Schema types <code>string</code> and + <code>short</code> because they are handled by the predefined + rules and we are happy with the result. Note also that + all C++ types are fully qualified. This is done to avoid + potential name conflicts in the generated code. Now we can + recompile our schema and move on to implementing the parsers:</p> + + <pre class="terminal"> +$ xsde cxx-parser --type-map people.map people.xsd + </pre> + + <p>Here is the implementation of our three parsers in full. One + way to save typing when implementing your own parsers is + to open the generated code and copy the signatures of parser + callbacks into your code. Or you could always auto generate the + sample implementations and fill them with your code.</p> + + <pre class="c++"> +#include "people-pskel.hxx" + +class gender_pimpl: public gender_pskel +{ +public: + gender_pimpl () + : gender_pskel (&base_impl_) + { + } + + virtual ::gender + post_gender () + { + return post_string () == "male" ? male : female; + } + +private: + xml_schema::string_pimpl base_impl_; +}; + +class person_pimpl: public person_pskel +{ +public: + virtual void + first_name (const std::string& f) + { + first_ = f; + } + + virtual void + last_name (const std::string& l) + { + last_ = l; + } + + virtual void + gender (::gender g) + { + gender_ = g; + } + + virtual void + age (short a) + { + age_ = a; + } + + virtual ::person + post_person () + { + return ::person (first_, last_, gender_, age_); + } + +private: + std::string first_; + std::string last_; + ::gender gender_; + short age_; +}; + +class people_pimpl: public people_pskel +{ +public: + virtual void + person (const ::person& p) + { + people_.push_back (p); + } + + virtual ::people + post_people () + { + ::people r; + r.swap (people_); + return r; + } + +private: + ::people people_; +}; + </pre> + + <p>This code fragment should look familiar by now. Just note that + all the <code>post_*()</code> callbacks now have return types instead + of <code>void</code>. Here is the implementation of the test + driver for this example:</p> + + <pre class="c++"> +#include <iostream> + +using namespace std; + +int +main (int argc, char* argv[]) +{ + // Construct the parser. + // + xml_schema::short_pimpl short_p; + xml_schema::string_pimpl string_p; + + gender_pimpl gender_p; + person_pimpl person_p; + people_pimpl people_p; + + person_p.parsers (string_p, string_p, gender_p, short_p); + people_p.parsers (person_p); + + // Parse the document to obtain the object model. + // + xml_schema::document_pimpl doc_p (people_p, "people"); + + people_p.pre (); + doc_p.parse (argv[1]); + people ppl = people_p.post_people (); + + // Print the object model. + // + for (people::iterator i (ppl.begin ()); i != ppl.end (); ++i) + { + cout << "first: " << i->first () << endl + << "last: " << i->last () << endl + << "gender: " << (i->gender () == male ? "male" : "female") << endl + << "age: " << i->age () << endl + << endl; + } +} + </pre> + + <p>The parser creation and assembly part is exactly the same as in + the previous chapter. The parsing part is a bit different: + <code>post_people()</code> now has a return value which is the + complete object model. We store it in the + <code>ppl</code> variable. The last bit of the code simply iterates + over the <code>people</code> vector and prints the information + for each person. We save the last two code fragments to + <code>driver.cxx</code> and proceed to compile and test + our new application:</p> + + + <pre class="terminal"> +$ c++ -I.../libxsde -c driver.cxx people-pskel.cxx +$ c++ -o driver driver.o people-pskel.o .../libxsde/xsde/libxsde.a +$ ./driver people.xml +first: John +last: Doe +gender: male +age: 32 + +first: Jane +last: Doe +gender: female +age: 28 + </pre> + + + <!-- Mapping Configuration --> + + + <h1><a name="5">5 Mapping Configuration</a></h1> + + <p>The Embedded C++/Parser 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, parser + implementation reuse styles, and support for XML Schema polymorphism. + Previous chapters assumed that the use of STL, iostream, C++ + exceptions, and XML Schema validation were enabled. + This chapter will discuss the changes in the Embedded C++/Parser + programming model that result from the changes to these configuration + parameters. A complete example that uses the minimal mapping + configuration is presented at the end of this chapter.</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 Embedded + C++/Parser mapping always delivers character data to the application + in the same 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 Embedded C++/Parser 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.</p> + + <h2><a name="5.1">5.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. When STL is disabled, all string-based + XML Schema types are mapped to C-style <code>char*</code> instead + of <code>std::string</code>, as described in + <a href="#4.2">Section 4.2, "Type Map File Format"</a>. The + following code fragment shows changes in the + signatures of <code>first_name()</code> and <code>last_name()</code> + callbacks from the person record example.</p> + + <pre class="c++"> +class person_pskel +{ +public: + virtual void + first_name (char*); + + virtual void + last_name (char*); + + ... +}; + </pre> + + <p>Note that it is your responsibility to eventually release the memory + associated with these strings using operator <code>delete[]</code>. + </p> + + <h2><a name="5.2">5.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, the + following two <code>parse()</code> functions in the + <code>xml_schema::document_pimpl</code> class become unavailable:</p> + + <pre class="c++"> + void + parse (const std::string& file); + + void + parse (std::istream&); + </pre> + + <p>Leaving you with only one function in the form:</p> + + <pre class="c++"> + void + parse (const void* data, size_t size, bool last); + </pre> + + <p>See <a href="#7.1">Section 7.1, "Document Parser"</a> + for more information on the semantics of these functions.</p> + + <h2><a name="5.3">5.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 are indicated with error codes instead of + exceptions, as described in <a href="#7.3">Section 7.3, + "Error Codes"</a>. + </p> + + <h2><a name="5.4">5.4 XML Schema Validation</a></h2> + + <p>To disable support for XML Schema validation, you will need to + configure the XSD/e runtime accordingly as well as pass + the <code>--suppress-validation</code> option to the XSD/e compiler + when translating your schemas. Disabling XML Schema validation + allows to further increase the parsing performance and + reduce footprint in cases where XML instances are known to be + valid. + </p> + + <h2><a name="5.5">5.5 64-bit Integer Type</a></h2> + + <p>By default the 64-bit <code>long</code> and <code>unsignedLong</code> + XML Schema built-in 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="5.6">5.6 Parser Reuse</a></h2> + + <p>When one type in XML Schema inherits from another, it is + often desirable to be able to reuse the parser implementation + corresponding to the base type in the parser implementation + corresponding to the derived type. XSD/e provides support + for two parser 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.</p> + + <p>The compiler can also be instructed not to generate any support + for parser reuse with the <code>--reuse-style-none</code> option. + This is mainly useful to further reduce the generated code size + when your vocabulary does not use inheritance or when you plan + to implement each parser from scratch. Note also that the + XSD/e runtime should be configured in accordance with the + parser reuse style used in the generated code. The remainder + of this section discusses the mixin and tiein parser reuse + styles in more detail.</p> + + + <p>To provide concrete examples for each reuse style we will use the + following schema fragment:</p> + + <pre class="xml"> +<xs:complexType name="person"> + <xs:sequence> + <xs:element name="first-name" type="xs:string"/> + <xs:element name="last-name" type="xs:string"/> + <xs:element name="age" type="xs:short"/> + </xs:sequence> +</xs:complexType> + +<xs:complexType name="emplyee"> + <complexContent> + <extension base="person"> + <xs:sequence> + <xs:element name="position" type="xs:string"/> + <xs:element name="salary" type="xs:unsignedLong"/> + </xs:sequence> + </extension> + </complexContent> +</xs:complexType> + </pre> + + <p>The mixin parser reuse style uses the C++ mixin idiom that + relies on multiple and virtual inheritance. Because + virtual inheritance can result in a significant object + code size increase, this reuse style should be considered + when such an overhead is acceptable and/or the vocabulary + consists of only a handful of types. When the mixin reuse + style is used, the generated parser skeletons use virtual + inheritance, for example:</p> + + <pre class="c++"> +class person_pskel: public virtual parser_complex_content +{ + ... +}; + +class employee_pskel: public virtual person_pskel +{ + ... +}; + </pre> + + + <p>When you implement the base parser you also need to use + virtual inheritance. The derived parser is implemented + by inheriting from both the derived parser skeleton and + the base parser implementation (that is, <em>mixing in</em> + the base parser implementation), for example:</p> + + <pre class="c++"> +class person_pimpl: public virtual person_pskel +{ + ... +}; + +class employee_pimpl: public employee_pskel, + public person_pimpl +{ + ... +}; + </pre> + + + <p>The tiein parser reuse style uses delegation and normally + results in a significantly smaller object code while being + almost as convenient to use as the mixin style. When the + tiein reuse style is used, the generated derived parser + skeleton declares a constructor which allows you to specify + the implementation of the base parser:</p> + + <pre class="c++"> +class person_pskel: public parser_complex_content +{ + ... +}; + +class employee_pskel: public person_pskel +{ +public: + employee_pskel (person_pskel* base_impl) + + ... +}; + </pre> + + <p>If you pass the implementation of the base parser to this + constructor then the generated code will transparently + forward all the callbacks corresponding to the base parser + skeleton to this implementation. You can also pass + <code>0</code> to this constructor in which case you will + need to implement the derived parser from scratch. The + following example shows how we could implement the + <code>person</code> and <code>employee</code> parsers + using the tiein style:</p> + + <pre class="c++"> +class person_pimpl: public person_pskel +{ + ... +}; + +class employee_pimpl: public employee_pskel +{ +public: + employee_pimpl () + : employee_pskel (&base_impl_) + { + } + + ... + +private: + person_pimpl base_impl_; +}; + </pre> + + <p>Note that you cannot use the <em>tied in</em> base parser + instance (<code>base_impl_</code> in the above code) for + parsing anything except the derived type.</p> + + <p>The ability to override the base parser callbacks in the + derived parser is also available in the tiein style. For + example, the following code fragment shows how we can + override the <code>age()</code> callback if we didn't + like the implementation provided by the base parser:</p> + + <pre class="c++"> +class employee_pimpl: public employee_pskel +{ +public: + employee_pimpl () + : employee_pskel (&base_impl_) + { + } + + virtual void + age (short a) + { + ... + } + + ... + +private: + person_pimpl base_impl_; +}; + </pre> + + <p>In the above example the <code>age</code> element will be + handled by <code>emplyee_pimpl</code> while the <code>first-name</code> + and <code>last-name</code> callbacks will still go to + <code>base_impl_</code>.</p> + + <p>It is also possible to inherit from the base parser implementation + instead of declaring it as a member variable. This can be useful + if you need to access protected members in the base implementation + or need to override a virtual function that is not part of + the parser skeleton interface. Note, however, that in this case + you will need to resolve a number of ambiguities with explicit + qualifications or using-declarations. For example:</p> + + + <pre class="c++"> +class person_pimpl: public person_pskel +{ + ... +protected: + virtual person* + create () + { + return new person (); + } +}; + +class employee_pimpl: public employee_pskel, + public person_pimpl +{ +public: + employee_pimpl () + : employee_pskel (static_cast<person_pimpl*> (this)) + { + } + + // Resolve ambiguities. + // + using emplyee_pskel::parsers; + + ... + +protected: + virtual employee* + create () + { + return new employee (); + } +}; + </pre> + + + <h2><a name="5.7">5.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>'s constructors. 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>When using the polymorphism-aware generated code, you can specify + several parsers for a single element by passing a parser map + instead of an individual parser to the parser connection function + for the element. One of the parsers will then be looked up and used + depending on the <code>xsi:type</code> attribute value or an element + name from a substitution group. 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>To print the data stored in such XML documents we can implement + the parsers as follows:</p> + + <pre class="c++"> +class person_pimpl: public person_pskel +{ +public: + virtual void + pre () + { + cout << "starting to parse person" << endl; + } + + virtual void + name (const std::string& v) + { + cout << "name: " << v << endl; + } + + virtual void + post_person () + { + cout << "finished parsing person" << endl; + } +}; + +class superman_pimpl: public superman_pskel +{ +public: + superman_pimpl () + : superman_pskel (&base_impl_) + { + } + + virtual void + pre () + { + cout << "starting to parse superman" << endl; + } + + virtual void + can_fly (bool v) + { + cout << "can-fly: " << v << endl; + } + + virtual void + post_person () + { + post_superman (); + } + + virtual void + post_superman () + { + cout << "finished parsing superman" << endl + } + +private: + person_pimpl base_impl_; +}; + +class batman_pimpl: public batman_pskel +{ +public: + batman_pimpl () + : batman_pskel (&base_impl_) + { + } + + virtual void + pre () + { + cout << "starting to parse batman" << endl; + } + + virtual void + wing_span (unsigned int v) + { + cout << "wing-span: " << v << endl; + } + + virtual void + post_person () + { + post_superman (); + } + + virtual void + post_superman () + { + post_batman (); + } + + virtual void + post_batman () + { + cout << "finished parsing batman" << endl; + } + +private: + superman_pimpl base_impl_; +}; + </pre> + + <p>Note that because the derived type parsers (<code>superman_pskel</code> + and <code>batman_pskel</code>) are called via the <code>person_pskel</code> + interface, we have to override the <code>post_person()</code> virtual + function in <code>superman_pimpl</code> and <code>batman_pimpl</code> + to call <code>post_superman()</code> and the <code>post_superman()</code> + virtual function in <code>batman_pimpl</code> to call + <code>post_batman()</code> (when the mixin parser reuse style is used + it is not necessary to override <code>post_person()</code> + in <code>batman_pimpl</code> since the suitable implementation + is inherited from <code>superman_pimpl</code>).</p> + + <p>The following code fragment shows how to connect the parsers together. + Notice that for the <code>person</code> element in the <code>supermen_p</code> + parser we specify a parser map instead of a specific parser and we pass + <code>true</code> as the last argument to the document parser constructor + to indicate that we are parsing potentially-polymorphic XML documents:</p> + + <pre class="c++"> +int +main (int argc, char* argv[]) +{ + // Construct the parser. + // + xml_schema::string_pimpl string_p; + xml_schema::boolean_pimpl boolean_p; + xml_schema::unsigned_int_pimpl unsigned_int_p; + + person_pimpl person_p; + superman_pimpl superman_p; + batman_pimpl batman_p; + + xml_schema::parser_map_impl person_map (5); // 5 hashtable buckets + supermen_pimpl supermen_p; + + person_p.parsers (string_p); + superman_p.parsers (string_p, boolean_p); + batman_p.parsers (string_p, boolean_p, unsigned_int_p); + + // Here we are specifying several parsers that can be used to + // parse the person element. + // + person_map.insert (person_p); + person_map.insert (superman_p); + person_map.insert (batman_p); + + supermen_p.person_parser (person_map); + + // Parse the XML document. The last argument to the document's + // constructor indicates that we are parsing polymorphic XML + // documents. + // + xml_schema::document_pimpl doc_p (supermen_p, "supermen", true); + + supermen_p.pre (); + doc_p.parse (argv[1]); + supermen_p.post_supermen (); +} + </pre> + + <p>When polymorphism-aware code is generated, each element's + <code>*_parser()</code> function is overloaded to also accept + an object of the <code>xml_schema::parser_map</code> type. + For example, the <code>supermen_pskel</code> class from the + above example looks like this:</p> + + <pre class="c++"> +class supermen_pskel: public xml_schema::parser_complex_content +{ +public: + + ... + + // Parser construction API. + // + void + parsers (person_pskel&); + + // Individual element parsers. + // + void + person_parser (person_pskel&); + + void + person_parser (xml_schema::parser_map&); + + ... +}; + </pre> + + <p>Note that you can specify both the individual (static) parser and + the parser map. The individual parser will be used when the static + element type and the dynamic type of the object being parsed are + the same. This is the case, for example, when there is no + <code>xsi:type</code> attribute and the element hasn't been + substituted. Because the individual parser for an element is + cached and no map lookup is necessary, it makes sense to specify + both the individual parser and the parser map when most of the + objects being parsed are of the static type and optimal + performance is important. The following code fragment shows + how to change the above example to set both the individual + parser and the parser map:</p> + + <pre class="c++"> +int +main (int argc, char* argv[]) +{ + ... + + // Here we are specifying several parsers that can be used to + // parse the person element. + // + person_map.insert (superman_p); + person_map.insert (batman_p); + + supermen_p.person_parser (person_p); + supermen_p.person_parser (person_map); + + ... +} + </pre> + + + <p>The <code>xml_schema::parser_map</code> interface and the + <code>xml_schema::parser_map_impl</code> default implementation + are presented below:</p> + + <pre class="c++"> +namespace xml_schema +{ + class parser_map + { + public: + virtual parser_base* + find (const char* type) const = 0; + + virtual void + reset () const = 0; + }; + + class parser_map_impl: public parser_map + { + public: + parser_map_impl (size_t buckets); + + void + insert (parser_base&); + + virtual parser_base* + find (const char* type) const; + + virtual void + reset () const; + + private: + parser_map_impl (const parser_map_impl&); + + parser_map_impl& + operator= (const parser_map_impl&); + + ... + }; +} + </pre> + + <p>The <code>type</code> argument in the <code>find()</code> virtual + function is the type name and namespace from the xsi:type attribute + (the namespace prefix is resolved to the actual XML namespace) + or the type of an element from the substitution group in the form + <code>"<name> <namespace>"</code> with the space and the + namespace part absent if the type does not have a namespace. + You can obtain a parser's dynamic type in the same format + using the <code>_dynamic_type()</code> function. The static + type can be obtained by calling the static <code>_static_type()</code> + function, for example <code>person_pskel::_static_type()</code>. + Both functions return a C string (<code>const char*</code>) which + is valid for as long as the application is running. The + <code>reset()</code> virtual function is used to reset + the parsers contained in the map (as opposed to resetting or + clearing the map itself). For more information on parser + resetting refer to <a href="#7.4">Section 7.4, "Reusing Parsers + after an Error"</a>. The following example shows how we can + implement our own parser map using <code>std::map</code>:</p> + + + <pre class="c++"> +#include <map> +#include <string> + +class parser_map: public xml_schema::parser_map +{ +public: + void + insert (xml_schema::parser_base& p) + { + map_[p._dynamic_type ()] = &p; + } + + virtual xml_schema::parser_base* + find (const char* type) const + { + map::const_iterator i = map_.find (type); + return i != map_.end () ? i->second : 0; + } + + virtual void + reset () const + { + for (map::const_iterator i (map_.begin ()), e (map_.end ()); + i != e; ++i) + { + xml_schema::parser_base* p = i->second; + p->_reset (); + } + } + +private: + typedef std::map<std::string, xml_schema::parser_base*> map; + map map_; +}; + </pre> + + <p>The XSD/e runtime provides the default implementation for the + <code>xml_schema::parser_map</code> interface, + <code>xml_schema::parser_map_impl</code>, which is a hashmap. + It requires that you specify the number of buckets it will contain + and it does not support automatic table resizing. To obtain good + performance the elements to buckets ratio should be between 0.7 and + 0.9. It is also recommended to use prime numbers for bucket counts: + 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, + 196613, 393241. + </p> + + <p>If C++ exceptions are disabled (<a href="#5.3">Section 5.3, + "C++ Exceptions"</a>), the <code>xml_schema::parser_map_impl</code> + class has the following additional error querying API. It can be used + to detect the out of memory errors after calls to the + <code>parser_map_impl</code>'s constructor and <code>insert()</code> + function.</p> + + <pre class="c++"> +namespace xml_schema +{ + class parser_map_impl: public parser_map + { + public: + enum error + { + error_none, + error_no_memory + }; + + error + _error () const; + + ... + }; +} + </pre> + + <p>To support polymorphic parsing the XSD/e runtime and generated code + maintain a number of hashmaps that contain substitution and, if + XML Schema validation is enabled (<a href="#5.4">Section 5.4, + "XML Schema Validation"</a>), inheritance information. Because + the number of elements in these hashmaps depends on the schemas + being compiled and thus is fairly static, these hashmaps do not + perform automatic table resizing and instead the number of buckets + is specified when the XSD/e runtime is configured. To obtain good + performance the elements to buckets ratio in these hashmaps should + be between 0.7 and 0.9. The recommended way to ensure this range + is to add diagnostics code to your application as shown in the + following example:</p> + + <pre class="c++"> +int +main () +{ + // Check that the load in substitution and inheritance hashmaps + // is not too high. + // +#ifndef NDEBUG + float load = xml_schema::parser_smap_elements (); + load /= xml_schema::parser_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_SMAP_BUCKETS" << endl; + } + + load = xml_schema::parser_imap_elements (); + load /= xml_schema::parser_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_IMAP_BUCKETS" << endl; + } +#endif + + ... +} + </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/parser/</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> + + <h2><a name="5.8">5.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> + + <h2><a name="5.9">5.9 A Minimal Example</a></h2> + + <p>The following example is a re-implementation of the person + records example presented in <a href="#3">Chapter 3, + "Parser Skeletons"</a>. It is intended to work + without STL, iostream, and C++ exceptions. It can be found in + the <code>examples/cxx/parser/minimal/</code> directory of the + XSD/e distribution. The <code>people.xsd</code> schema is + compiled with the <code>--no-stl</code>, <code>--no-iostream</code>, + and <code>--no-exceptions</code> options. The following listing + presents the implementation of parser skeletons and the test + driver in full.</p> + + <pre class="c++"> +#include <stdio.h> + +#include "people-pskel.hxx" + +class gender_pimpl: public gender_pskel +{ +public: + gender_pimpl () + : gender_pskel (&base_impl_) + { + } + + virtual void + post_gender () + { + char* s = post_string (); + printf ("gender: %s\n", s); + delete[] s; + } + +private: + xml_schema::string_pimpl base_impl_; +}; + +class person_pimpl: public person_pskel +{ +public: + virtual void + first_name (char* n) + { + printf ("first: %s\n", n); + delete[] n; + } + + virtual void + last_name (char* n) + { + printf ("last: %s\n", n); + delete[] n; + } + + virtual void + age (short a) + { + printf ("age: %hd\n", a); + } +}; + +class people_pimpl: public people_pskel +{ +public: + virtual void + person () + { + // Add an extra newline after each person record. + // + printf ("\n"); + } +}; + +int +main (int argc, char* argv[]) +{ + // Construct the parser. + // + xml_schema::short_pimpl short_p; + xml_schema::string_pimpl string_p; + + gender_pimpl gender_p; + person_pimpl person_p; + people_pimpl people_p; + + person_p.parsers (string_p, string_p, gender_p, short_p); + people_p.parsers (person_p); + + // Open the file. + // + FILE* f = fopen (argv[1], "rb"); + + if (f == 0) + { + fprintf (stderr, "%s: unable to open\n", argv[1]); + return 1; + } + + // Parse. + // + typedef xml_schema::parser_error error; + error e; + bool io_error = false; + + do + { + xml_schema::document_pimpl doc_p (people_p, "people"); + if (e = doc_p._error ()) + break; + + people_p.pre (); + if (e = people_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); + e = doc_p._error (); + + } while (!e && !feof (f)); + + if (io_error || e) + break; + + people_p.post_people (); + e = people_p._error (); + + } while (false); + + fclose (f); + + // Handle errors. + // + + if (io_error) + { + fprintf (stderr, "%s: read failure\n", argv[1]); + return 1; + } + + if (e) + { + switch (e.type ()) + { + case error::sys: + { + fprintf (stderr, "%s: %s\n", argv[1], e.sys_text ()); + break; + } + case error::xml: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + argv[1], e.line (), e.column (), e.xml_text ()); + break; + } + case error::schema: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + argv[1], e.line (), e.column (), e.schema_text ()); + break; + } + case error::app: + { + fprintf (stderr, "%s:%lu:%lu: application error %d\n", + argv[1], e.line (), e.column (), e.app_code ()); + break; + } + default: + break; + } + return 1; + } + return 0; +} + </pre> + + + <!-- Built-in XML Schema Type Parsers --> + + + <h1><a name="6">6 Built-In XML Schema Type Parsers</a></h1> + + <p>The XSD/e runtime provides parser implementations for all built-in + XML Schema types as summarized in the following table. Declarations + for these types are automatically included into each generated + header file. As a result you don't need to include any headers + to gain access to these parser implementations.</p> + + <!-- border="1" is necessary for html2ps --> + <table id="builtin" border="1"> + <tr> + <th>XML Schema type</th> + <th>Parser implementation in the <code>xml_schema</code> namespace</th> + <th>Parser return type</th> + </tr> + + <tr> + <th colspan="3">anyType and anySimpleType types</th> + </tr> + <tr> + <td><code>anyType</code></td> + <td><code>any_type_pimpl</code></td> + <td><code>void</code></td> + </tr> + <tr> + <td><code>anySimpleType</code></td> + <td><code>any_simple_type_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + + <tr> + <th colspan="3">fixed-length integral types</th> + </tr> + <!-- 8-bit --> + <tr> + <td><code>byte</code></td> + <td><code>byte_pimpl</code></td> + <td><code>signed char</code></td> + </tr> + <tr> + <td><code>unsignedByte</code></td> + <td><code>unsigned_byte_pimpl</code></td> + <td><code>unsigned char</code></td> + </tr> + + <!-- 16-bit --> + <tr> + <td><code>short</code></td> + <td><code>short_pimpl</code></td> + <td><code>short</code></td> + </tr> + <tr> + <td><code>unsignedShort</code></td> + <td><code>unsigned_short_pimpl</code></td> + <td><code>unsigned short</code></td> + </tr> + + <!-- 32-bit --> + <tr> + <td><code>int</code></td> + <td><code>int_pimpl</code></td> + <td><code>int</code></td> + </tr> + <tr> + <td><code>unsignedInt</code></td> + <td><code>unsigned_int_pimpl</code></td> + <td><code>unsigned int</code></td> + </tr> + + <!-- 64-bit --> + <tr> + <td><code>long</code></td> + <td><code>long_pimpl</code></td> + <td><code>long long</code> or <code>long</code><br/> + <a href="#5.5">Section 5.5, "64-bit Integer Type"</a></td> + </tr> + <tr> + <td><code>unsignedLong</code></td> + <td><code>unsigned_long_pimpl</code></td> + <td><code>unsigned long long</code> or + <code>unsigned long</code><br/> + <a href="#5.5">Section 5.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_pimpl</code></td> + <td><code>long</code></td> + </tr> + <tr> + <td><code>nonPositiveInteger</code></td> + <td><code>non_positive_integer_pimpl</code></td> + <td><code>long</code></td> + </tr> + <tr> + <td><code>nonNegativeInteger</code></td> + <td><code>non_negative_integer_pimpl</code></td> + <td><code>unsigned long</code></td> + </tr> + <tr> + <td><code>positiveInteger</code></td> + <td><code>positive_integer_pimpl</code></td> + <td><code>unsigned long</code></td> + </tr> + <tr> + <td><code>negativeInteger</code></td> + <td><code>negative_integer_pimpl</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_pimpl</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_pimpl</code></td> + <td><code>float</code></td> + </tr> + <tr> + <td><code>double</code></td> + <td><code>double_pimpl</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_pimpl</code></td> + <td><code>double</code></td> + </tr> + + <tr> + <th colspan="3">string-based types</th> + </tr> + <tr> + <td><code>string</code></td> + <td><code>string_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>normalizedString</code></td> + <td><code>normalized_string_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>token</code></td> + <td><code>token_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>Name</code></td> + <td><code>name_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>NMTOKEN</code></td> + <td><code>nmtoken_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>NCName</code></td> + <td><code>ncname_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + + <tr> + <td><code>language</code></td> + <td><code>language_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + + <tr> + <th colspan="3">qualified name</th> + </tr> + <tr> + <td><code>QName</code></td> + <td><code>qname_pimpl</code></td> + <td><code>xml_schema::qname</code> or <code>xml_schema::qname*</code><br/> + <a href="#6.1">Section 6.1, "<code>QName</code> Parser"</a></td> + </tr> + + <tr> + <th colspan="3">ID/IDREF types</th> + </tr> + <tr> + <td><code>ID</code></td> + <td><code>id_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + <tr> + <td><code>IDREF</code></td> + <td><code>idref_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.1, "Standard Template Library"</a></td> + </tr> + + <tr> + <th colspan="3">list types</th> + </tr> + <tr> + <td><code>NMTOKENS</code></td> + <td><code>nmtokens_pimpl</code></td> + <td><code>xml_schema::string_sequence*</code><br/><a href="#6.2">Section + 6.2, "<code>NMTOKENS</code> and <code>IDREFS</code> Parsers"</a></td> + </tr> + <tr> + <td><code>IDREFS</code></td> + <td><code>idrefs_pimpl</code></td> + <td><code>xml_schema::string_sequence*</code><br/><a href="#6.2">Section + 6.2, "<code>NMTOKENS</code> and <code>IDREFS</code> Parsers"</a></td> + </tr> + + <tr> + <th colspan="3">URI types</th> + </tr> + <tr> + <td><code>anyURI</code></td> + <td><code>uri_pimpl</code></td> + <td><code>std::string</code> or <code>char*</code><br/> + <a href="#5.1">Section 5.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_pimpl</code></td> + <td><code>xml_schema::buffer*</code><br/> + <a href="#6.3">Section 6.3, "<code>base64Binary</code> and + <code>hexBinary</code> Parsers"</a></td> + </tr> + <tr> + <td><code>hexBinary</code></td> + <td><code>hex_binary_pimpl</code></td> + <td><code>xml_schema::buffer*</code><br/> + <a href="#6.3">Section 6.3, "<code>base64Binary</code> and + <code>hexBinary</code> Parsers"</a></td> + </tr> + + <tr> + <th colspan="3">date/time types</th> + </tr> + <tr> + <td><code>date</code></td> + <td><code>date_pimpl</code></td> + <td><code>xml_schema::date</code><br/><a href="#6.5">Section 6.5, + "<code>date</code> Parser"</a></td> + </tr> + <tr> + <td><code>dateTime</code></td> + <td><code>date_time_pimpl</code></td> + <td><code>xml_schema::date_time</code><br/><a href="#6.6">Section 6.6, + "<code>dateTime</code> Parser"</a></td> + </tr> + <tr> + <td><code>duration</code></td> + <td><code>duration_pimpl</code></td> + <td><code>xml_schema::duration</code><br/><a href="#6.7">Section 6.7, + "<code>duration</code> Parser"</a></td> + </tr> + <tr> + <td><code>gDay</code></td> + <td><code>gday_pimpl</code></td> + <td><code>xml_schema::gday</code><br/><a href="#6.8">Section 6.8, + "<code>gDay</code> Parser"</a></td> + </tr> + <tr> + <td><code>gMonth</code></td> + <td><code>gmonth_pimpl</code></td> + <td><code>xml_schema::gmonth</code><br/><a href="#6.9">Section 6.9, + "<code>gMonth</code> Parser"</a></td> + </tr> + <tr> + <td><code>gMonthDay</code></td> + <td><code>gmonth_day_pimpl</code></td> + <td><code>xml_schema::gmonth_day</code><br/><a href="#6.10">Section 6.10, + "<code>gMonthDay</code> Parser"</a></td> + </tr> + <tr> + <td><code>gYear</code></td> + <td><code>gyear_pimpl</code></td> + <td><code>xml_schema::gyear</code><br/><a href="#6.11">Section 6.11, + "<code>gYear</code> Parser"</a></td> + </tr> + <tr> + <td><code>gYearMonth</code></td> + <td><code>gyear_month_pimpl</code></td> + <td><code>xml_schema::gyear_month</code><br/><a href="#6.12">Section + 6.12, "<code>gYearMonth</code> Parser"</a></td> + </tr> + <tr> + <td><code>time</code></td> + <td><code>time_pimpl</code></td> + <td><code>xml_schema::time</code><br/><a href="#6.13">Section 6.13, + "<code>time</code> Parser"</a></td> + </tr> + + </table> + + <h2><a name="6.1">6.1 <code>QName</code> Parser</a></h2> + + <p>The return type of the <code>qname_pimpl</code> parser implementation + is either <code>xml_schema::qname</code> when STL is enabled + (<a href="#5.1">Section 5.1, "Standard Template Library"</a>) or + <code>xml_schema::qname*</code> when STL is disabled. The + <code>qname</code> class represents an XML qualified name. When the + return type is <code>xml_schema::qname*</code>, the returned + object is dynamically allocated with operator <code>new</code> + and should eventually be deallocated with operator <code>delete</code>. + With STL enabled, 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 (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="#5.3">Section 5.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="6.2">6.2 <code>NMTOKENS</code> and <code>IDREFS</code> Parsers</a></h2> + + <p>The return type of the <code>nmtokens_pimpl</code> and + <code>idrefs_pimpl</code> parser implementations is + <code>xml_schema::string_sequence*</code>. + The returned object is dynamically allocated with operator + <code>new</code> and should eventually be deallocated with + operator <code>delete</code>. With STL and C++ exceptions enabled + (<a href="#5.1">Section 5.1, "Standard Template Library"</a>, + <a href="#5.3">Section 5.3, "C++ Exceptions"</a>), the + <code>string_sequence</code> type has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class string_sequence + { + public: + typedef std::string value_type; + typedef std::string* pointer; + typedef const std::string* const_pointer; + typedef std::string& reference; + typedef const std::string& const_reference; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef std::string* iterator; + typedef const std::string* const_iterator; + + public: + 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; + + std::string& + front (); + + const std::string& + front () const; + + std::string& + back (); + + const std::string& + back () const; + + std::string& + operator[] (size_t); + + const std::string& + 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 std::string&); + + iterator + insert (iterator, const std::string&); + + void + reserve (size_t); + }; + + bool + operator== (const string_sequence&, const string_sequence&); + + bool + operator!= (const string_sequence&, const string_sequence&); +} + </pre> + + <p>When STL is enabled and C++ exceptions are disabled, the signatures + of the <code>push_back()</code>, <code>insert()</code>, and + <code>reserve()</code> functions 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 (const std::string&); + + error + insert (iterator, const std::string&); + + error + insert (iterator, const std::string&, iterator& result); + + error + reserve (size_t); + }; +} + </pre> + + <p>When STL is disabled and C++ exceptions are enabled, the + <code>string_sequence</code> type has the following interface:</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); + + // Detach a string from the sequence at a given position. + // The string pointer at this position in the sequence is + // set to 0. + // + char* + detach (iterator); + }; + + bool + operator== (const string_sequence&, const string_sequence&); + + bool + operator!= (const string_sequence&, const string_sequence&); +} + </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 char[]</code> and will be deallocated + with operator <code>delete[]</code> by the <code>string_sequence</code> + object. These two functions free the passed object if the reallocation + of the underlying sequence buffer fails. The <code>push_back_copy()</code> + function makes a copy of the passed string. + If you detach the underlying element string, then it should + eventually be deallocated with operator <code>delete[]</code>.</p> + + <p>When both STL and 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 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="6.3">6.3 <code>base64Binary</code> and <code>hexBinary</code> Parsers</a></h2> + + <p>The return type of the <code>base64_binary_pimpl</code> and + <code>hex_binary_pimpl</code> parser implementations is + <code>xml_schema::buffer*</code>. The returned object is + dynamically allocated with operator <code>new</code> and + should eventually be deallocated with operator <code>delete</code>. + With C++ exceptions enabled (<a href="#5.3">Section 5.3, "C++ + Exceptions"</a>), the <code>buffer</code> type 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 + 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> type 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 + 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="6.4">6.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>xml_schema::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 <em>not specified</em> + state. If the time zone offset is negative then both hours and + minutes components are represented as negative integers.</p> + + <h2><a name="6.5">6.5 <code>date</code> Parser</a></h2> + + <p>The return type of the <code>date_pimpl</code> parser implementation + is <code>xml_schema::date</code> 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="#6.4">Section 6.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="6.6">6.6 <code>dateTime</code> Parser</a></h2> + + <p>The return type of the <code>date_time_pimpl</code> parser implementation + is <code>xml_schema::date_time</code> 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="#6.4">Section + 6.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="6.7">6.7 <code>duration</code> Parser</a></h2> + + <p>The return type of the <code>duration_pimpl</code> parser implementation + is <code>xml_schema::duration</code> 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="6.8">6.8 <code>gDay</code> Parser</a></h2> + + <p>The return type of the <code>gday_pimpl</code> parser implementation + is <code>xml_schema::gday</code> 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="#6.4">Section 6.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="6.9">6.9 <code>gMonth</code> Parser</a></h2> + + <p>The return type of the <code>gmonth_pimpl</code> parser implementation + is <code>xml_schema::gmonth</code> 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="#6.4">Section 6.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="6.10">6.10 <code>gMonthDay</code> Parser</a></h2> + + <p>The return type of the <code>gmonth_day_pimpl</code> parser implementation + is <code>xml_schema::gmonth_day</code> 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="#6.4">Section 6.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="6.11">6.11 <code>gYear</code> Parser</a></h2> + + <p>The return type of the <code>gyear_pimpl</code> parser implementation + is <code>xml_schema::gyear</code> 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="#6.4">Section 6.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="6.12">6.12 <code>gYearMonth</code> Parser</a></h2> + + <p>The return type of the <code>gyear_month_pimpl</code> parser implementation + is <code>xml_schema::gyear_month</code> 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="#6.4">Section 6.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="6.13">6.13 <code>time</code> Parser</a></h2> + + <p>The return type of the <code>time_pimpl</code> parser implementation + is <code>xml_schema::time</code> 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="#6.4">Section 6.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> + + + <!-- Error Handling --> + + + <h1><a name="7">7 Document Parser and Error Handling</a></h1> + + <p>In this chapter we will discuss the <code>xml_schema::document_pimpl</code> + type, the error handling mechanisms provided by the mapping, as well + as how to reuse a parser after an error has occurred.</p> + + <p>There are four categories of errors that can result from running + a parser on an XML instance: system, xml, schema, and application. + The system category contains memory allocation and file/stream + operation errors. The xml category is for XML parsing and + well-formedness checking errors. Similarly, the schema category is + for XML Schema validation errors. Finally, the application category + is for application logic errors that you may want to propagate + from parser implementations to the caller of the parser. + </p> + + <p>The C++/Parser mapping supports two methods of reporting errors: + using C++ exceptions and with error codes. The method used depends + on whether or not you have configured the XSD/e runtime and + the generated code with C++ exceptions enabled, as described + in <a href="#5.3">Section 5.3, "C++ Exceptions"</a>.</p> + + <h2><a name="7.1">7.1 Document Parser</a></h2> + + <p>The <code>xml_schema::document_pimpl</code> parser is a root parser for + the vocabulary. As mentioned in <a href="#3.4">Section 3.4, + "Connecting the Parsers Together"</a>, its interface varies depending + on the mapping configuration (<a href="#5">Chapter 5, "Mapping + Configuration"</a>). When STL and the iostream library are + enabled, the <code>xml_schema::document_pimpl</code> class has the + following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class parser_base; + + class document_pimpl + { + public: + document_pimpl (parser_base&, + const char* root_element_name); + + document_pimpl (parser_base&, + const char* root_element_namespace, + const char* root_element_name); + + document_pimpl (parser_base&, + const std::string& root_element_name); + + document_pimpl (parser_base&, + const std::string& root_element_namespace, + const std::string& root_element_name); + + + public: + // Parse a local file. The file is accessed with std::ifstream + // in binary mode. The std::ios_base::failure exception is used + // to report io errors (badbit and failbit) if exceptions are + // enabled. Otherwise error codes are used. + // + void + parse (const char* file); + + void + parse (const std::string& file); + + // Parse std::istream. std::ios_base::failure exception is used + // to report io errors (badbit and failbit) if exceptions are + // enabled. Otherwise error codes are used. + // + void + parse (std::istream&); + + // Parse a chunk of input. You can call this function multiple + // times with the last call having the last argument true. + // + void + parse (const void* data, size_t size, bool last); + + // Low-level Expat-specific parsing API. + // + void + parse_begin (XML_Parser); + + void + parse_end (); + }; +} + </pre> + + <p>When the use of STL is disabled, the constructors and the <code>parse()</code> + function that use <code>std::string</code> in their signatures + are not available. When the use of iostream is disabled, the + <code>parse()</code> functions that parse a local file and + <code>std::istream</code> are not available.</p> + + <p>When support for XML Schema polymorphism is enabled, the + overloaded <code>document_pimpl</code> constructors have + additional arguments which control polymorphic parsing. + For more information refer to <a href="#5.7">Section 5.7, + "Support for Polymorphism"</a>. + </p> + + <p>The first argument to all overloaded constructors is the + parser for the type of the root element. The <code>parser_base</code> + class is the base type for all parser skeletons. The second and + third arguments to the <code>document_pimpl</code>'s constructors are + the root element's name and namespace.</p> + + <p>The <code>parse_begin()</code> and <code>parse_end()</code> functions + present a low-level, Expat-specific parsing API for maximum control. + A typical use case would look like this (pseudo-code):</p> + + <pre class="c++"> +xxx_pimpl root_p; +document_pimpl doc_p (root_p, "root"); + +root_p.pre (); +doc_p.parse_begin (xml_parser); + +while (more_stuff_to_parse) +{ + // Call XML_Parse or XML_ParseBuffer: + // + if (XML_Parse (...) != XML_STATUS_ERROR) + break; +} + +doc_p.parse_end (); +result_type result (root_p.post_xxx ()); + </pre> + + <p>Note that if your vocabulary use XML namespaces, the + <code>XML_ParserCreateNS()</code> functions should be used to create + the XML parser. Space (<code>XML_Char (' ')</code>) should be used + as a separator (the second argument to <code>XML_ParserCreateNS()</code>). + Furthermore, if XML_Parse or XML_ParseBuffer fail, call + <code>parse_end()</code> to determine the error which is indicated + either via exception or set as an error code. + </p> + + <p>The error handling mechanisms employed by the <code>document_pimpl</code> + parser are described in <a href="#7.2">Section 7.2, "Exceptions"</a> + and <a href="#7.3">Section 7.3, "Error Codes"</a>.</p> + + <h2><a name="7.2">7.2 Exceptions</a></h2> + + <p>When C++ exceptions are used for error reporting, the system + errors are mapped to the standard exceptions. The out of memory + condition is indicated by throwing an instance + of <code>std::bad_alloc</code>. The stream operation errors + are reported by throwing an instance of + <code>std::ios_base::failure</code>.</p> + + <p>The xml and schema errors are reported by throwing the + <code>xml_schema::parser_xml</code> and <code>xml_schema::parser_schema</code> + exceptions, respectively. These two exceptions derive from + <code>xml_schema::parser_exception</code> which, in turn, derives + from <code>std::exception</code>. As a result, you can handle + any error from these two categories by either catching + <code>std::exception</code>, <code>xml_schema::parser_exception</code>, + or individual exceptions. The further down the hierarchy you go + the more detailed error information is available to you. The + following listing shows the definitions of these exceptions:</p> + + <pre class="c++"> +namespace xml_schema +{ + class parser_exception: public std::exception + { + public: + unsigned long + line () const; + + unsigned long + column () const; + + virtual const char* + text () const = 0; + + ... + }; + + std::ostream& + operator<< (std::ostream&, const parser_exception&); + + + typedef <implementation-details> parser_xml_error; + + class parser_xml: public parser_exception + { + public: + parser_xml_error + code () const; + + virtual const char* + text () const; + + virtual const char* + what () const throw (); + + ... + }; + + + typedef <implementation-details> parser_schema_error; + + class parser_schema: public parser_exception + { + public: + parser_schema_error + code () const; + + virtual const char* + text () const; + + virtual const char* + what () const throw (); + + ... + }; +} + </pre> + + <p>The <code>parser_xml_error</code> and <code>parser_schema_error</code> + are implementation-specific error code types. The + <code>operator<<</code> defined for the <code>parser_exception</code> + class simply prints the error description as returned by the + <code>text()</code> function. The following example shows + how we can catch these exceptions:</p> + + <pre class="c++"> +int +main (int argc, char* argv[]) +{ + try + { + // Parse argv[1]. + } + catch (const xml_schema::parser_exception& e) + { + cout << argv[1] << ":" << e.line () << ":" << e.column () + << ": error: " << e.text () << endl; + return 1; + } +} + </pre> + + <p>Finally, for reporting application errors from parsing callbacks, you + can throw any exceptions of your choice. They are propagated to + the caller of the parser without any alterations.</p> + + <h2><a name="7.3">7.3 Error Codes</a></h2> + + <p>When C++ exceptions are not available, error codes are used to + report error conditions. Each parser skeleton and the root + <code>document_pimpl</code> parser have the following member + function for querying + the error status:</p> + + <pre class="c++"> +xml_schema::parser_error +_error () const; + </pre> + + <p>To handle all possible error conditions, you will need to obtain + the error status after calls to: the <code>document_pimpl</code>'s + constructor (it performs memory allocations which may fail), the + root parser <code>pre()</code> callback, each call to the <code>parse()</code> + function, and, finally, the call to the root parser + <code>post_*()</code> callback. The definition of + <code>xml_schema::parser_error</code> class is presented below:</p> + + <pre class="c++"> +namespace xml_schema +{ + class sys_error + { + public: + enum value + { + none, + no_memory, + open_failed, + read_failed, + write_failed + }; + + sys_error (value); + + operator value () const; + + static const char* + text (value); + + ... + }; + + typedef <implementation-details> parser_xml_error; + typedef <implementation-details> parser_schema_error; + + class parser_error + { + public: + enum error_type + { + none, + sys, + xml, + schema, + app + }; + + error_type + type () const; + + // Line and column are only available for xml, schema, and + // app errors. + // + unsigned long + line () const; + + unsigned long + column () const; + + // Returns true if there is an error so that you can write + // if (p.error ()) or if (error e = p.error ()). + // + typedef void (error::*bool_convertible) (); + operator bool_convertible () const; + + // system + // + sys_error + sys_code () const; + + const char* + sys_text () const; + + // xml + // + parser_xml_error + xml_code () const; + + const char* + xml_text () const; + + // schema + // + parser_schema_error + schema_code () const; + + const char* + schema_text () const; + + // app + // + int + app_code () const; + + ... + }; +} + </pre> + + <p>The <code>parser_xml_error</code> and <code>parser_schema_error</code> + are implementation-specific error code types. The + <code>parser_error</code> class incorporates four categories of errors + which you can query by calling the <code>type()</code> function. + The following example shows how to handle error conditions with + error codes. It is based on the person record example presented + in <a href="#3">Chapter 3, "Parser Skeletons"</a>.</p> + + <pre class="c++"> +int +main (int argc, char* argv[]) +{ + // Construct the parser. + // + xml_schema::short_pimpl short_p; + xml_schema::string_pimpl string_p; + + gender_pimpl gender_p; + person_pimpl person_p; + people_pimpl people_p; + + person_p.parsers (string_p, string_p, gender_p, short_p); + people_p.parsers (person_p); + + // Parse. + // + using xml_schema::parser_error; + parser_error e; + + do + { + xml_schema::document_pimpl doc_p (people_p, "people"); + if (e = doc_p._error ()) + break; + + people_p.pre (); + if (e = people_p._error ()) + break; + + doc_p.parse (argv[1]); + if (e = doc_p._error ()) + break; + + people_p.post_people (); + e = people_p._error (); + + } while (false); + + // Handle errors. + // + if (e) + { + switch (e.type ()) + { + case parser_error::sys: + { + cerr << argv[1] << ": error: " << e.sys_text () << endl; + break; + } + case parser_error::xml: + { + cerr << argv[1] << ":" << e.line () << ":" << e.column () + << ": error: " << e.xml_text () << endl; + break; + } + case parser_error::schema: + { + cerr << argv[1] << ":" << e.line () << ":" << e.column () + << ": error: " << e.schema_text () << endl; + break; + } + case parser_error::app: + { + cerr << argv[1] << ":" << e.line () << ":" << e.column () + << ": application error " << e.app_code () << endl; + break; + } + } + return 1; + } +} + </pre> + + <p>The error type for application errors is <code>int</code> with + the value <code>0</code> indicated the absence of error. You can + set the application error by calling the <code>_app_error()</code> + function inside a parser callback. For example, if it was invalid to + have a person younger than 18 in our people catalog, then we could + have implemented this check as follows: </p> + + <pre class="c++"> +class person_pimpl: public person_pskel +{ +public: + virtual void + age (short a) + { + if (a < 18) + _app_error (1); + } + + ... +}; + </pre> + + <p>You can also set a system error by calling the <code>_sys_error()</code> + function inside a parser callback. This function has one argument of type + <code>xml_schema::sys_error</code> which was presented above. For + example:</p> + + <pre class="c++"> +class person_pimpl: public person_pskel +{ +public: + virtual void + pre () + { + p_ = new person (); + + if (p_ == 0) + _sys_error (xml_schema::sys_error::no_memory); + } + + ... + +private: + person* p_; +}; + </pre> + + + <h2><a name="7.4">7.4 Reusing Parsers after an Error</a></h2> + + <p>After a successful execution a parser returns into the initial + state and can be used to parse another document without any + extra actions. On the other hand, if an error occurred during + parsing and you would like to reuse the parser to parse another + document, you need to explicitly reset it into the initial + state as shown in the following code fragment:</p> + + <pre class="c++"> +int +main () +{ + ... + + std::vector<std::string> files = ... + + xml_schema::document_pimpl doc_p (people_p, "people"); + + for (size_t i = 0; i < files.size (); ++i) + { + try + { + people_p.pre (); + doc_p.parse (files[i]); + people_p.post_people (); + } + catch (const xml_schema::parser_exception&) + { + doc_p.reset (); + } + } +} + </pre> + + <p>If you do not need to reuse parsers after an error for example + because your application terminates or you create a new parser + instance in such situations, then you can avoid generating + parser reset code by specifying the <code>--suppress-reset</code> + XSD/e compiler option.</p> + + <p>Your individual parser implementations may also require extra + actions in order to bring them into a usable state after an + error. To accomplish this you can override the <code>_reset()</code> + virtual function as shown below. Notice that when you override the + <code>_reset()</code> function in your implementation, you should + always call the base skeleton version to allow it to reset + its state:</p> + +<pre class="c++"> +class person_pimpl: public person_pskel +{ +public: + virtual void + pre () + { + p_ = new person (); + } + + virtual void + _reset () + { + person_pskel::_reset (); + delete p_; + p_ = 0; + } + + ... + +private: + person* p_; +}; + </pre> + + <p>Note also that the <code>_reset()</code> mechanism is used only when + an error has occurred. To make sure that your parser implementations + arrive at the initial state during successful execution, use the + initialization (<code>pre()</code> and <code>_pre()</code>) and + finalization (<code>post_*()</code> and <code>_post()</code>) + callbacks.</p> + + <!-- Appendix A --> + + + <h1><a name="A">Appendix A — Supported XML Schema Constructs</a></h1> + + <p>The Embedded C++/Parser mapping supports validation of the following + W3C XML Schema constructs in the generated code.</p> + + <!-- border="1" is necessary for html2ps --> + <table id="features" border="1"> + <tr><th>Construct</th><th>Notes</th></tr> + <tr><th colspan="2">Structure</th></tr> + + <tr><td>element</td><td></td></tr> + <tr><td>attribute</td><td></td></tr> + + <tr><td>any</td><td></td></tr> + <tr><td>anyAttribute</td><td></td></tr> + + <tr><td>all</td><td></td></tr> + <tr><td>sequence</td><td></td></tr> + <tr><td>choice</td><td></td></tr> + + <tr><td>complex type, empty content</td><td></td></tr> + <tr><td>complex type, mixed content</td><td></td></tr> + <tr><td>complex type, simple content extension</td><td></td></tr> + <tr><td>complex type, simple content restriction</td><td></td></tr> + <tr><td>complex type, complex content extension</td><td></td></tr> + <tr><td>complex type, complex content restriction</td><td></td></tr> + + <tr><td>list</td><td></td></tr> + + <tr><th colspan="2">Facets</th></tr> + + <tr><td>length</td><td>String-based types.</td></tr> + <tr><td>minLength</td><td>String-based types.</td></tr> + <tr><td>maxLength</td><td>String-based types.</td></tr> + <tr><td>pattern</td><td>String-based types.</td></tr> + <tr><td>whiteSpace</td><td>String-based types.</td></tr> + <tr><td>enumeration</td><td>String-based types.</td></tr> + + <tr><td>minExclusive</td><td>Integer and floating-point types.</td></tr> + <tr><td>minInclusive</td><td>Integer and floating-point types.</td></tr> + <tr><td>maxExclusive</td><td>Integer and floating-point types.</td></tr> + <tr><td>maxInclusive</td><td>Integer and floating-point types.</td></tr> + + <tr><th colspan="2">Datatypes</th></tr> + + <tr><td>byte</td><td></td></tr> + <tr><td>unsignedByte</td><td></td></tr> + <tr><td>short</td><td></td></tr> + <tr><td>unsignedShort</td><td></td></tr> + <tr><td>int</td><td></td></tr> + <tr><td>unsignedInt</td><td></td></tr> + <tr><td>long</td><td></td></tr> + <tr><td>unsignedLong</td><td></td></tr> + <tr><td>integer</td><td></td></tr> + <tr><td>nonPositiveInteger</td><td></td></tr> + <tr><td>nonNegativeInteger</td><td></td></tr> + <tr><td>positiveInteger</td><td></td></tr> + <tr><td>negativeInteger</td><td></td></tr> + + <tr><td>boolean</td><td></td></tr> + + <tr><td>float</td><td></td></tr> + <tr><td>double</td><td></td></tr> + <tr><td>decimal</td><td></td></tr> + + <tr><td>string</td><td></td></tr> + <tr><td>normalizedString</td><td></td></tr> + <tr><td>token</td><td></td></tr> + <tr><td>Name</td><td></td></tr> + <tr><td>NMTOKEN</td><td></td></tr> + <tr><td>NCName</td><td></td></tr> + <tr><td>language</td><td></td></tr> + <tr><td>anyURI</td><td></td></tr> + + <tr><td>ID</td><td>Identity constraint is not enforced.</td></tr> + <tr><td>IDREF</td><td>Identity constraint is not enforced.</td></tr> + + <tr><td>NMTOKENS</td><td></td></tr> + <tr><td>IDREFS</td><td>Identity constraint is not enforced.</td></tr> + + <tr><td>QName</td><td></td></tr> + + <tr><td>base64Binary</td><td></td></tr> + <tr><td>hexBinary</td><td></td></tr> + + <tr><td>date</td><td></td></tr> + <tr><td>dateTime</td><td></td></tr> + <tr><td>duration</td><td></td></tr> + <tr><td>gDay</td><td></td></tr> + <tr><td>gMonth</td><td></td></tr> + <tr><td>gMonthDay</td><td></td></tr> + <tr><td>gYear</td><td></td></tr> + <tr><td>gYearMonth</td><td></td></tr> + <tr><td>time</td><td></td></tr> + </table> + + </div> +</div> + + +</body> +</html> diff --git a/doc/cxx/parser/guide/makefile b/doc/cxx/parser/guide/makefile new file mode 100644 index 0000000..48c37d9 --- /dev/null +++ b/doc/cxx/parser/guide/makefile @@ -0,0 +1,48 @@ +# file : doc/cxx/parser/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-parser-e-guide.ps \ + $(out_base)/cxx-parser-e-guide.pdf + + +$(out_base)/cxx-parser-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-parser-e-guide.pdf: $(out_base)/cxx-parser-e-guide.ps | $(out_base)/. + $(call message,ps2pdf $<,ps2pdf14 $< $@) + +# Dist. +# +$(dist): path := $(subst $(src_root)/,,$(src_base)) +$(dist): $(out_base)/cxx-parser-e-guide.ps $(out_base)/cxx-parser-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-parser-e-guide.ps,$(dist_prefix)/$(path)/cxx-parser-e-guide.ps) + $(call install-data,$(out_base)/cxx-parser-e-guide.pdf,$(dist_prefix)/$(path)/cxx-parser-e-guide.pdf) + +$(dist-win): $(dist) + + +# Clean +# +$(cleandoc): + $(call message,rm $$1,rm -f $$1,$(out_base)/cxx-parser-e-guide.ps) + $(call message,rm $$1,rm -f $$1,$(out_base)/cxx-parser-e-guide.pdf) + +# How to. +# +$(call include,$(bld_root)/install.make) diff --git a/doc/cxx/serializer/guide/figure-1.png b/doc/cxx/serializer/guide/figure-1.png Binary files differnew file mode 100644 index 0000000..8700758 --- /dev/null +++ b/doc/cxx/serializer/guide/figure-1.png diff --git a/doc/cxx/serializer/guide/figure-1.svg b/doc/cxx/serializer/guide/figure-1.svg new file mode 100644 index 0000000..68790f9 --- /dev/null +++ b/doc/cxx/serializer/guide/figure-1.svg @@ -0,0 +1,372 @@ +<?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://web.resource.org/cc/" + 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="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.45.1" + sodipodi:docbase="/home/boris/tmp" + sodipodi:docname="figure-1.svg" + inkscape:export-filename="/home/boris/tmp/figure-1.png" + inkscape:export-xdpi="76.195885" + inkscape:export-ydpi="76.195885" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Lend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Lend" + style="overflow:visible;"> + <path + id="path2934" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.8) rotate(180) translate(12.5,0)" /> + </marker> + <marker + inkscape:stockid="Dot_l" + orient="auto" + refY="0.0" + refX="0.0" + id="Dot_l" + style="overflow:visible"> + <path + id="path2875" + d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none" + transform="scale(0.8) translate(7.4, 1)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path2928" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <marker + inkscape:stockid="Dot_m" + orient="auto" + refY="0.0" + refX="0.0" + id="Dot_m" + style="overflow:visible"> + <path + id="path2872" + d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none" + transform="scale(0.4) translate(7.4, 1)" /> + </marker> + <marker + inkscape:stockid="Arrow1Lstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Lstart" + style="overflow:visible"> + <path + id="path2937" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.8) translate(12.5,0)" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow2Mend" + style="overflow:visible;"> + <path + id="path2910" + style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + transform="scale(0.6) rotate(180) translate(0,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="425.58704" + inkscape:cy="699.39127" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="1280" + inkscape:window-height="991" + inkscape:window-x="140" + inkscape:window-y="42" + showgrid="false" /> + <metadata + id="metadata7"> + <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"> + <g + id="g3902"> + <rect + y="194.64178" + x="24.142784" + height="106.2678" + width="149.70432" + id="rect1872" + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.29799986;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <text + sodipodi:linespacing="125%" + id="text3038" + y="219.99649" + x="28.284279" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;color:#000000;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:Monospace" + xml:space="preserve"><tspan + y="219.99649" + x="28.284279" + id="tspan3064" + sodipodi:role="line">class people_simpl</tspan><tspan + y="236.24649" + x="28.284279" + id="tspan3066" + sodipodi:role="line">{</tspan><tspan + y="252.49649" + x="28.284279" + id="tspan3068" + sodipodi:role="line"> void </tspan><tspan + y="268.74649" + x="28.284279" + id="tspan3070" + sodipodi:role="line"> person ();</tspan><tspan + y="284.99649" + x="28.284279" + id="tspan3072" + sodipodi:role="line">};</tspan></text> + </g> + <rect + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:8.33343506;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect5750" + width="149.4976" + height="246.47226" + x="264.03558" + y="124.53955" /> + <text + xml:space="preserve" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;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:Monospace" + x="269.5889" + y="148.27567" + id="text5752" + sodipodi:linespacing="100%"><tspan + sodipodi:role="line" + id="tspan5900" + x="269.5889" + y="148.27567">class person_simpl</tspan><tspan + sodipodi:role="line" + id="tspan5902" + x="269.5889" + y="161.27567">{</tspan><tspan + id="tspan2235" + sodipodi:role="line" + x="269.5889" + y="174.27567"> void</tspan><tspan + id="tspan2237" + sodipodi:role="line" + x="269.5889" + y="187.27567"> pre ();</tspan><tspan + id="tspan2239" + sodipodi:role="line" + x="269.5889" + y="200.27567" /><tspan + sodipodi:role="line" + id="tspan5904" + x="269.5889" + y="213.27567"> string</tspan><tspan + sodipodi:role="line" + id="tspan5906" + x="269.5889" + y="226.27567"> first_name ();</tspan><tspan + sodipodi:role="line" + id="tspan5908" + x="269.5889" + y="239.27567" /><tspan + sodipodi:role="line" + id="tspan5910" + x="269.5889" + y="252.27567"> string</tspan><tspan + sodipodi:role="line" + id="tspan5912" + x="269.5889" + y="265.27567"> last_name ();</tspan><tspan + sodipodi:role="line" + id="tspan5914" + x="269.5889" + y="278.27567" /><tspan + sodipodi:role="line" + id="tspan5916" + x="269.5889" + y="291.27567"> void</tspan><tspan + sodipodi:role="line" + id="tspan5918" + x="269.5889" + y="304.27567"> gender ();</tspan><tspan + sodipodi:role="line" + id="tspan5920" + x="269.5889" + y="317.27567" /><tspan + sodipodi:role="line" + id="tspan5922" + x="269.5889" + y="330.27567"> short</tspan><tspan + sodipodi:role="line" + id="tspan5930" + x="269.5889" + y="343.27567"> age ();</tspan><tspan + sodipodi:role="line" + id="tspan5932" + x="269.5889" + y="356.27567">};</tspan></text> + <g + id="g3845"> + <rect + y="77.741814" + x="506.28357" + height="99.610825" + width="151.1286" + id="rect5955" + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.69227886;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <flowRoot + transform="translate(-5.050762,12.10153)" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + id="flowRoot5957" + xml:space="preserve"><flowRegion + id="flowRegion5959"><rect + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + y="74.534515" + x="516.18793" + height="88.893425" + width="143.44167" + id="rect5961" /></flowRegion><flowPara + id="flowPara5965">class string_simpl</flowPara><flowPara + id="flowPara5967">{</flowPara><flowPara + id="flowPara5969"> void</flowPara><flowPara + id="flowPara5971"> pre (string);</flowPara><flowPara + id="flowPara5973">};</flowPara><flowPara + id="flowPara5975" /></flowRoot> </g> + <g + id="g3857"> + <rect + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.69227886;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect5977" + width="151.1286" + height="99.610825" + x="506.28357" + y="316.15808" /> + <flowRoot + xml:space="preserve" + id="flowRoot5979" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + transform="translate(-5.050761,250.5178)" + inkscape:export-filename="/tmp/figure-1.png" + inkscape:export-xdpi="546.53815" + inkscape:export-ydpi="546.53815"><flowRegion + id="flowRegion5981"><rect + id="rect5983" + width="143.44167" + height="88.893425" + x="516.18793" + y="74.534515" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" /></flowRegion><flowPara + id="flowPara5985">class short_simpl</flowPara><flowPara + id="flowPara5987">{</flowPara><flowPara + id="flowPara5989"> void</flowPara><flowPara + id="flowPara5991"> pre (short);</flowPara><flowPara + id="flowPara5993">};</flowPara><flowPara + id="flowPara5995" /></flowRoot> </g> + <g + id="g3869"> + <rect + style="fill:#c5ddf8;fill-opacity:1;fill-rule:evenodd;stroke:#c5ddf8;stroke-width:5.69227886;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect6023" + width="151.1286" + height="99.610825" + x="505.7785" + y="196.93977" /> + <flowRoot + xml:space="preserve" + id="flowRoot6025" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" + transform="translate(-5.555838,129.2792)"><flowRegion + id="flowRegion6027"><rect + id="rect6029" + width="143.44167" + height="88.893425" + x="516.18793" + y="74.534515" + style="font-size:13px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace" /></flowRegion><flowPara + id="flowPara6031">class gender_simpl</flowPara><flowPara + id="flowPara6033">{</flowPara><flowPara + id="flowPara6035"> void</flowPara><flowPara + id="flowPara6037"> pre ();</flowPara><flowPara + id="flowPara6039">};</flowPara><flowPara + id="flowPara6041" /></flowRoot> </g> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" + d="M 129.28571,265.21932 L 214.28572,264.86218 L 215,185.3979 L 277.85714,184.50504" + id="path2267" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);marker-mid:none;marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" + d="M 400,222.36218 L 461.07144,222.36217 L 460.89286,143.79075 L 520.71429,143.79075" + id="path3240" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" + d="M 370,301.64789 L 481.78571,301.29075 L 481.60714,262.8979 L 520,262.36218" + id="path3242" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);marker-end:url(#Arrow1Lend);stroke-opacity:1;display:inline" + d="M 345.71429,340.93361 L 461.07143,341.29075 L 461.25,383.25504 L 520.71429,383.07647" + id="path3244" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Dot_l);stroke-opacity:1;display:inline" + d="M 393.57143,261.64789 L 461.19314,261.78285 L 461.13464,222.52186" + id="path3250" + inkscape:connector-type="polyline" + sodipodi:nodetypes="ccc" /> + </g> +</svg> diff --git a/doc/cxx/serializer/guide/guide.html2ps b/doc/cxx/serializer/guide/guide.html2ps new file mode 100644 index 0000000..9e5fc78 --- /dev/null +++ b/doc/cxx/serializer/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++/Serializer 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/serializer/guide/index.xhtml'>XHTML</a>, + <a href='http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/cxx-serializer-e-guide.pdf'>PDF</a>, and + <a href='http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/cxx-serializer-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/serializer/guide/index.xhtml b/doc/cxx/serializer/guide/index.xhtml new file mode 100644 index 0000000..34ddbe1 --- /dev/null +++ b/doc/cxx/serializer/guide/index.xhtml @@ -0,0 +1,6542 @@ +<?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++/Serializer 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,serialize,create,write,validation,embedded,mobile"/> + <meta name="description" content="Embedded C++/Serializer Mapping Getting Started Guide"/> + + <link rel="stylesheet" type="text/css" href="../../../default.css" /> + +<style type="text/css"> + pre { + padding : 0 0 0 0em; + margin : 0em 0em 0em 0; + + font-size : 102% + } + + body { + min-width: 48em; + } + + h1 { + font-weight: bold; + font-size: 200%; + line-height: 1.2em; + } + + h2 { + font-weight : bold; + font-size : 150%; + + padding-top : 0.8em; + } + + h3 { + font-size : 140%; + padding-top : 0.8em; + } + + /* Adjust indentation for three levels. */ + #container { + max-width: 48em; + } + + #content { + padding: 0 0.1em 0 4em; + /*background-color: red;*/ + } + + #content h1 { + margin-left: -2.06em; + } + + #content h2 { + margin-left: -1.33em; + } + + /* Title page */ + + #titlepage { + padding: 2em 0 1em 0; + border-bottom: 1px solid black; + } + + #titlepage .title { + font-weight: bold; + font-size: 200%; + text-align: center; + } + + #titlepage #first-title { + padding: 1em 0 0.4em 0; + } + + #titlepage #second-title { + padding: 0.4em 0 2em 0; + } + + /* Lists */ + ul.list li { + padding-top : 0.3em; + padding-bottom : 0.3em; + } + + ol.steps { + padding-left : 1.8em; + } + + ol.steps 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; + } + + /* XML Schema features table. */ + #features { + margin: 2em 0 2em 0; + + border-collapse : collapse; + border : 1px solid; + border-color : #000000; + + font-size : 11px; + line-height : 14px; + } + + #features th, #features td { + border: 1px solid; + padding : 0.6em 0.6em 0.6em 0.6em; + } + + #features th { + background : #cde8f6; + } + + #features 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++/Serializer 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/serializer/guide/index.xhtml">XHTML</a>, + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/cxx-serializer-e-guide.pdf">PDF</a>, and + <a href="http://www.codesynthesis.com/projects/xsde/documentation/cxx/serializer/guide/cxx-serializer-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 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> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">Serializer Skeletons</a> + <table class="toc"> + <tr><th>3.1</th><td><a href="#3.1">Implementing the Gender Serializer</a></td></tr> + <tr><th>3.2</th><td><a href="#3.2">Implementing the Person Serializer</a></td></tr> + <tr><th>3.3</th><td><a href="#3.3">Implementing the People Serializer</a></td></tr> + <tr><th>3.4</th><td><a href="#3.4">Connecting the Serializers Together</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>4</th><td><a href="#4">Type Maps</a> + <table class="toc"> + <tr><th>4.1</th><td><a href="#4.1">Object Model</a></td></tr> + <tr><th>4.2</th><td><a href="#4.2">Type Map File Format</a></td></tr> + <tr><th>4.3</th><td><a href="#4.3">Serializer Implementations</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>5</th><td><a href="#5">Serializer Callbacks</a> + <table class="toc"> + <tr><th>5.1</th><td><a href="#5.1">Optional Callback</a></td></tr> + <tr><th>5.2</th><td><a href="#5.2">Sequence Callback</a></td></tr> + <tr><th>5.3</th><td><a href="#5.3">Choice Callback</a></td></tr> + <tr><th>5.4</th><td><a href="#5.4">Element Wildcard Callbacks</a></td></tr> + <tr><th>5.5</th><td><a href="#5.5">Attribute Wildcard Callbacks</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>6</th><td><a href="#6">Mapping Configuration</a> + <table class="toc"> + <tr><th>6.1</th><td><a href="#6.1">Standard Template Library</a></td></tr> + <tr><th>6.2</th><td><a href="#6.2">Input/Output Stream Library</a></td></tr> + <tr><th>6.3</th><td><a href="#6.3">C++ Exceptions</a></td></tr> + <tr><th>6.4</th><td><a href="#6.4">XML Schema Validation</a></td></tr> + <tr><th>6.5</th><td><a href="#6.5">64-bit Integer Type</a></td></tr> + <tr><th>6.6</th><td><a href="#6.6">Serializer Reuse</a></td></tr> + <tr><th>6.7</th><td><a href="#6.7">Support for Polymorphism</a></td></tr> + <tr><th>6.8</th><td><a href="#6.8">Custom Allocators</a></td></tr> + <tr><th>6.9</th><td><a href="#6.9">A Minimal Example</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>7</th><td><a href="#7">Built-In XML Schema Type Serializers</a> + <table class="toc"> + <tr><th>7.1</th><td><a href="#7.1">Floating-Point Type Serializers</a></td></tr> + <tr><th>7.2</th><td><a href="#7.2">String-Based Type Serializers</a></td></tr> + <tr><th>7.3</th><td><a href="#7.3"><code>QName</code> Serializer</a></td></tr> + <tr><th>7.4</th><td><a href="#7.4"><code>NMTOKENS</code> and <code>IDREFS</code> Serializers</a></td></tr> + <tr><th>7.5</th><td><a href="#7.5"><code>base64Binary</code> and <code>hexBinary</code> Serializers</a></td></tr> + <tr><th>7.6</th><td><a href="#7.6">Time Zone Representation</a></td></tr> + <tr><th>7.7</th><td><a href="#7.7"><code>date</code> Serializer</a></td></tr> + <tr><th>7.8</th><td><a href="#7.8"><code>dateTime</code> Serializer</a></td></tr> + <tr><th>7.9</th><td><a href="#7.9"><code>duration</code> Serializer</a></td></tr> + <tr><th>7.10</th><td><a href="#7.10"><code>gDay</code> Serializer</a></td></tr> + <tr><th>7.11</th><td><a href="#7.11"><code>gMonth</code> Serializer</a></td></tr> + <tr><th>7.12</th><td><a href="#7.12"><code>gMonthDay</code> Serializer</a></td></tr> + <tr><th>7.13</th><td><a href="#7.13"><code>gYear</code> Serializer</a></td></tr> + <tr><th>7.14</th><td><a href="#7.14"><code>gYearMonth</code> Serializer</a></td></tr> + <tr><th>7.15</th><td><a href="#7.15"><code>time</code> Serializer</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>8</th><td><a href="#8">Document Serializer and Error Handling</a> + <table class="toc"> + <tr><th>8.1</th><td><a href="#8.1">Document Serializer</a></td></tr> + <tr><th>8.2</th><td><a href="#8.2">Exceptions</a></td></tr> + <tr><th>8.3</th><td><a href="#8.3">Error Codes</a></td></tr> + <tr><th>8.4</th><td><a href="#8.4">Reusing Serializers after an Error</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th></th><td><a href="#A">Appendix A — Supported XML Schema Constructs</a></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++/Serializer 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>The <code>INSTALL</code> file in the XSD/e distribution provides + build instructions for various platforms.</li> + + <li>The <code>examples/cxx/serializer/</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++/Serializer 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++/Serializer mapping. + XSD/e is a dependency-free W3C XML Schema to C++ compiler for mobile, + embedded, and light-weight applications. Embedded C++/Serializer is an + XML Schema to C++ mapping that represents an XML vocabulary as a set of + serializer skeletons which you can implement to perform XML serialization + as required by your application logic. + </p> + + <h2><a name="1.1">1.1 Mapping Overview</a></h2> + + <p>The Embedded C++/Serializer mapping provides event-driven, + stream-oriented XML serialization, XML Schema validation, + and C++ data binding. It 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 serializers are 2-10 + times faster than general-purpose validating XML serializers + while at the same time maintaining extremely low static and + dynamic memory footprints. For example, a validating serializer + executable can be as small as 60KB in size. The size can be + further reduced by disabling support for 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 C++ templates.</p> + + <p>To speed up application development, the C++/Serializer mapping + can be instructed to generate sample serializer implementations + and a test driver which can then be filled with the application + logic code. The mapping also provides a wide range of + mechanisms for controlling and customizing the generated code.</p> + + <p>The next chapter shows how to create a simple application + that uses the Embedded C++/Serializer mapping to validate + and serialize simple data to an XML document. The following + chapters describe the Embedded C++/Serializer mapping in more + detail.</p> + + <h2><a name="1.2">1.2 Benefits</a></h2> + + <p>Traditional XML serialization APIs such as Document Object Model (DOM) + or XML Writer 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>Text-based representation results in inefficient use of + resources.</li> + + <li>Extra validation code that is not used by the application.</li> + + <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 produced by the application logic to the text + encoding used in XML.</li> + + <li>Resulting applications are hard to debug, change, and + maintain.</li> + </ul> + + <p>In contrast, statically-typed, vocabulary-specific serializer + skeletons produced by the Embedded C++/Serializer mapping use + native data types (for example, integers are passed as + integers, not as text) and include validation code 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, the serializer skeletons allow you to operate in your + domain terms instead of the generic elements, attributes, and + text. Automatic code generation frees you for more + interesting tasks (such as doing something useful with the + information that needs to be stored in XML) and + minimizes the effort needed to adapt your applications to changes + in the document structure. To summarize, the C++/Serializer mapping + has the following key advantages over generic XML serialization APIs:</p> + + <ul class="list"> + <li><b>Ease of use.</b> The generated code hides all the complexity + associated with recreating the document structure, maintaining the + state, and converting the data from types suitable for + manipulation by the application logic to the text representation + used in XML.</li> + + <li><b>Natural representation.</b> The generated serializer skeletons + implement serializer callbacks as virtual functions with names + corresponding to elements and attributes in XML. As a result, + you serialize the data using your domain vocabulary instead + of generic elements, attributes, and text. + </li> + + <li><b>Concise code.</b> With a separate serializer skeleton for each + XML Schema type, the application implementation is simpler + and thus easier to read and understand.</li> + + <li><b>Safety.</b> The data is passed by serializer callbacks as + statically typed objects. The serializer callbacks themselves + are virtual functions. 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 application code that need to be + changed.</li> + + <li><b>Efficiency.</b> The generated serializer skeletons use native + data types and combine validation and data-to-text + conversion in a single step. This makes them much more efficient + than traditional architectures with separate stages for validation + and data conversion.</li> + </ul> + + + <!-- Hello World Example --> + + + <h1><a name="2">2 Hello World Example</a></h1> + + <p>In this chapter we will examine how to create a very simple XML + document using the XSD/e-generated C++/Serializer skeletons. + + All the code presented in this chapter is based on the <code>hello</code> + example which can be found in the <code>examples/cxx/serializer/</code> + directory of the XSD/e distribution.</p> + + <h2><a name="2.1">2.1 Writing Schema</a></h2> + + <p>First, we need to get an idea about the structure of the XML + document that we are going to create. The sample XML that + we will try to produce with our Hello application looks like + this:</p> + + <pre class="xml"> +<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"> +<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 the XML Schema language, it + should be easy to connect declarations in <code>hello.xsd</code> + to elements in the sample XML document above. 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 vocabulary; it tells + everybody what valid XML instances of our vocabulary should look + like. The next step is to compile this schema to generate C++ + serializer skeletons.</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++ + serializer skeletons. To do this we invoke the XSD/e compiler + from a terminal (UNIX) or a command prompt (Windows): + </p> + + <pre class="terminal"> +$ xsde cxx-serializer hello.xsd + </pre> + + <p>The XSD/e compiler produces two C++ files: <code>hello-sskel.hxx</code> + and <code>hello-sskel.cxx</code>. The following code fragment is taken + from <code>hello-sskel.hxx</code>; it should give you an idea about what + gets generated: + </p> + +<pre class="c++"> +class hello_sskel +{ +public: + // Serializer callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual std::string + greeting () = 0; + + virtual bool + name_next () = 0; + + virtual std::string + name () = 0; + + virtual void + post (); + + // Serializer construction API. + // + void + greeting_serializer (xml_schema::string_sskel&); + + void + name_serializer (xml_schema::string_sskel&); + + void + serializers (xml_schema::string_sskel& /* greeting */, + xml_schema::string_sskel& /* name */); + +private: + ... +}; + </pre> + + <p>The first five member functions shown above are called serializer + callbacks. You would normally override them in your implementation + of the serializer. Let's go through all of them one by one.</p> + + <p>The <code>pre()</code> function is an initialization callback. It is + called when a new element of type <code>hello</code> is about + to be serialized. You would normally use this function to initialize + data structures, such as iterators, which will be used during + serialization. As we will see in subsequent chapters, there is + also a way to pass an argument to this function which may be + useful if you are serializing an in-memory data structure + to XML. The default implementation of the initialization callback + does nothing.</p> + + <p>The <code>post()</code> function is a finalization callback. It is + called when serialization of the element is completed. If necessary, + you can use this function to perform cleanups of data structures + initialized in <code>pre()</code> or during serialization. + The default implementation of the finalization callback also does + nothing. + </p> + + <p>The <code>greeting()</code> and <code>name()</code> functions are + called when the <code>greeting</code> and <code>name</code> elements + are about to be serialized and the values for these elements need + to be provided. Because the <code>name</code> element can be + repeated several times (note the <code>maxOccurs="unbounded"</code> + attribute in the schema), the serializer skeleton also has the + <code>name_next()</code> function which is called before + <code>name()</code> to check if another <code>name</code> element + needs to be serialized.</p> + + <p>The last three functions are for connecting serializers to each other. + For example, there is a predefined serializer for built-in XML Schema + type <code>string</code> in the XSD/e runtime. We will be using it to + serialize the values of <code>greeting</code> and <code>name</code> + elements, as shown in the next section.</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 create our + sample XML document. The first step is to implement the + serializer: + </p> + + <pre class="c++"> +#include <string> +#include <vector> +#include "hello-sskel.hxx" + +struct hello_simpl: hello_sskel +{ + hello_simpl () + { + names_.push_back ("sun"); + names_.push_back ("moon"); + names_.push_back ("world"); + } + + virtual void + pre () + { + i_ = names_.begin (); + } + + virtual std::string + greeting () + { + return "Hello"; + } + + virtual bool + name_next () + { + return i_ != names_.end (); + } + + virtual std::string + name () + { + return *i_++; + } + +private: + typedef std::vector<std::string> names; + + names names_; + names::iterator i_; +}; + </pre> + + <p>We use the <code>hello_simpl</code>'s constructor to initialize + a vector of names. Then, in the <code>pre()</code> initialization + callback, we initialize an iterator to point to the beginning of the + names vector. The <code>greeting()</code> callback + simply returns the string representing our greeting. The + <code>name_next()</code> callback checks if we reached the + end of the names vector and returns <code>false</code> + if that's the case. The <code>name()</code> callback returns + the next name from the names vector and advances the iterator. + Note that <code>name()</code> is not called if <code>name_next()</code> + returned false. Finally, we left <code>post()</code> with the + default implementations since we don't have anything to cleanup.</p> + + <p>Now it is time to put this serializer implementation to work:</p> + + <pre class="c++"> +#include <iostream> + +using namespace std; + +int +main () +{ + try + { + // Construct the serializer. + // + xml_schema::string_simpl string_s; + hello_simpl hello_s; + + hello_s.greeting_serializer (string_s); + hello_s.name_serializer (string_s); + + // Create the XML document. + // + xml_schema::document_simpl doc_s (hello_s, "hello"); + + hello_s.pre (); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + hello_s.post (); + } + catch (const xml_schema::serializer_exception& e) + { + cerr << "error: " << e.text () << endl; + return 1; + } +} + </pre> + + <p>The first part of this code snippet instantiates individual serializers + and assembles them into a complete vocabulary serializer. + <code>xml_schema::string_simpl</code> is an implementation of a + serializer for built-in XML Schema type <code>string</code>. It is + provided by the XSD/e runtime along with serializers for other built-in + types (for more information on the built-in serializers see + <a href="#7">Chapter 7, "Built-In XML Schema Type Serializers"</a>). + We use <code>string_simpl</code> to serialize the <code>greeting</code> + and <code>name</code> elements as indicated by the calls to + <code>greeting_serializer()</code> and <code>name_serializer()</code>. + </p> + + <p>Then we instantiate a document serializer (<code>doc_s</code>). The + first argument to its constructor is the serializer for the root + element (<code>hello_s</code> in our case). The second argument is + the root element name. + </p> + + <p>The final piece is the calls to <code>pre()</code>, + <code>serialize()</code>, and <code>post()</code>. The call to + <code>serialize()</code> performs the actual XML serialization + with the result written to <code>std::cout</code>. The second + argument in this call 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. + The calls to <code>pre()</code> and + <code>post()</code> make sure that the serializer for the + root element can perform proper initialization and cleanup.</p> + + <p>While our serializer implementation and test driver are pretty small and + easy to write by hand, for bigger XML vocabularies it can be a + substantial effort. To help with this task XSD/e can automatically + generate sample serializer implementations and a test driver from your + schemas. To request the generation of a sample implementation with + empty function bodies specify the <code>--generate-empty-impl</code> + option. To request the generation of a test driver you can use the + <code>--generate-test-driver</code> option. For more information + on these options refer to the + <a href="http://www.codesynthesis.com/projects/xsde/documentation/xsde.xhtml">XSD/e + Compiler Command Line Manual</a>.</p> + + <h2><a name="2.4">2.4 Compiling and Running</a></h2> + + <p>After saving all the parts from the previous section in + <code>driver.cxx</code>, we are ready to compile and run + our first application. On UNIX this can be done with the + following commands: + </p> + + <pre class="terminal"> +$ c++ -I.../libxsde -c driver.cxx hello-sskel.cxx +$ c++ -o driver driver.o hello-sskel.o .../libxsde/xsde/libxsde.a +$ ./driver +<hello> + <greeting>Hello</greeting> + <name>sun</name> + <name>moon</name> + <name>world</name> +</hello> + </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 XML Schema validation. We can "forget" to + add any names to the vector so that <code>name_next()</code> + returns <code>false</code> on the first call:</p> + +<pre class="c++"> +struct hello_simpl: hello_sskel +{ + hello_simpl () + { + /* + names_.push_back ("sun"); + names_.push_back ("moon"); + names_.push_back ("world"); + */ + } + ... +}; + </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 +error: expected element not encountered + </pre> + + + <!-- Chapater 3 --> + + + <h1><a name="3">3 Serializer Skeletons</a></h1> + + <p>As we have seen in the previous chapter, the XSD/e compiler generates + a serializer skeleton class for each type defined in XML Schema. In + this chapter we will take a closer look at different functions + that comprise a serializer skeleton as well as the way to connect + our implementations of these serializer skeletons to create a complete + vocabulary serializer.</p> + + <p>In this and subsequent chapters we will use the following + schema that describes a collection of person records. We + save it in <code>people.xsd</code>:</p> + + <pre class="xml"> +<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="last-name" type="xs:string"/> + <xs:element name="gender" type="gender"/> + <xs:element name="age" type="xs:short"/> + </xs:sequence> + </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 could look like + this:</p> + + <pre class="xml"> +<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> +</people> + </pre> + + <p>Compiling <code>people.xsd</code> with the XSD/e compiler results + in three serializer skeletons being generated: <code>gender_sskel</code>, + <code>person_sskel</code>, and <code>people_sskel</code>. We are going + to examine and implement each of them in the subsequent sections.</p> + + <p>In the previous chapter we used pre-initialized, static data to + create an XML document. In this chapter we will use the standard + input (<code>std::cin</code>) as the source of data. This approach + reflects a common design theme where the data to be serialized is + computed on the fly instead of being stored in, for example, an + in-memory object model. The next chapter will examine mechanisms + provided by the C++/Serializer mapping for serializing in-memory + object models.</p> + + <h2><a name="3.1">3.1 Implementing the Gender Serializer</a></h2> + + <p>The generated <code>gender_sskel</code> serializer skeleton looks + like this:</p> + + <pre class="c++"> +class gender_sskel: public xml_schema::string_sskel +{ +public: + gender_sskel (xml_schema::string_sskel* base_impl) + + // Serializer callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual void + post (); +}; + </pre> + + <p>Notice that <code>gender_sskel</code> inherits from + <code>xml_schema::string_sskel</code> which is a serializer + skeleton for built-in XML Schema type <code>string</code> + and is predefined in the XSD/e runtime library. This is an example + of the general rule that serializer skeletons follow: if a type + in XML Schema inherits from another then there will be an + equivalent inheritance between the corresponding serializer + skeleton classes. The <code>gender_sskel</code> class also + declares a constructor which expects a pointer to the base + serializer skeleton. We will discuss the purpose of this + constructor shortly.</p> + + <p>The <code>pre()</code> and <code>post()</code> callbacks should look + familiar from the previous chapter. Let's now implement this + serializer. Our implementation will simply query the gender + value from the standard input stream (<code>std::cin</code>):</p> + + + <pre class="c++"> +#include <string> +#include <iostream> + +using namespace std; + +class gender_simpl: public gender_sskel +{ +public: + gender_simpl () + : gender_sskel (&base_impl_) + { + } + + virtual void + pre () + { + string g; + cerr << "gender (male/female): "; + getline (cin, g); + base_impl_.pre (g); + } + +private: + xml_schema::string_simpl base_impl_; +}; + </pre> + + <p>While the code is quite short, there is a lot going on. First, + notice that we define a member variable <code>base_impl_</code> + of type <code>xml_schema::string_simpl</code> and then pass + it to the <code>gender_sskel</code>'s constructor. We have + encountered <code>xml_schema::string_simpl</code> already; it is an + implementation of the <code>xml_schema::string_sskel</code> serializer + skeleton for built-in XML Schema type <code>string</code>. By + passing <code>base_impl_</code> to the <code>gender_sskel</code>'s + constructor we provide an implementation for the part of the + serializer skeleton that is inherited from <code>string_sskel</code>.</p> + + <p>This is another common theme in the C++/Serializer programming model: + reusing implementations of the base serializers in the derived ones. + In our case, <code>string_simpl</code> will do all the dirty work of + serializing the data which we pass to it with the call to + <code>base_impl_.pre()</code>. For more information on serializer + implementation reuse refer to <a href="#6.6">Section 6.6, + "Serializer Reuse"</a>.</p> + + <p>In case you are curious, here are the definitions for + <code>xml_schema::string_sskel</code> and + <code>xml_schema::string_simpl</code>:</p> + + <pre class="c++"> +namespace xml_schema +{ + class string_sskel: public serializer_simple_content + { + public: + virtual void + pre (const std::string&) = 0; + }; + + class string_simpl: public string_sskel + { + public: + virtual void + pre (const std::string&); + + virtual void + _serialize_content (); + + protected: + std::string value_; + }; +} + </pre> + + <p>There are two new pieces in this code that we haven't seen yet. + Those are the <code>xml_schema::serializer_simple_content</code> + class and the <code>_serialize_content()</code> function. + The <code>serializer_simple_content</code> class is defined in + the XSD/e runtime and is a base class for all serializer skeletons + that conform to the simple content model in XML Schema. Types with + the simple content model cannot have nested elements—only + text and attributes. There is also the + <code>xml_schema::serializer_complex_content</code> class which + corresponds to the complex content mode (types with nested elements, + for example, <code>person</code> from <code>people.xsd</code>).</p> + + <p>The <code>_serialize_content()</code> function is a low-level + serializer callback that is called to perform actual content + serialization (that is to output text or nested elements). There + is also the <code>_serialize_attributes()</code> callback which + is called to serialize attributes in complex types. You will seldom + need to use these callbacks directly. Using implementations for the + built-in serializers provided by the XSD/e runtime is usually a + simpler and more convenient alternative.</p> + + <p>Another bit of information that is useful to know about is + the <code>_pre()</code> and <code>_post()</code> serialization + callbacks. Remember we talked about the <code>pre()</code> and + <code>post()</code> callbacks in the previous chapter? The + <code>_pre()</code> and <code>_post</code> have very + similar but somewhat different roles. As a result, each + serializer skeleton has four special callbacks:</p> + + <pre class="c++"> + virtual void + pre (); + + virtual void + _pre (); + + virtual void + _post (); + + virtual void + post (); + </pre> + + <p><code>pre()</code> and <code>_pre()</code> are initialization + callbacks. They get called in that order before a new instance of the type + is about to be serialized. The difference between <code>pre()</code> and + <code>_pre()</code> is conventional: <code>pre()</code> can + be completely overridden by a derived serializer. The derived + serializer can also override <code>_pre()</code> but has to always call + the original version. This allows you to partition initialization + into customizable and required parts.</p> + + <p>Similarly, <code>_post()</code> and <code>post()</code> are + finalization callbacks with exactly the same semantics: + <code>post()</code> can be completely overridden by the derived + serializer while the original <code>_post()</code> should always be + called. + </p> + + <p>At this point you might be wondering why some <code>pre()</code> + callbacks, for example <code>string_sskel::pre()</code>, have an + argument with which they receive the data they need to serialize while + others, for example <code>gender_sskel::pre()</code>, have no such + argument. This is a valid concern and it will be addressed in the + next chapter.</p> + + <h2><a name="3.2">3.2 Implementing the Person Serializer</a></h2> + + <p>The generated <code>person_sskel</code> serializer skeleton looks like + this:</p> + + <pre class="c++"> +class person_sskel: public xml_schema::serializer_complex_content +{ +public: + // Serializer callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual std::string + first_name () = 0; + + virtual std::string + last_name () = 0; + + virtual void + gender (); + + virtual short + age () = 0; + + virtual void + post (); + + // Serializer construction API. + // + void + first_name_serializer (xml_schema::string_sskel&); + + void + last_name_serializer (xml_schema::string_sskel&); + + void + gender_serializer (gender_sskel&); + + void + age_serializer (xml_schema::short_sskel&); + + void + serializers (xml_schema::string_sskel& /* first-name */, + xml_schema::string_sskel& /* last-name */, + gender_sskel& /* gender */, + xml_schema::short_sskel& /* age */); +}; + </pre> + + + <p>As you can see, we have a serializer callback for each of the nested + elements found in the <code>person</code> XML Schema type. + The implementation of this serializer is straightforward:</p> + + <pre class="c++"> +class person_simpl: public person_sskel +{ +public: + virtual string + first_name () + { + string fn; + cerr << "first name: "; + getline (cin, fn); + return fn; + } + + virtual std::string + last_name () + { + string ln; + cerr << "last name: "; + getline (cin, ln); + return ln; + } + + virtual short + age () + { + short a; + cerr << "age: "; + cin >> a; + return a; + } +}; + </pre> + + <p>Notice that we didn't need to override the <code>gender()</code> + callback because all the work is done by <code>gender_simpl</code>.</p> + + <h2><a name="3.3">3.3 Implementing the People Serializer</a></h2> + + <p>The generated <code>people_sskel</code> serializer skeleton looks like + this:</p> + + <pre class="c++"> +class people_sskel: public xml_schema::serializer_complex_content +{ +public: + // Serializer callbacks. Override them in your implementation. + // + virtual void + pre (); + + virtual bool + person_next () = 0; + + virtual void + person (); + + virtual void + post (); + + // Serializer construction API. + // + void + person_serializer (person_sskel&); + + void + serializers (person_sskel& /* person */); +}; + </pre> + + <p>The <code>person_next()</code> callback will be called before serializing + each <code>person</code> element. Our implementation of + <code>person_next()</code> asks the user whether to serialize + another person record:</p> + + <pre class="c++"> +class people_simpl: public people_sskel +{ +public: + virtual bool + person_next () + { + string s; + cerr << "serialize another person record (y/n): "; + cin >> ws; // Skip leading whitespaces. + getline (cin, s); + return s == "y"; + } +}; + </pre> + + <p>Now it is time to put everything together.</p> + + + <h2><a name="3.4">3.4 Connecting the Serializers Together</a></h2> + + <p>At this point we have all the individual serializers implemented + and can proceed to assemble them into a complete serializer + for our XML vocabulary. The first step is to instantiate + all the individual serializers that we will need:</p> + + <pre class="c++"> +xml_schema::short_simpl short_s; +xml_schema::string_simpl string_s; + +gender_simpl gender_s; +person_simpl person_s; +people_simpl people_s; + </pre> + + <p>Notice that our schema uses two built-in XML Schema types: + <code>string</code> for the <code>first-name</code> and + <code>last-name</code> elements as well as <code>short</code> + for <code>age</code>. We will use predefined serializers that + come with the XSD/e runtime to serialize these types. The next + step is to connect all the individual serializers. We do this + with the help of functions defined in the serializer + skeletons and marked with the "Serializer Construction API" + comment. One way to do it is to connect each individual + serializers by calling the <code>*_serializer()</code> functions:</p> + + <pre class="c++"> +person_s.first_name_serializer (string_s); +person_s.last_name_serializer (string_s); +person_s.gender_serializer (gender_s); +person_s.age_serializer (short_s); + +people_s.person_serializer (person_s); + </pre> + + <p>You might be wondering what happens if you do not provide + a serializer by not calling one of the <code>*_serializer()</code> + functions. In that case the corresponding XML fragment will be + skipped.</p> + + <p>An alternative, shorter, way to connect the serializers is by using + the <code>serializers()</code> functions which connects all the + serializers for a given type at once:</p> + + <pre class="c++"> +person_s.serializers (string_s, string_s, gender_s, short_s); +people_s.serializers (person_s); + </pre> + + <p>The following figure illustrates the resulting connections. Notice + the correspondence between return types of element callbacks and + argument types of the <code>pre()</code> functions that are connected + by the arrows.</p> + + <!-- align=center is needed for html2ps --> + <div class="img" align="center"><img src="figure-1.png"/></div> + + <p>The last step is the construction of the document serializer and + invocation of the complete serializer to produce an XML + document:</p> + + <pre class="c++"> +xml_schema::document_simpl doc_s (people_s, "people"); + +std::ostringstream os; + +people_s.pre (); +doc_s.serialize (os, xml_schema::document_simpl::pretty_print); +people_s.post (); + +cout << os.str (); + </pre> + + <p>Note that we first serialize the document into an + <code>std::ostringstream</code> object and then write + the result to the standard output stream. This is done + to prevent the input prompts and output XML from interleaving. + However, writing XML directly to <code>std::cout</code> in + this example is a great way to observe the moments in the XML + document construction process at which serializer callbacks are + being called.</p> + + <p>Let's consider <code>xml_schema::document_simpl</code> in + more detail. While the exact definition of this class + varies depending on the mapping configuration, here is + the part relevant to our example:</p> + + <pre class="c++"> +namespace xml_schema +{ + class document_simpl + { + public: + document_simpl (xml_schema::serializer_base&, + const std::string& root_element_name); + + document_simpl (xml_schema::serializer_base&, + const std::string& root_element_namespace, + const std::string& root_element_name); + + typedef unsigned short flags; + static const flags pretty_print; + + void + serialize (std::ostream&, flags = 0); + }; +} + </pre> + + <p><code>xml_schema::document_simpl</code> is a root serializer for + the vocabulary. The first argument to its constructors is the + serializer for the type of the root element (<code>people_simpl</code> + in our case). Because a type serializer is only concerned with + the element's content and not with the element's name, we need + to specify the root element name somewhere. That's + what is passed as the second and third arguments to the + <code>document_simpl</code>'s constructors.</p> + + <p>There is also a number of overloaded <code>serialize()</code> + function defined in the <code>document_simpl</code> class. + At the moment we are only interested in the version that + writes XML to a standard output stream. For more information + on the <code>xml_schema::document_simpl</code> class + refer to <a href="#8">Chapter 8, "Document Serializer and Error + Handling"</a>.</p> + + <p>Let's now consider a step-by-step list of actions that happen + as we serialize the following sample XML document:</p> + + <pre class="xml"> +<people> + <person> + <first-name>John</first-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>32</age> + </person> +</people> + </pre> + + + <ol class="steps"> + <li><code>people_s.pre()</code> is called from + <code>main()</code>. We did not provide any implementation + for this callback so this call is a no-op.</li> + + <li><code>doc_s.serialize(os)</code> is called from + <code>main()</code>. The document serializer + writes out the <code><people></code> opening tag + and calls <code>_pre()</code> on the root element + type serializer (<code>people_s</code>) which is + also a no-op. Serialization is delegated to + <code>people_s</code>.</li> + + <li>The <code>people_s</code> serializer calls <code>person_next()</code> + to determine if another <code>person</code> element + needs to be serialized. Our implementation ask the user + (who answers <code>"y"</code>) and returns <code>true</code>.</li> + + <li>The <code>people_s</code> serializer calls <code>person()</code> + which is a no-op. It then calls <code>pre()</code> on + <code>person_s</code> (no-op), writes out the + <code><person></code> opening tag, and calls <code>_pre()</code> + on <code>person_s</code> (no-op). Serialization is delegated to + <code>person_s</code>.</li> + + <li>The <code>person_s</code> serializer calls <code>first_name()</code> + that returns a first name which it asks the user to enter. + <code>person_s</code> then calls <code>pre()</code> on + <code>string_s</code> and passes the name returned from + <code>first_name()</code> as its argument. It then writes + out the <code><first-name></code> opening tag and calls + <code>_pre()</code> on <code>string_s</code>. Serialization + is delegated to <code>string_s</code>.</li> + + <li>The <code>_serialize_content()</code> callback is called on + <code>string_s</code> which writes out the string passed + to it in the <code>pre()</code> call.</li> + + <li>Control is returned to <code>person_s</code> which + calls <code>_post()</code> on <code>string_s</code>, writes + out the <code></first-name></code> closing tag, and calls + <code>post()</code> on <code>string_s</code>.</li> + + <li>Steps analogous to 5-7 are performed for the <code>last-name</code>, + <code>gender</code>, and <code>age</code> elements.</li> + + <li>Control is returned to <code>people_s</code> + which calls <code>_post()</code> on <code>person_s</code> (no-op), + writes out the <code></person></code> closing tag, and calls + <code>post()</code> on <code>person_s</code> (no-op).</li> + + <li>The <code>people_s</code> serializer calls <code>person_next()</code> + to determine if another <code>person</code> element + needs to be serialized. Our implementation ask the user + (who answers <code>"n"</code>) and returns <code>false</code>.</li> + + <li>Control is returned to <code>doc_s</code> which calls + <code>_post()</code> on <code>people_s</code> (no-op) and + writes out the <code></people></code> closing tag.</li> + + <li>Control is returned to <code>main()</code> which + calls <code>post()</code> on <code>people_s</code> (no-op).</li> + </ol> + + + <!-- Chpater 4 --> + + + <h1><a name="4">4 Type Maps</a></h1> + + <p>There are many useful things you can do inside serializer callbacks as they + are right now. There are, however, times when you want to propagate + some information from one serializer to another or from the caller of + the serializer. One common task that would greatly benefit from such a + possibility is serializing a tree-like in-memory object model to XML. + During execution, each individual serializer would be responsible + for disaggregating and serializing a specific portion of the tree + and delegating the rest to its sub-serializers.</p> + + <p>In this chapter we will discuss the mechanisms offered by the + C++/Serializer mapping for passing information between individual + serializers and see how to use them to serialize a sample object + model for our people vocabulary.</p> + + <h2><a name="4.1">4.1 Object Model</a></h2> + + <p>An object model for our person record example could + look like this (saved in the <code>people.hxx</code> file):</p> + + <pre class="c++"> +#include <string> +#include <vector> + +enum gender +{ + male, + female +}; + +class person +{ +public: + person (const std::string& first, + const std::string& last, + ::gender gender, + short age) + : first_ (first), last_ (last), + gender_ (gender), age_ (age) + { + } + + const std::string& + first () const + { + return first_; + } + + const std::string& + last () const + { + return last_; + } + + ::gender + gender () const + { + return gender_; + } + + short + age () const + { + return age_; + } + +private: + std::string first_; + std::string last_; + ::gender gender_; + short age_; +}; + +typedef std::vector<person> people; + </pre> + + <p>While it is clear which serializer is responsible for which part of + the object model, it is not exactly clear how, for + example, <code>person_simpl</code> will pass <code>gender</code> + to <code>gender_simpl</code>. You might have noticed that + <code>string_simpl</code> manages to receive its value from the + <code>first_name()</code> callback. Let's + see how we can utilize the same mechanism to propagate our + own data.</p> + + <p>There is a way to tell the XSD/e compiler that you want to + exchange data between serializers. More precisely, for each + type defined in XML Schema, you can tell the compiler two things. + First, the argument type of the <code>pre()</code> callback + in the serializer skeleton generated for this type. And, second, + the return type for callbacks corresponding to elements and + attributes of this type. For example, for XML Schema type + <code>gender</code> we can specify the argument type for + <code>pre()</code> in the <code>gender_sskel</code> + skeleton and the return type for the <code>gender()</code> callback + in the <code>person_sskel</code> skeleton. As you might have guessed, + the generated code will then pass the return value from an + element or attribute callback (<code>person_sskel::gender()</code> + in our case) to the <code>pre()</code> callback of the corresponding + serializer skeleton (<code>gender_sskel::pre()</code> in our case).</p> + + <p>The way to tell the XSD/e compiler about these XML Schema to + C++ mappings is with type map files. Here is a simple type + map for the <code>gender</code> type from the previous paragraph.</p> + + <pre class="type-map"> +include "people.hxx"; +gender ::gender ::gender; + </pre> + + <p>The first line indicates that the generated code must include + <code>people.hxx</code> in order to get the definition for the + <code>gender</code> type. The second line specifies that both + argument and return types for the <code>gender</code> + XML Schema type should be the <code>::gender</code> C++ enum + (we use fully-qualified C++ names to avoid name clashes). + The next section will describe the type map format in more detail. + We save this type map in <code>people.map</code> and + then translate our schemas with the <code>--type-map</code> + option to let the XSD/e compiler know about our type map:</p> + + <pre class="terminal"> +$ xsde cxx-serializer --type-map people.map people.xsd + </pre> + + <p>If we now look at the generated <code>people-sskel.hxx</code>, + we will see the following changes in the <code>gender_sskel</code> and + <code>person_sskel</code> skeletons:</p> + + <pre class="c++"> +#include "people.hxx" + +class gender_sskel: public xml_schema::string_sskel +{ + virtual void + pre (::gender) = 0; + + ... +}; + +class person_sskel: public xml_schema::serializer_complex_content +{ + virtual ::gender + gender () = 0; + + ... +}; + </pre> + + <p>Notice that <code>#include "people.hxx"</code> was added to + the generated header file from the type map to provide the + definition for the <code>gender</code> enum.</p> + + <h2><a name="4.2">4.2 Type Map File Format</a></h2> + + <p>Type map files are used to define a mapping between XML Schema + and C++ types. The compiler uses this information + to determine argument types of <code>pre()</code> + callbacks in serializer skeletons corresponding to XML Schema + types as well as return types for callbacks corresponding + to elements and attributes of these types.</p> + + <p>The compiler has a set of predefined mapping rules that map + the built-in XML Schema types to suitable C++ types (discussed + below) and all other types to <code>void</code>. + By providing your own type maps you can override these predefined + rules. The format of the type map file is presented below: + </p> + + <pre class="type-map"> +namespace <schema-namespace> [<cxx-namespace>] +{ + (include <file-name>;)* + ([type] <schema-type> <cxx-ret-type> [<cxx-arg-type>];)* +} + </pre> + + <p>Both <code><i><schema-namespace></i></code> and + <code><i><schema-type></i></code> are regex patterns while + <code><i><cxx-namespace></i></code>, + <code><i><cxx-ret-type></i></code>, and + <code><i><cxx-arg-type></i></code> are regex pattern + substitutions. All names can be optionally enclosed in + <code>" "</code>, for example, to include white-spaces.</p> + + <p><code><i><schema-namespace></i></code> determines XML + Schema namespace. Optional <code><i><cxx-namespace></i></code> + is prefixed to every C++ type name in this namespace declaration. + <code><i><cxx-ret-type></i></code> is a C++ type name that is + used as a return type for the element and attribute callbacks corresponding + to this schema type. Optional <code><i><cxx-arg-type></i></code> + is an argument type for the <code>pre()</code> callback in the serializer + skeleton for this schema type. If <code><i><cxx-arg-type></i></code> + is not specified, it defaults to <code><i><cxx-ret-type></i></code> + if <code><i><cxx-ret-type></i></code> ends with <code>*</code> or + <code>&</code> (that is, it is a pointer or a reference) and + <code>const <i><cxx-ret-type></i>&</code> + otherwise. + <code><i><file-name></i></code> is a file name either in the + <code>" "</code> or <code>< ></code> format + and is added with the <code>#include</code> directive to + the generated code.</p> + + <p>The <code><b>#</b></code> character starts a comment that ends + with a new line or end of file. To specify a name that contains + <code><b>#</b></code> enclose it in <code><b>" "</b></code>. + For example:</p> + + <pre> +namespace http://www.example.com/xmlns/my my +{ + include "my.hxx"; + + # Pass apples by value. + # + apple apple; + + # Pass oranges as pointers. + # + orange orange_t*; +} + </pre> + + <p>In the example above, for the + <code>http://www.example.com/xmlns/my#orange</code> + XML Schema type, the <code>my::orange_t*</code> C++ type will + be used as both return and argument types.</p> + + <p>Several namespace declarations can be specified in a single + file. The namespace declaration can also be completely + omitted to map types in a schema without a namespace. For + instance:</p> + + <pre class="type-map"> +include "my.hxx"; +apple apple; + +namespace http://www.example.com/xmlns/my +{ + orange "const orange_t*"; +} + </pre> + + <p>The compiler has a number of predefined mapping rules for + the built-in XML Schema types which can be presented as the + following map files:</p> + + <pre class="type-map"> +namespace http://www.w3.org/2001/XMLSchema +{ + boolean bool bool; + + byte "signed char" "signed char"; + unsignedByte "unsigned char" "unsigned char"; + + short short short; + unsignedShort "unsigned short" "unsigned short"; + + int int int; + unsignedInt "unsigned int" "unsigned int"; + + long "long long" "long long"; + unsignedLong "unsigned long long" "unsigned long long"; + + integer long long; + + negativeInteger long long; + nonPositiveInteger long long; + + positiveInteger "unsigned long" "unsigned long"; + nonNegativeInteger "unsigned long" "unsigned long"; + + float float float; + double double double; + decimal double double; + + NMTOKENS "const xml_schema::string_sequence*"; + IDREFS "const xml_schema::string_sequence*"; + + base64Binary "const xml_schema::buffer*"; + hexBinary "const xml_schema::buffer*"; + + date xml_schema::date; + dateTime xml_schema::date_time; + duration xml_schema::duration; + gDay xml_schema::gday; + gMonth xml_schema::gmonth; + gMonthDay xml_schema::gmonth_day; + gYear xml_schema::gyear; + gYearMonth xml_schema::gyear_month; + time xml_schema::time; +} + </pre> + + <p>If STL is enabled (<a href="#6.1">Section 6.1, "Standard Template + Library"</a>), the following mapping is used for the string-based + XML Schema built-in types:</p> + + <pre class="type-map"> +namespace http://www.w3.org/2001/XMLSchema +{ + include <string>; + + anySimpleType std::string; + + string std::string; + normalizedString std::string; + token std::string; + Name std::string; + NMTOKEN std::string; + NCName std::string; + ID std::string; + IDREF std::string; + language std::string; + anyURI std::string; + + QName xml_schema::qname; +} + </pre> + + <p>Otherwise, a C string-based mapping is used:</p> + + <pre class="type-map"> +namespace http://www.w3.org/2001/XMLSchema +{ + anySimpleType "const char*"; + + string "const char*"; + normalizedString "const char*"; + token "const char*"; + Name "const char*"; + NMTOKEN "const char*"; + NCName "const char*"; + ID "const char*"; + IDREF "const char*"; + language "const char*"; + anyURI "const char*"; + + QName "const xml_schema::qname*"; +} + </pre> + + <p>For more information about the mapping of the built-in XML Schema types + to C++ types refer to <a href="#7">Chapter 7, "Built-In XML Schema Type + Serializers"</a>. The last predefined rule maps anything that wasn't + mapped by previous rules to <code>void</code>:</p> + + <pre class="type-map"> +namespace .* +{ + .* void void; +} + </pre> + + + <p>When you provide your own type maps with the + <code>--type-map</code> option, they are evaluated first. This + allows you to selectively override any + of the predefined rules. Note also that if you change the mapping + of a built-in XML Schema type then it becomes your responsibility + to provide the corresponding serializer skeleton and implementation + in the <code>xml_schema</code> namespace. You can include the + custom definitions into the generated header file using the + <code>--hxx-prologue-*</code> options.</p> + + <h2><a name="4.3">4.3 Serializer Implementations</a></h2> + + <p>With the knowledge from the previous section, we can proceed + with creating a type map that maps types in the <code>people.xsd</code> + schema to our object model classes in + <code>people.hxx</code>. In fact, we already have the beginning + of our type map file in <code>people.map</code>. Let's extend + it with the rest of the types:</p> + + <pre class="type-map"> +include "people.hxx"; + +gender ::gender ::gender; +person "const ::person&"; +people "const ::people&"; + </pre> + + <p>A few things to note about this type map. We decided to pass + the <code>person</code> and <code>people</code> objects by + constant references in order to avoid unnecessary copying. + We can do this because we know that our object model is + present for the duration of serialization. We also did not + provide any mappings for built-in XML Schema types + <code>string</code> and <code>short</code> because they + are handled by the predefined rules and we are happy with + the result. Note also that all C++ types are fully qualified. + This is done to avoid potential name conflicts in the generated + code. Now we can recompile our schema and move on to implementing + the serializers:</p> + + <pre class="terminal"> +$ xsde cxx-serializer --type-map people.map people.xsd + </pre> + + <p>Here is the implementation of our three serializers in full. One + way to save typing when implementing your own serializers is + to open the generated code and copy the signatures of serializer + callbacks into your code. Or you could always auto generate the + sample implementations and fill them with your code.</p> + + <pre class="c++"> +#include "people-sskel.hxx" + +const char* gender_strings[] = {"male", "female"}; + +class gender_simpl: public gender_sskel +{ +public: + gender_simpl () + : gender_sskel (&base_impl_) + { + } + + virtual void + pre (gender g) + { + base_impl_.pre (gender_strings[g]); + } + +private: + xml_schema::string_simpl base_impl_; +}; + +class person_simpl: public person_sskel +{ +public: + virtual void + pre (const person& p) + { + p_ = &p; + } + + virtual std::string + first_name () + { + return p_->first (); + } + + virtual std::string + last_name () + { + return p_->last (); + } + + virtual ::gender + gender () + { + return p_->gender (); + } + + virtual short + age () + { + return p_->age (); + } + +private: + const person* p_; +}; + +class people_simpl: public people_sskel +{ +public: + virtual void + pre (const people& p) + { + p_ = &p; + i_ = p_->begin (); + } + + virtual bool + person_next () + { + return i_ != p_->end (); + } + + virtual const ::person& + person () + { + return *i_++; + } + +private: + const people* p_; + people::const_iterator i_; +}; + </pre> + + <p>This code fragment should look familiar by now. Just note that + all the <code>pre()</code> callbacks now have arguments. Here is the + implementation of the test driver for this example:</p> + + <pre class="c++"> +#include <iostream> + +using namespace std; + +int +main () +{ + // Create a sample object model. + // + people ppl; + + ppl.push_back (person ("John", "Doe", male, 32)); + ppl.push_back (person ("Jane", "Doe", female, 28)); + + // Construct the serializer. + // + xml_schema::short_simpl short_s; + xml_schema::string_simpl string_s; + + gender_simpl gender_s; + person_simpl person_s; + people_simpl people_s; + + person_s.serializers (string_s, string_s, gender_s, short_s); + people_s.serializers (person_s); + + // Create the XML document. + // + xml_schema::document_simpl doc_s (people_s, "people"); + + people_s.pre (ppl); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + people_s.post (); +} + </pre> + + <p>The serializer creation and assembly part is exactly the same as in + the previous chapter. The serialization part is a bit different: + <code>people_simpl::pre()</code> now has an argument which is the + complete object model. Also we write the resulting XML directly + to the standard output stream instead of first storing it in a string. + We can now save the last two code fragments to <code>driver.cxx</code> + and proceed to compile and test our new application:</p> + + + <pre class="terminal"> +$ c++ -I.../libxsde -c driver.cxx people-sskel.cxx +$ c++ -o driver driver.o people-sskel.o .../libxsde/xsde/libxsde.a +$ ./driver +<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> +</people> + </pre> + + + <!-- Serializer Callbacks --> + + <h1><a name="5">5 Serializer Callbacks</a></h1> + + <p>In previous chapters we have learned that for each attribute + and element in a schema type there is a callback in a serializer + skeleton with the same name and which optionally returns + this element's or attribute's value. We've also seen that + elements that can appear multiple times + (<code>maxOccurs="unbounded"</code>) have an additional + serializer callback in the form:</p> + + <pre class="c++"> +virtual bool +<name>_next (); + </pre> + + <p>Where <code><name></code> stands for the element's name. In + this chapter we will discuss other additional serializer + callbacks that are generated for certain XML Schema constructs. + We will also learn that besides elements and attributes, serializer + callback can be generated for the <code>all</code>, <code>choice</code>, + and <code>sequence</code> compositors as well as the <code>any</code> + and <code>anyAttribute</code> wildcards.</p> + + <p>When additional serializer callback are generated for elements + and attributes, their names are derived from element's and + attribute's names. Compositors and wildcards, on the other + hand, do not have names and as a result the serializer + callback names for these constructs are based on synthesized + names in the form: <code>all</code> for the <code>all</code> + compositor, <code>sequence</code>, <code>sequence1</code>, + etc., for the <code>sequence</code> compositors, <code>choice</code>, + <code>choice1</code>, etc., for the <code>choice</code> compositors, + <code>any</code>, <code>any1</code>, etc., for the <code>any</code> + wildcards, and <code>any_attribute</code>, <code>any_attribute1</code>, + etc., for the <code>anyAttribute</code> wildcards. For example:</p> + + <pre> +<xs:complexType name="coordinates"> + <xs:sequence maxOccurs="unbounded"> + <xs:element name="lat" type="xs:float"/> + <xs:element name="lon" type="xs:float"/> + </xs:sequence> +</xs:complexType> + </pre> + + <p>The above schema fragment, when compiled, results in the following + serializer skeleton:</p> + + <pre class="c++"> +class coordinates_sskel: public xml_schema::serializer_complex_content +{ +public: + virtual void + pre (); + + virtual bool + sequence_next (); + + virtual float + lan () = 0; + + virtual float + lon () = 0; + + virtual void + post (); + + ... +}; + </pre> + + + <h2><a name="5.1">5.1 Optional Callback</a></h2> + + <p>For elements, compositors, and element wildcards with the minimal + occurrence constraint equals <code>0</code> (<code>minOccurs="0"</code>) + and the maximum occurrence constraint equals <code>1</code> + (<code>maxOccurs="1"</code>) as well as for optional attributes, the + optional callback is generated in the form:</p> + + <pre class="c++"> +virtual bool +<name>_present (); + </pre> + + <p>This callback is called before any other callbacks for this schema + construct and if it returns <code>false</code> no further callback + calls corresponding to this construct are made and the corresponding + XML fragment is omitted. For example:</p> + + <pre> +<xs:complexType name="name"> + <xs:sequence minOccurs="0"> + <xs:element name="first" type="xs:string"/> + <xs:element name="initial" type="xs:string" minOccurs="0"/> + <xs:element name="last" type="xs:string"/> + </xs:sequence> + <xs:attribute name="lang" type="xs:language"/> +</xs:complexType> + </pre> + + <p>The above schema fragment, when compiled, results in the following + serializer skeleton:</p> + + <pre class="c++"> +class name_sskel: public xml_schema::serializer_complex_content +{ +public: + virtual void + pre (); + + virtual bool + lang_present (); + + virtual std::string + lang () = 0; + + virtual bool + sequence_present (); + + virtual std::string + first () = 0; + + virtual bool + initial_present (); + + virtual std::string + initial () = 0; + + virtual std::string + last () = 0; + + virtual void + post (); + + ... +}; + </pre> + + <h2><a name="5.2">5.2 Sequence Callback</a></h2> + + <p>For elements, compositors, and element wildcards with the the maximum + occurrence constraint greater than <code>1</code> (for example, + <code>maxOccurs="unbounded"</code>) the sequence callback is + generated in the form:</p> + + <pre class="c++"> +virtual bool +<name>_next (); + </pre> + + <p>This callback is called before each new item of the sequence is + about to be serialized. Returning <code>false</code> from this + callback indicates that no more items in the sequence need to + be serialized. For example:</p> + + <pre> +<xs:complexType name="names"> + <xs:sequence maxOccurs="unbounded"> + <xs:element name="first" type="xs:string"/> + <xs:element name="last" type="xs:string"/> + <xs:element name="pseudonym" type="xs:string" maxOccurs="3"/> + </xs:sequence> +</xs:complexType> + </pre> + + <p>The above schema fragment, when compiled, results in the following + serializer skeleton:</p> + + <pre class="c++"> +class names_sskel: public xml_schema::serializer_complex_content +{ +public: + virtual void + pre (); + + virtual bool + sequence_next () = 0; + + virtual std::string + first () = 0; + + virtual std::string + last () = 0; + + virtual bool + pseudonym_next () = 0; + + virtual std::string + pseudonym () = 0; + + virtual void + post (); +}; + </pre> + + <h2><a name="5.3">5.3 Choice Callback</a></h2> + + <p>The choice compositor allows an XML document to contain one + of several element or compositor options. In the Embedded + C++/Serializer mapping, these options are called <em>choice + arms</em> and are identified by the <em>arm tags</em>. For + example:</p> + + <pre> +<xs:complexType name="name"> + <xs:choice> + <xs:element name="full-name" type="xs:string"/> + <xs:sequence> + <xs:element name="first-name" type="xs:string"/> + <xs:element name="last-name" type="xs:string"/> + </xs:sequence> + </xs:choice> +</xs:complexType> + </pre> + + <p>The above schema fragment, when compiled, results in the following + serializer skeleton:</p> + + <pre class="c++"> +class name_sskel: public xml_schema::serializer_complex_content +{ +public: + virtual void + pre (); + + enum choice_arm_tag + { + full_name_tag, + sequence_tag + }; + + virtual choice_arm_tag + choice_arm () = 0; + + virtual std::string + full_name () = 0; + + virtual std::string + first_name () = 0; + + virtual std::string + last_name () = 0; + + virtual void + post (); +}; + </pre> + + <p>The arm tags enum name (<code>choice_arm_tag</code> above) is derived + from the choice compositor name (that is, <code>choice</code>, + <code>choice1</code>, etc.) by adding the <code>_arm_tag</code> + suffix. The tag names themselves are derived from the corresponding + elements, compositors, or element wildcards.</p> + + <p>The choice compositor callback has a name in the form + <code>choice_tag()</code> (or <code>choice1_tag()</code>, etc., for + subsequent <code>choice</code> compositors in the type). It returns + the arm tag which identifies the choice arm that should be + serialized. For example, if a <code>name_sskel</code> implementation + returns <code>full_name_tag</code> from the <code>choice_arm()</code> + callback, then the first choice arm is chosen and + the <code>full_name()</code> callback is then called. Otherwise + the <code>first_name</code> and <code>last_name()</code> callbacks + are called.</p> + + + <h2><a name="5.4">5.4 Element Wildcard Callbacks</a></h2> + + <p>An element wildcard allows an arbitrary element from the specified + namespace list to be present in an XML instance. Element wildcards + can have the same cardinality constraints as elements and, as as a + result, the optional or sequence callbacks can be generated. For + example:</p> + + <pre> +<xs:complexType name="name"> + <xs:sequence> + <xs:element name="first" type="xs:string"/> + <xs:element name="last" type="xs:string"/> + <xs:any namespace="##other" processContents="skip" minOccurs="0"/> + </xs:sequence> +</xs:complexType> + </pre> + + <p>The above schema fragment, when compiled, results in the following + serializer skeleton:</p> + + <pre class="c++"> +class name_sskel: public xml_schema::serializer_complex_content +{ +public: + virtual void + pre (); + + virtual std::string + first () = 0; + + virtual std::string + last () = 0; + + virtual bool + any_present (); + + virtual void + any (std::string& ns, std::string& name); + + virtual void + serialize_any (); + + virtual void + post (); +}; + </pre> + + <p>The <code>any()</code> callback is called to obtain the element + name and namespace. If validation is enabled, the namespace is + checked against the allowed list. Then an element with these name + and namespace is created and the <code>serialize_any()</code> + callback is called to allow you to serialize the element's attributes + and content. There are two common ways to serialize a wildcard + element. The first approach is to use a serializer implementation. + This approach is shown in the <code>wildcard</code> example which + is part of the XSD/e distribution. The other approach is to use + the low-level XML serialization API that is available to every + serializer implementation via the + <code>xml_schema::serializer_base</code> base serializer:</p> + + <pre class="c++"> +namespace xml_schema +{ + class serializer_base + { + public: + void + _start_element (const char* name); + + void + _start_element (const char* ns, const char* name); + + void + _end_element (); + + void + _start_attribute (const char* name); + + void + _start_attribute (const char* ns, const char* name); + + void + _end_attribute (); + + void + _attribute (const char* name, const char* value); + + void + _attribute (const char* ns, const char* name, const char* value); + + void + _characters (const char*); + + void + _characters (const char*, size_t); + + void + _declare_namespace (const char* ns, const char* prefix); + + void + _declare_default_namespace (const char* ns); + + void + _clear_default_namespace (); + }; +} + </pre> + + <p>The following example shows how we could implement the + <code>name_sskel</code> skeleton using this approach:</p> + + <pre class="c++"> +class name_simpl: public name_sskel +{ +public: + virtual std::string + first () + { + return "John"; + } + + virtual ::std::string + last () + { + return "Doe"; + } + + virtual bool + any_present () + { + return true; + } + + virtual void + any (std::string& ns, std::string& name) + { + ns = "http://www.example.com/extension"; + name = "pseudonyms"; + } + + virtual void + serialize_any () + { + _attribute ("id", "jd"); + + _start_element ("pseudonym"); + _characters ("Johnny Doer"); + _end_element (); + + _start_element ("pseudonym"); + _characters ("Johnty Doo"); + _end_element (); + } +}; + </pre> + + + <h2><a name="5.5">5.5 Attribute Wildcard Callbacks</a></h2> + + <p>An attribute wildcard allows an arbitrary number of attributes from + the specified namespace list to be present in an XML instance. As a + result, the serializer callbacks for an attribute wildcard resemble + those of an element with <code>maxOccurs="unbounded"</code>. For + example:</p> + + <pre> +<xs:complexType name="name"> + <xs:sequence> + <xs:element name="first" type="xs:string"/> + <xs:element name="last" type="xs:string"/> + </xs:sequence> + <xs:anyAttribute namespace="##any" processContents="skip"/> +</xs:complexType> + </pre> + + <p>The above schema fragment, when compiled, results in the following + serializer skeleton:</p> + + <pre class="c++"> +class name_sskel: public xml_schema::serializer_complex_content +{ +public: + virtual void + pre (); + + virtual bool + any_attribute_next (); + + virtual void + any_attribute (std::string& ns, std::string& name); + + virtual void + serialize_any_attribute (); + + virtual std::string + first () = 0; + + virtual std::string + last () = 0; + + virtual void + post (); +}; + </pre> + + <p>Every time the <code>any_attribute_next()</code> callback returns + <code>true</code>, <code>any_attribute()</code> is called to obtain + the attribute name and namespace. If validation is enabled, the + namespace is checked against the allowed list. Then an attribute + with these name and namespace is created and the + <code>serialize_any_attribute()</code> callback is called to allow + you to write the attribute value, for example using one of the + serializer implementations (see the <code>wildcard</code> example + on how to do it) or the low-level <code>_characters()</code> function + (for more information about the low-level XML serialization + API see the previous section). The following example show + how we could implement the <code>name_sskel</code> skeleton + using the latter approach:</p> + + <pre class="c++"> +class name_simpl: public name_sskel +{ +public: + virtual void + pre () + { + id_written_ = false; + } + + virtual bool + any_attribute_next () + { + return !id_written_; + } + + virtual void + any_attribute (std::string& ns, std::string& name) + { + ns = ""; + name = "id"; + } + + virtual void + serialize_any_attribute () + { + _characters ("jd"); + id_written_ = true; + } + + virtual std::string + first () + { + return "John"; + } + + virtual ::std::string + last () + { + return "Doe"; + } + +private: + bool id_written_; +}; + </pre> + + + <!-- Mapping Configuration --> + + + <h1><a name="6">6 Mapping Configuration</a></h1> + + <p>The Embedded C++/Serializer 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, serializer + implementation reuse styles, and support for XML Schema polymorphism. + Previous chapters assumed that the use of STL, iostream, C++ + exceptions, and XML Schema validation were enabled. + This chapter will discuss the changes in the Embedded C++/Serializer + programming model that result from the changes to these configuration + parameters. A complete example that uses the minimal mapping + configuration is presented at the end of this chapter.</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>The Embedded C++/Serializer mapping always expects character data + supplied by the application to be in the same 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. The underlying XML + serializer used by the Embedded C++/Serializer mapping produces + the resulting XML documents in the UTF-8 encoding.</p> + + <h2><a name="6.1">6.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. When STL is disabled, all string-based + XML Schema types are mapped to C-style <code>const char*</code> + instead of <code>std::string</code>, as described in + <a href="#4.2">Section 4.2, "Type Map File Format"</a>. The + following code fragment shows changes in the + signatures of the <code>first_name()</code> and <code>last_name()</code> + callbacks from the person record example.</p> + + <pre class="c++"> +class person_sskel +{ +public: + virtual const char* + first_name (); + + virtual const char* + last_name (); + + ... +}; + </pre> + + <p>When STL is disabled, the serializer implementations for the string-based + built-in XML Schema types can be instructed to release the string + after serialization using operator <code>delete[]</code>. For more + information on how to do this refer to <a href="#7.2">Section 7.2, + "String-Based Type Serializers"</a>. + </p> + + <h2><a name="6.2">6.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, the + following <code>serialize()</code> function in the + <code>xml_schema::document_simpl</code> class become unavailable:</p> + + <pre class="c++"> +void +serialize (std::ostream&, flags); + </pre> + + <p>See <a href="#8.1">Section 8.1, "Document Serializer"</a> + for more information.</p> + + <h2><a name="6.3">6.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 are indicated with error codes instead of + exceptions, as described in <a href="#8.3">Section 8.3, + "Error Codes"</a>. + </p> + + <h2><a name="6.4">6.4 XML Schema Validation</a></h2> + + <p>To disable support for XML Schema validation, you will need to + configure the XSD/e runtime accordingly as well as pass + the <code>--suppress-validation</code> option to the XSD/e compiler + when translating your schemas. Disabling XML Schema validation + allows to further increase the serialization performance and + reduce footprint in cases where the data being serialized is + known to be valid. + </p> + + <h2><a name="6.5">6.5 64-bit Integer Type</a></h2> + + <p>By default the 64-bit <code>long</code> and <code>unsignedLong</code> + XML Schema built-in 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="6.6">6.6 Serializer Reuse</a></h2> + + <p>When one type in XML Schema inherits from another, it is + often desirable to be able to reuse the serializer implementation + corresponding to the base type in the serializer implementation + corresponding to the derived type. XSD/e provides support + for two serializer 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.</p> + + <p>The compiler can also be instructed not to generate any support + for serializer reuse with the <code>--reuse-style-none</code> option. + This is mainly useful to further reduce the generated code size + when your vocabulary does not use inheritance or when you plan + to implement each serializer from scratch. Note also that the + XSD/e runtime should be configured in accordance with the + serializer reuse style used in the generated code. The remainder + of this section discusses the mixin and tiein serializer reuse + styles in more detail.</p> + + + <p>To provide concrete examples for each reuse style we will use the + following schema fragment:</p> + + <pre class="xml"> +<xs:complexType name="person"> + <xs:sequence> + <xs:element name="first-name" type="xs:string"/> + <xs:element name="last-name" type="xs:string"/> + <xs:element name="age" type="xs:short"/> + </xs:sequence> +</xs:complexType> + +<xs:complexType name="emplyee"> + <complexContent> + <extension base="person"> + <xs:sequence> + <xs:element name="position" type="xs:string"/> + <xs:element name="salary" type="xs:unsignedLong"/> + </xs:sequence> + </extension> + </complexContent> +</xs:complexType> + </pre> + + <p>The mixin serializer reuse style uses the C++ mixin idiom that + relies on multiple and virtual inheritance. Because + virtual inheritance can result in a significant object + code size increase, this reuse style should be considered + when such an overhead is acceptable and/or the vocabulary + consists of only a handful of types. When the mixin reuse + style is used, the generated serializer skeletons use virtual + inheritance, for example:</p> + + <pre class="c++"> +class person_sskel: public virtual serializer_complex_content +{ + ... +}; + +class employee_sskel: public virtual person_sskel +{ + ... +}; + </pre> + + + <p>When you implement the base serializer you also need to use + virtual inheritance. The derived serializer is implemented + by inheriting from both the derived serializer skeleton and + the base serializer implementation (that is, <em>mixing in</em> + the base serializer implementation), for example:</p> + + <pre class="c++"> +class person_simpl: public virtual person_sskel +{ + ... +}; + +class employee_simpl: public employee_sskel, + public person_simpl +{ + ... +}; + </pre> + + + <p>The tiein serializer reuse style uses delegation and normally + results in a significantly smaller object code while being + almost as convenient to use as the mixin style. When the + tiein reuse style is used, the generated derived serializer + skeleton declares a constructor which allows you to specify + the implementation of the base serializer:</p> + + <pre class="c++"> +class person_sskel: public serializer_complex_content +{ + ... +}; + +class employee_sskel: public person_sskel +{ +public: + employee_sskel (person_sskel* base_impl) + + ... +}; + </pre> + + <p>If you pass the implementation of the base serializer to this + constructor then the generated code will transparently + forward all the callbacks corresponding to the base serializer + skeleton to this implementation. You can also pass + <code>0</code> to this constructor in which case you will + need to implement the derived serializer from scratch. The + following example shows how we could implement the + <code>person</code> and <code>employee</code> serializers + using the tiein style:</p> + + <pre class="c++"> +class person_simpl: public person_sskel +{ + ... +}; + +class employee_simpl: public employee_sskel +{ +public: + employee_simpl () + : employee_sskel (&base_impl_) + { + } + + ... + +private: + person_simpl base_impl_; +}; + </pre> + + <p>Note that you cannot use the <em>tied in</em> base serializer + instance (<code>base_impl_</code> in the above code) for + serializing anything except the derived type.</p> + + <p>The ability to override the base serializer callbacks in the + derived serializer is also available in the tiein style. For + example, the following code fragment shows how we can + override the <code>age()</code> callback if we didn't + like the implementation provided by the base serializer:</p> + + <pre class="c++"> +class employee_simpl: public employee_sskel +{ +public: + employee_simpl () + : employee_sskel (&base_impl_) + { + } + + virtual short + age () + { + ... + } + + ... + +private: + person_simpl base_impl_; +}; + </pre> + + <p>In the above example the <code>age</code> element will be + handled by <code>emplyee_simpl</code> while the <code>first-name</code> + and <code>last-name</code> callbacks will still go to + <code>base_impl_</code>.</p> + + <p>It is also possible to inherit from the base serializer implementation + instead of declaring it as a member variable. This can be useful + if you need to access protected members in the base implementation + or need to override a virtual function that is not part of + the serializer skeleton interface. Note, however, that in this case + you will need to resolve a number of ambiguities with explicit + qualifications or using-declarations. For example:</p> + + + <pre class="c++"> +class person_simpl: public person_sskel +{ +public: + virtual void + pre (person* p) + { + person_ = p; + } + + ... + +protected: + person* person_; +}; + +class employee_simpl: public employee_sskel, + public person_simpl +{ +public: + employee_simpl () + : employee_sskel (static_cast<person_simpl*> (this)) + { + } + + // Resolve ambiguities. + // + using emplyee_sskel::serializers; + + virtual void + pre (employee* e) + { + person_simpl::pre (e); + } + + virtual std::string + position () + { + return static_cast<employee*> (person_)->position (); + } + + virtual unsigned int + salary () + { + return static_cast<employee*> (person_)->salary (); + } +}; + </pre> + + <h2><a name="6.7">6.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</code>'s constructors. 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>When using the polymorphism-aware generated code, you can specify + several serializers for a single element by passing a serializer map + instead of an individual serializer to the serializer connection function + for the element. One of the serializers will then be looked up and used + depending on the user-provided type information that can optionally be + set in the callback function for the element. 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: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> + + <person can-fly="true" wing-span="10" xsi:type="batman"> + <name>Bruce Wayne</name> + </person> + +</supermen> + </pre> + + <p>The C++ object model for this vocabulary might look as follows:</p> + + <pre class="c++"> +#include <string> +#include <vector> + +enum type_id +{ + person_type, + superman_type, + batman_type +}; + +class person +{ +public: + virtual + ~person () {} + + person (const std::string& name) + : name_ (name) + { + } + + const std::string& + name () const + { + return name_; + } + + void + name (const std::string& n) + { + name_ = n; + } + + virtual type_id + type () const + { + return person_type; + } + +private: + std::string name_; +}; + +class superman: public person +{ +public: + superman (const std::string& name, bool can_fly) + : person (name), can_fly_ (can_fly) + { + } + + bool + can_fly () const + { + return can_fly_; + } + + void + can_fly (bool cf) + { + can_fly_ = cf; + } + + virtual type_id + type () const + { + return superman_type; + } + +private: + bool can_fly_; +}; + +class batman: public superman +{ +public: + batman (const std::string& name, unsigned int wing_span) + : superman (name, true), wing_span_ (wing_span) + { + } + + unsigned int + wing_span () const + { + return wing_span_; + } + + void + wing_span (unsigned int ws) + { + wing_span_ = ws; + } + + virtual type_id + type () const + { + return batman_type; + } + +private: + unsigned int wing_span_; +}; + +// Poor man's polymorphic sequence which also assumes ownership +// of the elements. +// +class supermen: public std::vector<person*> +{ +public: + ~supermen () + { + for (iterator i = begin (); i != end (); ++i) + delete *i; + } +}; + </pre> + + <p>Here we choose to provide our own type information. We can instead + use the standard C++ <code>typeid</code>/<code>type_info</code> + mechanism if it is available. The type map corresponding to this + object model is presented below. Notice that the <code>superman</code> + and <code>batman</code> objects are passed as a reference to + <code>person</code>:</p> + + <pre> +person "const ::person&"; +superman "const ::person&"; +batman "const ::person&"; +supermen "const ::supermen&"; + </pre> + + <p>The serializer implementations that serialize the above + C++ object model to XML are presented next:</p> + + <pre class="c++"> +class person_simpl: public person_sskel +{ +public: + virtual void + pre (const person& p) + { + person_ = &p; + } + + virtual std::string + name () + { + return person_->name (); + } + + // Derived serializer implementations need access to this + // member variable. + // +public: + const person* person_; +}; + +class superman_simpl: public superman_sskel +{ +public: + superman_simpl () + : superman_sskel (&base_impl_) + { + } + + virtual bool + can_fly () + { + return superman_ ().can_fly (); + } + + const superman& + superman_ () + { + return *static_cast<const superman*> (base_impl_.person_); + } + +private: + person_simpl base_impl_; +}; + +class batman_simpl: public batman_sskel +{ +public: + batman_simpl () + : batman_sskel (&base_impl_) + { + } + + virtual unsigned int + wing_span () + { + return batman_ ().wing_span (); + } + + const batman& + batman_ () + { + return static_cast<const batman&> (base_impl_.superman_ ()); + } + +private: + superman_simpl base_impl_; +}; + +class supermen_simpl: public supermen_sskel +{ +public: + virtual void + pre (const supermen& s) + { + supermen_ = &s; + i_ = s.begin (); + } + + virtual bool + person_next () + { + return i_ != supermen_->end (); + } + + virtual const ::person& + person () + { + const ::person& p = **i_++; + xml_schema::serializer_context& ctx = _context (); + + switch (p.type ()) + { + case person_type: + { + ctx.type_id (person_sskel::_static_type ()); + break; + } + case superman_type: + { + ctx.type_id (superman_sskel::_static_type ()); + break; + } + case batman_type: + { + ctx.type_id (batman_sskel::_static_type ()); + break; + } + } + + return p; + } + +private: + const supermen* supermen_; + supermen::const_iterator i_; +}; + </pre> + + <p>Most of the code in these serializer implementations is the same + as in the non-polymorphic case. The only part that explicitly deals + with polymorphism is the <code>person()</code> callback in the + <code>superman_simpl</code> class. In it we are translating + the type information as provided by the C++ object mode to + the type information used in the default implementation of + the serializer map (we will talk more about serializer maps + as well as the <code>_static_type()</code> function shortly). + The <code>type_id()</code> function from + <code>xml_schema::serializer_context</code> allows you to + specify optional type information which is used to look up + the corresponding serializer. Its argument is of type + <code>const void*</code> which allows you to pass + application-specific type information as an opaque pointer.</p> + + <p>The following code fragment shows how to connect the serializers + together and then use them to serialize a sample object model. + Notice that for the <code>person</code> element in the + <code>instance_s</code> serializer we specify a serializer map + instead of a specific serializer and we pass <code>true</code> as + the last argument to the document serializer constructor to indicate + that we are serializing potentially-polymorphic XML documents:</p> + + <pre class="c++"> +int +main () +{ + // Create a sample supermen catalog. To keep things simple + // the following code is not exception-safe. + // + supermen sm; + + sm.push_back (new person ("John Doe")); + sm.push_back (new superman ("James 007 Bond", false)); + sm.push_back (new batman ("Bruce Wayne", 10)); + + // Construct the serializer. + // + xml_schema::string_simpl string_s; + xml_schema::boolean_simpl boolean_s; + xml_schema::unsigned_int_simpl unsigned_int_s; + + person_simpl person_s; + superman_simpl superman_s; + batman_simpl batman_s; + + xml_schema::serializer_map_impl person_map (5); // 5 hashtable buckets + supermen_simpl supermen_s; + + person_s.serializers (string_s); + superman_s.serializers (string_s, boolean_s); + batman_s.serializers (string_s, boolean_s, unsigned_int_s); + + // Here we are specifying several serializers that can be + // used to serialize the person element. + // + person_map.insert (person_s); + person_map.insert (superman_s); + person_map.insert (batman_s); + + supermen_s.person_serializer (person_map); + + // Create the XML instance document. The last argument to the + // document's constructor indicates that we are serializing + // polymorphic XML documents. + // + xml_schema::document_simpl doc_s (supermen_s, "supermen", true); + + supermen_s.pre (sm); + doc_s.serialize (std::cout, xml_schema::document_simpl::pretty_print); + supermen_s.post (); +} + </pre> + + <p>When polymorphism-aware code is generated, each element's + <code>*_serializer()</code> function is overloaded to also accept + an object of the <code>xml_schema::serializer_map</code> type. + For example, the <code>supermen_sskel</code> class from the + above example looks like this:</p> + + <pre class="c++"> +class supermen_sskel: public xml_schema::serializer_complex_content +{ +public: + + ... + + // Serializer construction API. + // + void + serializers (person_sskel&); + + // Individual element serializers. + // + void + person_serializer (person_sskel&); + + void + person_serializer (xml_schema::serializer_map&); + + ... +}; + </pre> + + <p>Note that you can specify both the individual (static) serializer and + the serializer map. The individual serializer will be used when the static + element type and the dynamic type of the object being serialized are + the same. This is the case when the <code>type_id()</code> function + hasn't been called or the type information pointer is set to + <code>0</code>. Because the individual serializer for an element + is cached and no map lookup is necessary, it makes sense to specify + both the individual serializer and the serializer map when most of + the objects being serialized are of the static type and optimal + performance is important. The following code fragment shows how + to change the above example to set both the individual serializer + and the serializer map:</p> + + <pre class="c++"> +int +main () +{ + ... + + // Here we are specifying several serializers that can be + // used to serialize the person element. + // + person_map.insert (superman_s); + person_map.insert (batman_s); + + supermen_s.person_serializer (person_s); + supermen_s.person_serializer (person_map); + + ... +} + </pre> + + + <p>The <code>xml_schema::serializer_map</code> interface and its + default implementation, <code>xml_schema::serializer_map_impl</code>, + are presented below:</p> + + <pre class="c++"> +namespace xml_schema +{ + class serializer_map + { + public: + virtual serializer_base* + find (const void* type_id) const = 0; + + virtual void + reset () const = 0; + }; + + class serializer_map_impl: public serializer_map + { + public: + serializer_map_impl (size_t buckets); + + // Note that the type_id string is not copied so it should + // be valid for the lifetime of the map. + // + void + insert (const char* type_id, serializer_base&); + + // This version of insert is a shortcut that uses the string + // returned by the serializer's _dynamic_type() function. + // + void + insert (serializer_base&); + + virtual serializer_base* + find (const void* type_id) const; + + virtual void + reset () const; + + private: + serializer_map_impl (const serializer_map_impl&); + + serializer_map_impl& + operator= (const serializer_map_impl&); + + ... + }; +} + </pre> + + <p>The <code>type_id</code> argument in the <code>find()</code> virtual + function is the application-specific type information for the object + being serialized that is specified using the <code>type_id()</code> + function in the element callback. It is passed as an opaque + <code>const void*</code>. The <code>reset()</code> virtual function + is used to reset the serializers contained in the map (as opposed to + resetting or clearing the map itself). For more information on serializer + resetting refer to <a href="#8.4">Section 8.4, "Reusing Serializers + after an Error"</a>.</p> + + <p>The XSD/e runtime provides the default implementation for the + <code>xml_schema::serializer_map</code> interface, + <code>xml_schema::serializer_map_impl</code>, which uses a C string + (<code>const char*</code>) as type information. One way to + obtain a serializer's dynamic type in the form + <code>"<name> <namespace>"</code> with the space and the + namespace part absent if the type does not have a namespace + is to call the <code>_dynamic_type()</code> function on this + serializer. The static type can be obtained by calling the static + <code>_static_type()</code> function, for example + <code>person_sskel::_static_type()</code>. Both functions return + a C string (<code>const char*</code>) which is valid for as long + as the application is running.</p> + + <p>The default serializer map implementation is a hashmap. It requires + that you specify the number of buckets it will contain and it does + not support automatic table resizing. To obtain good performance the + elements to buckets ratio should be between 0.7 and 0.9. It is also + recommended to use prime numbers for bucket counts: + 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, + 196613, 393241. + </p> + + <p>If C++ exceptions are disabled (<a href="#5.3">Section 5.3, + "C++ Exceptions"</a>), the <code>xml_schema::serializer_map_impl</code> + class has the following additional error querying API. It can be used + to detect the out of memory errors after calls to the + <code>serializer_map_impl</code>'s constructor and <code>insert()</code> + functions.</p> + + <pre class="c++"> +namespace xml_schema +{ + class serializer_map_impl: public serializer_map + { + public: + enum error + { + error_none, + error_no_memory + }; + + error + _error () const; + + ... + }; +} + </pre> + + <p>You can also provide your own serializer map implementation which uses + custom type information. The following example shows how we can + implement our own serializer map for the above example that uses + the type information provided by the C++ object model:</p> + + <pre class="c++"> +#include <map> + +class person_serializer_map: public xml_schema::serializer_map +{ +public: + void + insert (person_sskel& p) + { + const char* dt = p._dynamic_type (); + type_id ti; + + if (strcmp (dt, person_sskel::_static_type ()) == 0) + ti = person_type; + else if (strcmp (dt, superman_sskel::_static_type ()) == 0) + ti = superman_type; + else if (strcmp (dt, batman_sskel::_static_type ()) == 0) + ti = batman_type; + else + return; + + map_[ti] = &p; + } + + virtual xml_schema::serializer_base* + find (const char* x) const + { + const person* p = static_cast<const person*> (x); + map::const_iterator i = map_.find (p->type ()); + return i != map_.end () ? i->second : 0; + } + + virtual void + reset () const + { + for (map::const_iterator i (map_.begin ()), e (map_.end ()); + i != e; ++i) + { + person_sskel* s = i->second; + s->_reset (); + } + } + +private: + typedef std::map<type_id, person_sskel*> map; + map map_; +}; + </pre> + + <p>Our custom implementation of the serializer map expects that + we pass the actual object to the <code>find()</code> function. + To account for this will need to change the + <code>supermen_simpl::person()</code> callback as follows:</p> + + <pre class="c++"> + virtual const ::person& + person () + { + const ::person& p = **i_++; + _context ().type_id (&p); + return p; + } + </pre> + + + <p>To support polymorphic serialization the XSD/e runtime and generated + code maintain a number of hashmaps that contain substitution and, if + XML Schema validation is enabled (<a href="#5.4">Section 5.4, + "XML Schema Validation"</a>), inheritance information. Because + the number of elements in these hashmaps depends on the schemas + being compiled and thus is fairly static, these hashmaps do not + perform automatic table resizing and instead the number of buckets + is specified when the XSD/e runtime is configured. To obtain good + performance the elements to buckets ratio in these hashmaps should + be between 0.7 and 0.9. The recommended way to ensure this range + is to add diagnostics code to your application as shown in the + following example:</p> + + <pre class="c++"> +int +main () +{ + // Check that the load in substitution and inheritance hashmaps + // is not too high. + // +#ifndef NDEBUG + float load = xml_schema::serializer_smap_elements (); + load /= xml_schema::serializer_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_SMAP_BUCKETS" << endl; + } + + load = xml_schema::serializer_smap_bucket_elements (); + load /= xml_schema::serializer_smap_bucket_buckets (); + + if (load > 0.8) + { + cerr << "substitution inner hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_SMAP_BUCKET_BUCKETS" << endl; + } + + load = xml_schema::serializer_imap_elements (); + load /= xml_schema::serializer_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_IMAP_BUCKETS" << endl; + } +#endif + + ... +} + </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/serializer/</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> + + <h2><a name="6.8">6.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> + + <h2><a name="6.9">6.9 A Minimal Example</a></h2> + + <p>The following example is a re-implementation of the person + records example presented in <a href="#4">Chapter 4, + "Type Maps"</a>. It is intended to work without STL, + iostream, and C++ exceptions. It can be found in the + <code>examples/cxx/serializer/minimal/</code> directory of the + XSD/e distribution. The <code>people.xsd</code> schema is + compiled with the <code>--no-stl</code>, <code>--no-iostream</code>, + and <code>--no-exceptions</code> options. The object model + types in <code>people.hxx</code> have also been reimplemented + in order not to use STL types:</p> + + <pre class="c++"> +#include <stddef.h> // size_t + +enum gender +{ + male, + female +}; + +struct person +{ + const char* first_name_; + const char* last_name_; + gender gender_; + unsigned short age_; +}; + +struct people +{ + person* people_; + size_t size_; +}; + </pre> + + + <p>The following listing presents the implementation of serializer + skeletons and the test driver in full:</p> + + <pre class="c++"> +#include <stdio.h> +#include "people-sskel.hxx" + +const char* gender_strings[] = {"male", "female"}; + +class gender_simpl: public gender_sskel +{ +public: + gender_simpl () + : gender_sskel (&base_impl_) + { + } + + virtual void + pre (gender g) + { + base_impl_.pre (gender_strings[g]); + } + +private: + public xml_schema::string_simpl base_impl_; +}; + +class person_simpl: public person_sskel +{ +public: + virtual void + pre (const person& p) + { + person_ = &p; + } + + virtual const char* + first_name () + { + return person_->first_name_; + } + + virtual const char* + last_name () + { + return person_->last_name_; + } + + virtual ::gender + gender () + { + return person_->gender_; + } + + virtual unsigned short + age () + { + return person_->age_; + } + +private: + const person* person_; +}; + +class people_simpl: public people_sskel +{ +public: + virtual void + pre (const people& p) + { + i_ = 0; + people_ = &p; + } + + virtual bool + person_next () + { + return i_ < people_->size_; + } + + virtual const ::person& + person () + { + return people_->people_[i_++]; + } + +private: + size_t i_; + const people* people_; +}; + +class writer: public xml_schema::writer +{ +public: + 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 () +{ + // Create a sample person list. + // + people p; + + p.size_ = 2; + p.people_ = new person[p.size_]; + + if (p.people_ == 0) + { + fprintf (stderr, "error: no memory\n"); + return 1; + } + + p.people_[0].first_name_ = "John"; + p.people_[0].last_name_ = "Doe"; + p.people_[0].gender_ = male; + p.people_[0].age_ = 32; + + p.people_[1].first_name_ = "Jane"; + p.people_[1].last_name_ = "Doe"; + p.people_[1].gender_ = female; + p.people_[1].age_ = 28; + + // Construct the serializer. + // + xml_schema::unsigned_short_simpl unsigned_short_s; + xml_schema::string_simpl string_s; + + gender_simpl gender_s; + person_simpl person_s; + people_simpl people_s; + + person_s.serializers (string_s, string_s, gender_s, unsigned_short_s); + people_s.serializers (person_s); + + // Serialize. + // + typedef xml_schema::serializer_error error; + + error e; + writer w; + + do + { + xml_schema::document_simpl doc_s (people_s, "people"); + + if (e = doc_s._error ()) + break; + + people_s.pre (p); + + if (e = people_s._error ()) + break; + + doc_s.serialize (w, xml_schema::document_simpl::pretty_print); + + if (e = doc_s._error ()) + break; + + people_s.post (); + + e = people_s._error (); + + } while (false); + + delete[] p.people_; + + // Handle errors. + // + if (e) + { + switch (e.type ()) + { + case error::sys: + { + fprintf (stderr, "error: %s\n", e.sys_text ()); + break; + } + case error::xml: + { + fprintf (stderr, "error: %s\n", e.xml_text ()); + break; + } + case error::schema: + { + fprintf (stderr, "error: %s\n", e.schema_text ()); + break; + } + case error::app: + { + fprintf (stderr, "application error: %d\n", e.app_code ()); + break; + } + default: + break; + } + + return 1; + } + + return 0; +} + </pre> + + + <!-- Built-in XML Schema Type Serializers --> + + + <h1><a name="7">7 Built-In XML Schema Type Serializers</a></h1> + + <p>The XSD/e runtime provides serializer implementations for all built-in + XML Schema types as summarized in the following table. Declarations + for these types are automatically included into each generated + header file. As a result you don't need to include any headers + to gain access to these serializer implementations.</p> + + <!-- border="1" is necessary for html2ps --> + <table id="builtin" border="1"> + <tr> + <th>XML Schema type</th> + <th>Serializer implementation in the <code>xml_schema</code> namespace</th> + <th>Serializer argument type</th> + </tr> + + <tr> + <th colspan="3">anyType and anySimpleType types</th> + </tr> + <tr> + <td><code>anyType</code></td> + <td><code>any_type_simpl</code></td> + <td><code>void</code></td> + </tr> + <tr> + <td><code>anySimpleType</code></td> + <td><code>any_simple_type_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">fixed-length integral types</th> + </tr> + <!-- 8-bit --> + <tr> + <td><code>byte</code></td> + <td><code>byte_simpl</code></td> + <td><code>signed char</code></td> + </tr> + <tr> + <td><code>unsignedByte</code></td> + <td><code>unsigned_byte_simpl</code></td> + <td><code>unsigned char</code></td> + </tr> + + <!-- 16-bit --> + <tr> + <td><code>short</code></td> + <td><code>short_simpl</code></td> + <td><code>short</code></td> + </tr> + <tr> + <td><code>unsignedShort</code></td> + <td><code>unsigned_short_simpl</code></td> + <td><code>unsigned short</code></td> + </tr> + + <!-- 32-bit --> + <tr> + <td><code>int</code></td> + <td><code>int_simpl</code></td> + <td><code>int</code></td> + </tr> + <tr> + <td><code>unsignedInt</code></td> + <td><code>unsigned_int_simpl</code></td> + <td><code>unsigned int</code></td> + </tr> + + <!-- 64-bit --> + <tr> + <td><code>long</code></td> + <td><code>long_simpl</code></td> + <td><code>long long</code> or <code>long</code><br/> + <a href="#6.5">Section 6.5, "64-bit Integer Type"</a></td> + </tr> + <tr> + <td><code>unsignedLong</code></td> + <td><code>unsigned_long_simpl</code></td> + <td><code>unsigned long long</code> or + <code>unsigned long</code><br/> + <a href="#6.5">Section 6.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_simpl</code></td> + <td><code>long</code></td> + </tr> + <tr> + <td><code>nonPositiveInteger</code></td> + <td><code>non_positive_integer_simpl</code></td> + <td><code>long</code></td> + </tr> + <tr> + <td><code>nonNegativeInteger</code></td> + <td><code>non_negative_integer_simpl</code></td> + <td><code>unsigned long</code></td> + </tr> + <tr> + <td><code>positiveInteger</code></td> + <td><code>positive_integer_simpl</code></td> + <td><code>unsigned long</code></td> + </tr> + <tr> + <td><code>negativeInteger</code></td> + <td><code>negative_integer_simpl</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_simpl</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_simpl</code></td> + <td><code>float</code><br/> + <a href="#7.1">Section 7.1, "Floating-Point Type Serializers"</a></td> + </tr> + <tr> + <td><code>double</code></td> + <td><code>double_simpl</code></td> + <td><code>double</code><br/> + <a href="#7.1">Section 7.1, "Floating-Point Type Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">arbitrary-precision floating-point types</th> + </tr> + <tr> + <td><code>decimal</code></td> + <td><code>decimal_simpl</code></td> + <td><code>double</code><br/> + <a href="#7.1">Section 7.1, "Floating-Point Type Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">string-based types</th> + </tr> + <tr> + <td><code>string</code></td> + <td><code>string_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + <tr> + <td><code>normalizedString</code></td> + <td><code>normalized_string_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + <tr> + <td><code>token</code></td> + <td><code>token_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + <tr> + <td><code>Name</code></td> + <td><code>name_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + <tr> + <td><code>NMTOKEN</code></td> + <td><code>nmtoken_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + <tr> + <td><code>NCName</code></td> + <td><code>ncname_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + + <tr> + <td><code>language</code></td> + <td><code>language_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">qualified name</th> + </tr> + <tr> + <td><code>QName</code></td> + <td><code>qname_simpl</code></td> + <td><code>const xml_schema::qname&</code> or<br/> + <code>const xml_schema::qname*</code><br/> + <a href="#7.3">Section 7.3, "<code>QName</code> Serializer"</a></td> + </tr> + + <tr> + <th colspan="3">ID/IDREF types</th> + </tr> + <tr> + <td><code>ID</code></td> + <td><code>id_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + <tr> + <td><code>IDREF</code></td> + <td><code>idref_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">list types</th> + </tr> + <tr> + <td><code>NMTOKENS</code></td> + <td><code>nmtokens_simpl</code></td> + <td><code>const xml_schema::string_sequence*</code><br/><a href="#7.4">Section + 7.4, "<code>NMTOKENS</code> and <code>IDREFS</code> Serializers"</a></td> + </tr> + <tr> + <td><code>IDREFS</code></td> + <td><code>idrefs_simpl</code></td> + <td><code>const xml_schema::string_sequence*</code><br/><a href="#7.4">Section + 7.4, "<code>NMTOKENS</code> and <code>IDREFS</code> Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">URI types</th> + </tr> + <tr> + <td><code>anyURI</code></td> + <td><code>uri_simpl</code></td> + <td><code>const std::string&</code> or<br/> <code>const char*</code><br/> + <a href="#7.2">Section 7.2, "String-Based Type Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">binary types</th> + </tr> + <tr> + <td><code>base64Binary</code></td> + <td><code>base64_binary_simpl</code></td> + <td><code>const xml_schema::buffer*</code><br/> + <a href="#7.5">Section 7.5, "<code>base64Binary</code> and + <code>hexBinary</code> Serializers"</a></td> + </tr> + <tr> + <td><code>hexBinary</code></td> + <td><code>hex_binary_simpl</code></td> + <td><code>const xml_schema::buffer*</code><br/> + <a href="#7.5">Section 7.5, "<code>base64Binary</code> and + <code>hexBinary</code> Serializers"</a></td> + </tr> + + <tr> + <th colspan="3">date/time types</th> + </tr> + <tr> + <td><code>date</code></td> + <td><code>date_simpl</code></td> + <td><code>const xml_schema::date&</code><br/> + <a href="#7.7">Section 7.7, "<code>date</code> Serializer"</a></td> + </tr> + <tr> + <td><code>dateTime</code></td> + <td><code>date_time_simpl</code></td> + <td><code>const xml_schema::date_time&</code><br/> + <a href="#7.8">Section 7.8, "<code>dateTime</code> Serializer"</a></td> + </tr> + <tr> + <td><code>duration</code></td> + <td><code>duration_simpl</code></td> + <td><code>const xml_schema::duration&</code><br/> + <a href="#7.9">Section 7.9, "<code>duration</code> Serializer"</a></td> + </tr> + <tr> + <td><code>gDay</code></td> + <td><code>gday_simpl</code></td> + <td><code>const xml_schema::gday&</code><br/> + <a href="#7.10">Section 7.10, "<code>gDay</code> Serializer"</a></td> + </tr> + <tr> + <td><code>gMonth</code></td> + <td><code>gmonth_simpl</code></td> + <td><code>const xml_schema::gmonth&</code><br/> + <a href="#7.11">Section 7.11, "<code>gMonth</code> Serializer"</a></td> + </tr> + <tr> + <td><code>gMonthDay</code></td> + <td><code>gmonth_day_simpl</code></td> + <td><code>const xml_schema::gmonth_day&</code><br/> + <a href="#7.12">Section 7.12, "<code>gMonthDay</code> Serializer"</a></td> + </tr> + <tr> + <td><code>gYear</code></td> + <td><code>gyear_simpl</code></td> + <td><code>const xml_schema::gyear&</code><br/> + <a href="#7.13">Section 7.13, "<code>gYear</code> Serializer"</a></td> + </tr> + <tr> + <td><code>gYearMonth</code></td> + <td><code>gyear_month_simpl</code></td> + <td><code>const xml_schema::gyear_month&</code><br/> + <a href="#7.14">Section 7.14, "<code>gYearMonth</code> Serializer"</a></td> + </tr> + <tr> + <td><code>time</code></td> + <td><code>time_simpl</code></td> + <td><code>const xml_schema::time&</code><br/> + <a href="#7.15">Section 7.15, "<code>time</code> Serializer"</a></td> + </tr> + + </table> + + <h2><a name="7.1">7.1 Floating-Point Type Serializers</a></h2> + + <p>The serializer implementations for the <code>float</code>, + <code>double</code>, and <code>decimal</code> built-in + XML Schema types allow you to specify the resulting + notation (fixed or scientific) as well as precision. + This is done by passing the corresponding arguments + to their constructors:</p> + + <pre class="c++"> +namespace xml_schema +{ + class float_simpl: public float_sskel + { + enum notation + { + notation_auto, + notation_fixed, + notation_scientific + }; + + float_simpl (notation = notation_auto, + unsigned int precision = FLT_DIG); + + virtual void + pre (float); + + ... + }; + + class double_simpl: public double_sskel + { + enum notation + { + notation_auto, + notation_fixed, + notation_scientific + }; + + double_simpl (notation = notation_auto, + unsigned int precision = DBL_DIG); + + virtual void + pre (double); + + ... + }; + + class decimal_simpl: public decimal_sskel + { + decimal_simpl (unsigned int precision = DBL_DIG); + + virtual void + pre (double); + + ... + }; +} + </pre> + + <p>By default the notation for the <code>float</code> and <code>double</code> + types is automatically selected to produce the shortest representation. + Note that the <code>decimal</code> values are always serialized in + the fixed-point notation.</p> + + <h2><a name="7.2">7.2 String-Based Type Serializers</a></h2> + + <p>When STL is enabled (<a href="#6.1">Section 6.1, "Standard Template + Library"</a>), the serializer argument type for the <code>string</code>, + <code>normalizedString</code>, <code>token</code>, + <code>Name</code>, <code>NMTOKEN</code>, <code>NCName</code>, + <code>ID</code>, <code>IDREF</code>, <code>language</code>, + <code>anyURI</code>, and <code>anySimpleType</code> built-in XML Schema + types is + <code>const std::string&</code>. When STL is disabled, the value + is passed as a constant C-string: <code>const char*</code>. + In this case, you can also instruct the serializer + implementations for string-based types to release the + string with operator <code>delete[]</code> by passing + <code>true</code> to their constructors. For instance, + using the person records example from the previous chapter:</p> + + <pre class="c++"> +class person_simpl: public person_sskel +{ +public: + virtual const char* + first_name () + { + char* r = new char[5]; + strcpy (r, "John"); + return r; + } + + virtual const char* + last_name () + { + char* r = new char[4]; + strcpy (r, "Doe"); + return r; + } + + ... +}; + +int +main () +{ + // Construct the serializer. + // + xml_schema::unsigned_short_simpl unsigned_short_s; + xml_schema::string_simpl string_s (true); // Release the string passed. + + gender_simpl gender_s; + person_simpl person_s; + people_simpl people_s; + + person_s.serializers (string_s, string_s, gender_s, unsigned_short_s); + + ... +} + </pre> + + <h2><a name="7.3">7.3 <code>QName</code> Serializer</a></h2> + + <p>The argument type of the <code>qname_simpl</code> serializer + implementation is either <code>const xml_schema::qname&</code> + when STL is enabled (<a href="#6.1">Section 6.1, "Standard Template + Library"</a>) or <code>const xml_schema::qname*</code> when STL + is disabled. The <code>qname</code> class represents an XML + qualified name. When the argument type is <code>const + xml_schema::qname*</code>, you can optionally instruct the + serializer to release the <code>qname</code> object with operator + <code>delete</code> by passing <code>true</code> to its + constructor.</p> + + <p>With STL enabled, 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 (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="#6.3">Section 6.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="7.4">7.4 <code>NMTOKENS</code> and <code>IDREFS</code> Serializers</a></h2> + + <p>The argument type of the <code>nmtokens_simpl</code> and + <code>idrefs_simpl</code> serializer implementations is + <code>const xml_schema::string_sequence*</code>. You can + optionally instruct these serializers to release the + <code>string_sequence</code> object with operator <code>delete</code> + by passing <code>true</code> to their constructors. With STL and C++ exceptions enabled + (<a href="#6.1">Section 6.1, "Standard Template Library"</a>, + <a href="#6.3">Section 6.3, "C++ Exceptions"</a>), the + <code>string_sequence</code> type has the following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class string_sequence + { + public: + typedef std::string value_type; + typedef std::string* pointer; + typedef const std::string* const_pointer; + typedef std::string& reference; + typedef const std::string& const_reference; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef std::string* iterator; + typedef const std::string* const_iterator; + + public: + 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; + + std::string& + front (); + + const std::string& + front () const; + + std::string& + back (); + + const std::string& + back () const; + + std::string& + operator[] (size_t); + + const std::string& + 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 std::string&); + + iterator + insert (iterator, const std::string&); + + void + reserve (size_t); + }; + + bool + operator== (const string_sequence&, const string_sequence&); + + bool + operator!= (const string_sequence&, const string_sequence&); +} + </pre> + + <p>When STL is enabled and C++ exceptions are disabled, the signatures + of the <code>push_back()</code>, <code>insert()</code>, and + <code>reserve()</code> functions 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 (const std::string&); + + error + insert (iterator, const std::string&); + + error + insert (iterator, const std::string&, iterator& result); + + error + reserve (size_t); + }; +} + </pre> + + <p>When STL is disabled and C++ exceptions are enabled, the + <code>string_sequence</code> type has the following interface:</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); + + // Detach a string from the sequence at a given position. + // The string pointer at this position in the sequence is + // set to 0. + // + char* + detach (iterator); + }; + + bool + operator== (const string_sequence&, const string_sequence&); + + bool + operator!= (const string_sequence&, const string_sequence&); +} + </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 char[]</code> and will be deallocated + with operator <code>delete[]</code> by the <code>string_sequence</code> + object. These two functions free the passed object if the reallocation + of the underlying sequence buffer fails. The <code>push_back_copy()</code> + function makes a copy of the passed string. + If you detach the underlying element string, then it should + eventually be deallocated with operator <code>delete[]</code>.</p> + + <p>When both STL and 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 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="7.5">7.5 <code>base64Binary</code> and <code>hexBinary</code> Serializers</a></h2> + + <p>The argument type of the <code>base64_binary_simpl</code> and + <code>hex_binary_simpl</code> serializer implementations is + <code>const xml_schema::buffer*</code>. You can optionally + instruct these serializers to release the <code>buffer</code> + object with operator <code>delete</code> by passing <code>true</code> + to their constructors. With C++ exceptions enabled (<a href="#6.3">Section + 6.3, "C++ Exceptions"</a>), the <code>buffer</code> type 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 + 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> type 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 + 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="7.6">7.6 Time Zone Representation</a></h2> + + <p>The <code>date</code>, <code>dateTime</code>, <code>gDay</code>, + <code>gMonth</code>, <code>gMonthDay</code>, <code>gYear</code>, + <code>gYearMonth</code>, and <code>time</code> XML Schema built-in + types all include an optional time zone component. The following + <code>xml_schema::time_zone</code> base class is used to represent + this information:</p> + + <pre class="c++"> +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 <em>not specified</em> + state. If the time zone offset is negative then both hours and + minutes components are represented as negative integers.</p> + + <h2><a name="7.7">7.7 <code>date</code> Serializer</a></h2> + + <p>The argument type of the <code>date_simpl</code> serializer implementation + is <code>const xml_schema::date&</code>. The <code>date</code> class + 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="#7.6">Section + 7.6, "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="7.8">7.8 <code>dateTime</code> Serializer</a></h2> + + <p>The argument type of the <code>date_time_simpl</code> serializer + implementation is <code>const xml_schema::date_time&</code>. + The <code>date_time</code> class 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="#7.6">Section + 7.6, "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="7.9">7.9 <code>duration</code> Serializer</a></h2> + + <p>The argument type of the <code>duration_simpl</code> serializer + implementation is <code>const xml_schema::duration&</code>. + The <code>duration</code> class 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="7.10">7.10 <code>gDay</code> Serializer</a></h2> + + <p>The argument type of the <code>gday_simpl</code> serializer + implementation is <code>const xml_schema::gday&</code> The + <code>gday</code> class 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="#7.6">Section 7.6, "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="7.11">7.11 <code>gMonth</code> Serializer</a></h2> + + <p>The argument type of the <code>gmonth_simpl</code> serializer + implementation is <code>const xml_schema::gmonth&</code>. The + <code>gmonth</code> class 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="#7.6">Section 7.6, "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="7.12">7.12 <code>gMonthDay</code> Serializer</a></h2> + + <p>The argument type of the <code>gmonth_day_simpl</code> serializer + implementation is <code>const xml_schema::gmonth_day&</code>. + The <code>gmonth_day</code> class 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="#7.6">Section 7.6, "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="7.13">7.13 <code>gYear</code> Serializer</a></h2> + + <p>The argument type of the <code>gyear_simpl</code> serializer + implementation is <code>const xml_schema::gyear&</code>. The + <code>gyear</code> class 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="#7.6">Section 7.6, "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="7.14">7.14 <code>gYearMonth</code> Serializer</a></h2> + + <p>The argument type of the <code>gyear_month_simpl</code> serializer + implementation is <code>const xml_schema::gyear_month&</code>. + The <code>gyear_month</code> class 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="#7.6">Section 7.6, "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="7.15">7.15 <code>time</code> Serializer</a></h2> + + <p>The argument type of the <code>time_simpl</code> serializer implementation + is <code>const xml_schema::time&</code>. The <code>time</code> class + 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="#7.6">Section + 7.6, "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> + + + <!-- Error Handling --> + + + <h1><a name="8">8 Document Serializer and Error Handling</a></h1> + + <p>In this chapter we will discuss the <code>xml_schema::document_simpl</code> + type, the error handling mechanisms provided by the mapping, as well as + how to reuse a serializer after an error has occurred.</p> + + <p>There are four categories of errors that can result from running + a serializer to produce an XML instance: system, xml, schema, and + application. The system category contains memory allocation and + input/output operation errors. The xml category is for XML serialization + and well-formedness checking errors. Similarly, the schema category is + for XML Schema validation errors. Finally, the application category + is for application logic errors that you may want to propagate + from serializer implementations to the caller of the serializer. + </p> + + <p>The C++/Serializer mapping supports two methods of reporting errors: + using C++ exceptions and with error codes. The method used depends + on whether or not you have configured the XSD/e runtime and + the generated code with C++ exceptions enabled, as described + in <a href="#6.3">Section 6.3, "C++ Exceptions"</a>.</p> + + <h2><a name="8.1">8.1 Document Serializer</a></h2> + + <p>The <code>xml_schema::document_simpl</code> serializer is a root + serializer for the vocabulary. As mentioned in <a href="#3.4">Section + 3.4, "Connecting the Serializer Together"</a>, its interface varies + depending on the mapping configuration (<a href="#6">Chapter 6, "Mapping + Configuration"</a>). When STL, C++ exceptions, and the iostream library + are enabled, the <code>xml_schema::document_simpl</code> class has the + following interface:</p> + + <pre class="c++"> +namespace xml_schema +{ + class serializer_base; + + class writer + { + public: + // The first write function is called to write a '\0'-terminated + // string. Its default implementation calls the second versions: + // write (s, strlen (s)). These functions use exceptions to + // indicate a write failure. + // + virtual void + write (const char* s); + + virtual void + write (const char* s, size_t n) = 0; + + virtual void + flush () = 0; + }; + + class document_simpl + { + public: + document_simpl (serializer_base&, + const char* root_element_name); + + document_simpl (serializer_base&, + const char* root_element_namespace, + const char* root_element_name); + + document_simpl (serializer_base&, + const std::string& root_element_name); + + document_simpl (serializer_base&, + const std::string& root_element_namespace, + const std::string& root_element_name); + + public: + void + add_prefix (const char* prefix, const char* namespace_); + + void + add_default_prefix (const char* namespace_); + + void + add_schema (const char* namespace_, const char* location); + + void + add_no_namespace_schema (const char* location); + + void + add_prefix (const std::string& prefix, + const std::string& namespace_); + + void + add_default_prefix (const std::string& namespace_); + + void + add_schema (const std::string& namespace_, + const std::string& location); + + void + add_no_namespace_schema (const std::string& location); + + public: + // Serialization flags. + // + typedef unsigned short flags; + + static const flags pretty_print; + + public: + // Serialize to std::ostream. The std::ios_base::failure + // exception is used to report io errors (badbit and failbit) + // if C++ exceptions are enabled. Otherwise error codes are + // used. + // + void + serialize (std::ostream&, flags = 0); + + public: + // Serialize by calling writer::write() and writer::flush() to + // output XML. + // + void + serialize (writer&, flags = 0); + + // Serialize by calling the write and flush functions. If the + // unbounded write function is not provided, the bounded version + // is called: write_bound_func (s, strlen (s)). user_data is + // passed as a first argument to these functions. These functions + // use exceptions to indicate a write failure. + // + typedef void (*write_func) (void*, const char*); + typedef void (*write_bound_func) (void*, const char*, size_t); + typedef void (*flush_func) (void*); + + void + serialize (write_bound_func, + flush_func, + void* user_data, + flags = 0); + + void + serialize (write_func, + write_bound_func, + flush_func, + void* user_data, + flags = 0); + public: + // Low-level, genx-specific serialization. With this method + // it is your responsibility to call genxStartDoc*() and + // genxEndDocument(). + // + void + serialize (genxWriter); + }; +} + </pre> + + <p>When the use of STL is disabled, the constructors, as well as + the <code>add_prefix()</code> and <code>add_schema()</code> + functions that use <code>std::string</code> in their signatures + are not available. When the use of iostream is disabled, the + <code>serialize()</code> functions that serializes to + <code>std::ostream</code> is not available.</p> + + <p>When C++ exceptions are disabled, the <code>write()</code> and + <code>flush()</code> virtual functions in the <code>writer</code> + interface as well as <code>write_func</code>, + <code>write_bound_func</code>, and <code>flush_func</code> + function pointers use <code>bool</code> return type + for error reporting. These functions should return <code>true</code> + if the operation was successful and <code>false</code> otherwise. + The relevant parts in the <code>writer</code> and + <code>document_simpl</code> interfaces change as follows:</p> + + <pre class="c++"> +namespace xml_schema +{ + class serializer_base; + + class writer + { + public: + // The first write function is called to write a '\0'-terminated + // string. Its default implementation calls the second versions: + // write (s, strlen (s)). These functions return true if the + // operation was successful and false otherwise. + // + // indicate a write failure. + // + virtual bool + write (const char* s); + + virtual bool + write (const char* s, size_t n) = 0; + + virtual bool + flush () = 0; + }; + + class document_simpl + { + ... + + // Serialize by calling the write and flush functions. If the + // unbounded write function is not provided, the bounded version + // is called: write_bound_func (s, strlen (s)). user_data is + // passed as a first argument to these functions. These functions + // return true if the operation was successful and false otherwise. + // + typedef bool (*write_func) (void*, const char*); + typedef bool (*write_bound_func) (void*, const char*, size_t); + typedef bool (*flush_func) (void*); + + ... + + public: + const serializer_error& + _error () const; + }; +} + </pre> + + <p>For more information on error handling with C++ exceptions and + error codes see <a href="#8.2">Section 8.2, "Exceptions"</a> + and <a href="#8.3">Section 8.3, "Error Codes"</a> below.</p> + + <p>When support for XML Schema polymorphism is enabled, the + overloaded <code>document_simpl</code> constructors have + additional arguments which control polymorphic serialization. + For more information refer to <a href="#6.7">Section 6.7, + "Support for Polymorphism"</a>. + </p> + + <p>The first argument to all overloaded constructors is the + serializer for the type of the root element. The + <code>serializer_base</code> class is the base type for all + serializer skeletons. The second and third arguments to the + <code>document_simpl</code>'s constructors are the root element's + name and namespace.</p> + + <p>The <code>add_prefix()</code> and <code>add_default_prefix()</code> + functions allow you to establish custom prefixes for XML + namespaces. If none is provided, and namespaces are used + by your vocabulary, the serializer will automatically + assign namespace prefixes in an implementation-specific + manner. For example:</p> + + <pre class="c++"> +xml_schema::document_simpl doc_s ( + root_s, + "http://www.example.com/example", + "root"); + +doc_s.add_prefix ("ex", "http://www.example.com/example"); + </pre> + + <p>The resulting XML will have the following namespace declaration:</p> + + <pre class="xml"> +<ex:root xmlns:ex="http://www.example.com/example" ...> + ... +</ex:root> + </pre> + + <p>Similarly, the <code>add_schema()</code> and + <code>add_no_namespace_schema()</code> functions allow you to embed + schema location information for a particular namespace into resulting + XML. The schema location information is placed into the + <code>xsi:schemaLocation</code> and + <code>xsi:noNamespaceSchemaLocation</code> attributes. For example:</p> + + <pre class="c++"> +xml_schema::document_simpl doc_s ( + root_s, + "http://www.example.com/example", + "root"); + +doc_s.add_prefix ("ex", "http://www.example.com/example"); +doc_s.add_schema ("http://www.example.com/example", "example.xsd"); + </pre> + + <p>The resulting XML will have the following namespace declaration:</p> + + <pre class="xml"> +<ex:root + xmlns:ex="http://www.example.com/example" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.example.com/example example.xsd" ...> + ... +</ex:root> + </pre> + + <h2><a name="8.2">8.2 Exceptions</a></h2> + + <p>When C++ exceptions are used for error reporting, the system + errors are mapped to the standard exceptions. The out of memory + condition is indicated by throwing an instance + of <code>std::bad_alloc</code>. The stream operation errors + are reported by throwing an instance of + <code>std::ios_base::failure</code>.</p> + + <p>The xml and schema errors are reported by throwing the + <code>xml_schema::serializer_xml</code> and + <code>xml_schema::serializer_schema</code> + exceptions, respectively. These two exceptions derive from + <code>xml_schema::serializer_exception</code> which, in turn, derives + from <code>std::exception</code>. As a result, you can handle + any error from these two categories by either catching + <code>std::exception</code>, <code>xml_schema::serializer_exception</code>, + or individual exceptions. The further down the hierarchy you go + the more detailed error information is available to you. The + following listing shows the definitions of these exceptions:</p> + + <pre class="c++"> +namespace xml_schema +{ + class serializer_exception: public std::exception + { + public: + virtual const char* + text () const = 0; + + ... + }; + + std::ostream& + operator<< (std::ostream&, const serializer_exception&); + + + typedef <implementation-details> serializer_xml_error; + + class serializer_xml: public serializer_exception + { + public: + serializer_xml_error + code () const; + + virtual const char* + text () const; + + virtual const char* + what () const throw (); + + ... + }; + + + typedef <implementation-details> serializer_schema_error; + + class serializer_schema: public serializer_exception + { + public: + serializer_schema_error + code () const; + + virtual const char* + text () const; + + virtual const char* + what () const throw (); + + ... + }; +} + </pre> + + <p>The <code>serializer_xml_error</code> and + <code>serializer_schema_error</code> are implementation-specific error + code types. The <code>operator<<</code> defined for the + <code>serializer_exception</code> class simply prints the error + description as returned by the <code>text()</code> function. The + following example shows how we can catch these exceptions:</p> + + <pre class="c++"> +int +main () +{ + try + { + // Serialize. + } + catch (const xml_schema::serializer_exception& e) + { + cout << "error: " << e.text () << endl; + return 1; + } +} + </pre> + + <p>Finally, for reporting application errors from serializer callbacks, + you can throw any exceptions of your choice. They are propagated + to the caller of the serializer without any alterations.</p> + + <h2><a name="8.3">8.3 Error Codes</a></h2> + + <p>When C++ exceptions are not available, error codes are used to + report error conditions. Each serializer skeleton and the root + <code>document_simpl</code> serializer have the following member + function for querying the error status:</p> + + <pre class="c++"> +xml_schema::serializer_error +_error () const; + </pre> + + <p>To handle all possible error conditions, you will need to obtain + the error status after calls to: the <code>document_simpl</code>'s + constructor (it performs memory allocations which may fail), + calls to <code>add_prefix()</code> and <code>add_schema()</code> + functions if any, the call to the root serializer <code>pre()</code> + callback, the call to the <code>serialize()</code> function, and, + finally, the call to the root serializer <code>post()</code> callback. + The definition of <code>xml_schema::serializer_error</code> class + is presented below:</p> + + <pre class="c++"> +namespace xml_schema +{ + class sys_error + { + public: + enum value + { + none, + no_memory, + open_failed, + read_failed, + write_failed + }; + + sys_error (value); + + operator value () const; + + static const char* + text (value); + + ... + }; + + typedef <implementation-details> serializer_xml_error; + typedef <implementation-details> serializer_schema_error; + + class serializer_error + { + public: + enum error_type + { + none, + sys, + xml, + schema, + app + }; + + error_type + type () const; + + // Returns true if there is an error so that you can write + // if (s.error ()) or if (error e = s.error ()). + // + typedef void (error::*bool_convertible) (); + operator bool_convertible () const; + + // system + // + sys_error + sys_code () const; + + const char* + sys_text () const; + + // xml + // + serializer_xml_error + xml_code () const; + + const char* + xml_text () const; + + // schema + // + serializer_schema_error + schema_code () const; + + const char* + schema_text () const; + + // app + // + int + app_code () const; + + ... + }; +} + </pre> + + <p>The <code>serializer_xml_error</code> and + <code>serializer_schema_error</code> are implementation-specific + error code types. The <code>serializer_error</code> class incorporates + four categories of errors which you can query by calling the + <code>type()</code> function. The following example shows how to + handle error conditions with error codes. It is based on the + person record example presented in <a href="#3">Chapter 3, "Serializer + Skeletons"</a>.</p> + + <pre class="c++"> +int +main () +{ + // Construct the serializer. + // + xml_schema::short_simpl short_s; + xml_schema::string_simpl string_s; + + gender_simpl gender_s; + person_simpl person_s; + people_simpl people_s; + + person_s.serializers (string_s, string_s, gender_s, short_s); + people_s.serializers (person_s); + + // Serialize. + // + using xml_schema::serializer_error; + serializer_error e; + + do + { + xml_schema::document_simpl doc_s (people_s, "people"); + if (e = doc_s._error ()) + break; + + people_s.pre (); + if (e = people_s._error ()) + break; + + doc_s.serialize (cout); + if (e = doc_s._error ()) + break; + + people_s.post (); + e = people_s._error (); + + } while (false); + + // Handle errors. + // + if (e) + { + switch (e.type ()) + { + case serializer_error::sys: + { + cerr << "system error: " << e.sys_text () << endl; + break; + } + case serializer_error::xml: + { + cerr << "xml error: " << e.xml_text () << endl; + break; + } + case serializer_error::schema: + { + cerr << "schema error: " << e.schema_text () << endl; + break; + } + case serializer_error::app: + { + cerr << "application error: " << e.app_code () << endl; + break; + } + } + return 1; + } +} + </pre> + + <p>The error type for application errors is <code>int</code> with + the value <code>0</code> indicated the absence of error. You can + set the application error by calling the <code>_app_error()</code> + function inside a serializer callback. For example, if it was invalid + to have a person younger than 18 in our people catalog, then we + could have implemented this check as follows: </p> + + <pre class="c++"> +class person_simpl: public person_sskel +{ +public: + virtual short + age () + { + short a = ...; + + if (a < 18) + _app_error (1); + + return a; + } +}; + </pre> + + <p>You can also set a system error by calling the <code>_sys_error()</code> + function inside a serializer callback. This function has one argument of + type <code>xml_schema::sys_error</code> which was presented above. + For example:</p> + + <pre class="c++"> +class person_simpl: public person_sskel +{ +public: + virtual const char* + first_name () + { + char* r = new char[5]; + + if (r == 0) + { + _sys_error (xml_schema::sys_error::no_memory); + return 0; + } + + strcpy (r, "John"); + return r; + } +}; + </pre> + + <h2><a name="8.4">8.4 Reusing Serializers after an Error</a></h2> + + <p>After a successful execution a serializer returns into the initial + state and can be used to serialize another document without any + extra actions. On the other hand, if an error occurred during + serialization and you would like to reuse the serializer to serialize another + document, you need to explicitly reset it into the initial + state as shown in the following code fragment:</p> + + <pre class="c++"> +int +main () +{ + ... + + xml_schema::document_simpl doc_s (people_s, "people"); + + for (size_t i = 0; i < 4; ++i) + { + try + { + people_s.pre (); + doc_s.serialize (cout); + people_s.post (); + } + catch (const xml_schema::serializer_exception&) + { + doc_s.reset (); + } + } +} + </pre> + + <p>If you do not need to reuse serializers after an error for example + because your application terminates or you create a new serializer + instance in such situations, then you can avoid generating + serializer reset code by specifying the <code>--suppress-reset</code> + XSD/e compiler option.</p> + + <p>Your individual serializer implementations may also require extra + actions in order to bring them into a usable state after an + error. To accomplish this you can override the <code>_reset()</code> + virtual function as shown below. Notice that when you override the + <code>_reset()</code> function in your implementation, you should + always call the base skeleton version to allow it to reset + its state:</p> + +<pre class="c++"> +class person_simpl: public person_sskel +{ +public: + virtual void + pre (person* p) + { + p_ = p; + } + + virtual void + post () + { + delete p_; + p_ = 0; + } + + virtual void + _reset () + { + person_sskel::_reset (); + delete p_; + p_ = 0; + } + + ... + +private: + person* p_; +}; + </pre> + + <p>Note also that the <code>_reset()</code> mechanism is used only when + an error has occurred. To make sure that your serializer implementations + arrive at the initial state during successful execution, use the + initialization (<code>pre()</code> and <code>_pre()</code>) and + finalization (<code>post_*()</code> and <code>_post()</code>) + callbacks.</p> + + + <!-- Appendix A --> + + + <h1><a name="A">Appendix A — Supported XML Schema Constructs</a></h1> + + <p>The Embedded C++/Serializer mapping supports validation of the following + W3C XML Schema constructs in the generated code.</p> + + <!-- border="1" is necessary for html2ps --> + <table id="features" border="1"> + <tr><th>Construct</th><th>Notes</th></tr> + <tr><th colspan="2">Structure</th></tr> + + <tr><td>element</td><td></td></tr> + <tr><td>attribute</td><td></td></tr> + + <tr><td>any</td><td></td></tr> + <tr><td>anyAttribute</td><td></td></tr> + + <tr><td>all</td><td></td></tr> + <tr><td>sequence</td><td></td></tr> + <tr><td>choice</td><td></td></tr> + + <tr><td>complex type, empty content</td><td></td></tr> + <tr><td>complex type, mixed content</td><td></td></tr> + <tr><td>complex type, simple content extension</td><td></td></tr> + <tr><td>complex type, simple content restriction</td><td></td></tr> + <tr><td>complex type, complex content extension</td><td></td></tr> + <tr><td>complex type, complex content restriction</td><td></td></tr> + + <tr><td>list</td><td></td></tr> + + <tr><th colspan="2">Facets</th></tr> + + <tr><td>length</td><td>String-based types.</td></tr> + <tr><td>minLength</td><td>String-based types.</td></tr> + <tr><td>maxLength</td><td>String-based types.</td></tr> + <tr><td>pattern</td><td>String-based types.</td></tr> + <tr><td>enumeration</td><td>String-based types.</td></tr> + + <tr><td>minExclusive</td><td>Integer and floating-point types.</td></tr> + <tr><td>minInclusive</td><td>Integer and floating-point types.</td></tr> + <tr><td>maxExclusive</td><td>Integer and floating-point types.</td></tr> + <tr><td>maxInclusive</td><td>Integer and floating-point types.</td></tr> + + <tr><th colspan="2">Datatypes</th></tr> + + <tr><td>byte</td><td></td></tr> + <tr><td>unsignedByte</td><td></td></tr> + <tr><td>short</td><td></td></tr> + <tr><td>unsignedShort</td><td></td></tr> + <tr><td>int</td><td></td></tr> + <tr><td>unsignedInt</td><td></td></tr> + <tr><td>long</td><td></td></tr> + <tr><td>unsignedLong</td><td></td></tr> + <tr><td>integer</td><td></td></tr> + <tr><td>nonPositiveInteger</td><td></td></tr> + <tr><td>nonNegativeInteger</td><td></td></tr> + <tr><td>positiveInteger</td><td></td></tr> + <tr><td>negativeInteger</td><td></td></tr> + + <tr><td>boolean</td><td></td></tr> + + <tr><td>float</td><td></td></tr> + <tr><td>double</td><td></td></tr> + <tr><td>decimal</td><td></td></tr> + + <tr><td>string</td><td></td></tr> + <tr><td>normalizedString</td><td></td></tr> + <tr><td>token</td><td></td></tr> + <tr><td>Name</td><td></td></tr> + <tr><td>NMTOKEN</td><td></td></tr> + <tr><td>NCName</td><td></td></tr> + <tr><td>language</td><td></td></tr> + <tr><td>anyURI</td><td></td></tr> + + <tr><td>ID</td><td>Identity constraint is not enforced.</td></tr> + <tr><td>IDREF</td><td>Identity constraint is not enforced.</td></tr> + + <tr><td>NMTOKENS</td><td></td></tr> + <tr><td>IDREFS</td><td>Identity constraint is not enforced.</td></tr> + + <tr><td>QName</td><td></td></tr> + + <tr><td>base64Binary</td><td></td></tr> + <tr><td>hexBinary</td><td></td></tr> + + <tr><td>date</td><td></td></tr> + <tr><td>dateTime</td><td></td></tr> + <tr><td>duration</td><td></td></tr> + <tr><td>gDay</td><td></td></tr> + <tr><td>gMonth</td><td></td></tr> + <tr><td>gMonthDay</td><td></td></tr> + <tr><td>gYear</td><td></td></tr> + <tr><td>gYearMonth</td><td></td></tr> + <tr><td>time</td><td></td></tr> + </table> + + </div> +</div> + + +</body> +</html> diff --git a/doc/cxx/serializer/guide/makefile b/doc/cxx/serializer/guide/makefile new file mode 100644 index 0000000..7502a53 --- /dev/null +++ b/doc/cxx/serializer/guide/makefile @@ -0,0 +1,48 @@ +# file : doc/cxx/serializer/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-serializer-e-guide.ps \ + $(out_base)/cxx-serializer-e-guide.pdf + + +$(out_base)/cxx-serializer-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-serializer-e-guide.pdf: $(out_base)/cxx-serializer-e-guide.ps | $(out_base)/. + $(call message,ps2pdf $<,ps2pdf14 $< $@) + +# Dist. +# +$(dist): path := $(subst $(src_root)/,,$(src_base)) +$(dist): $(out_base)/cxx-serializer-e-guide.ps $(out_base)/cxx-serializer-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-serializer-e-guide.ps,$(dist_prefix)/$(path)/cxx-serializer-e-guide.ps) + $(call install-data,$(out_base)/cxx-serializer-e-guide.pdf,$(dist_prefix)/$(path)/cxx-serializer-e-guide.pdf) + +$(dist-win): $(dist) + + +# Clean. +# +$(cleandoc): + $(call message,rm $$1,rm -f $$1,$(out_base)/cxx-serializer-e-guide.ps) + $(call message,rm $$1,rm -f $$1,$(out_base)/cxx-serializer-e-guide.pdf) + +# How to. +# +$(call include,$(bld_root)/install.make) |