aboutsummaryrefslogtreecommitdiff
path: root/documentation
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2009-03-26 17:09:53 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2009-03-26 17:09:53 +0200
commite4c22d3686da0e973e21eae0561c1169c0eeff36 (patch)
tree0a49e9167edc88938b0287949080931314e8afea /documentation
parent0d62005a3ff3b62d02c2eb3fd8644e0e19b202e8 (diff)
Implement support for XML Schema polymorphism in C++/Hybrid
examples/cxx/hybrid/polyroot/ examples/cxx/hybrid/polymorphism/: new examples tests/cxx/hybrid/polymorphism/: new tests
Diffstat (limited to 'documentation')
-rw-r--r--documentation/cxx/hybrid/guide/index.xhtml397
-rw-r--r--documentation/cxx/parser/guide/index.xhtml4
-rw-r--r--documentation/cxx/serializer/guide/index.xhtml2
-rw-r--r--documentation/xsde.137
-rw-r--r--documentation/xsde.xhtml34
5 files changed, 468 insertions, 6 deletions
diff --git a/documentation/cxx/hybrid/guide/index.xhtml b/documentation/cxx/hybrid/guide/index.xhtml
index 62603dc..5871593 100644
--- a/documentation/cxx/hybrid/guide/index.xhtml
+++ b/documentation/cxx/hybrid/guide/index.xhtml
@@ -256,6 +256,7 @@
<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>
</table>
</td>
</tr>
@@ -271,6 +272,7 @@
<tr><th>4.6</th><td><a href="#4.6">Modifying the Object Model</a></td></tr>
<tr><th>4.7</th><td><a href="#4.7">Creating the Object Model from Scratch</a></td></tr>
<tr><th>4.8</th><td><a href="#4.8">Customizing the Object Model</a></td></tr>
+ <tr><th>4.9</th><td><a href="#4.9">Polymorphic Object Models</a></td></tr>
</table>
</td>
</tr>
@@ -560,7 +562,7 @@
&lt;greeting>Hello&lt;/greeting>
&lt;name>sun&lt;/name>
- &lt;name>earth&lt;/name>
+ &lt;name>moon&lt;/name>
&lt;name>world&lt;/name>
&lt;/hello>
@@ -910,7 +912,7 @@ main (int argc, char* argv[])
&lt;hello>
&lt;greeting>Hi&lt;/greeting>
&lt;name>sun&lt;/name>
- &lt;name>earth&lt;/name>
+ &lt;name>moon&lt;/name>
&lt;name>world&lt;/name>
&lt;name>mars&lt;/name>
&lt;/hello>
@@ -1410,6 +1412,154 @@ namespace xml_schema
"Serializer Reuse"</a> in the Embedded C++/Serializer Mapping Getting
Started Guide for details.</p>
+ <h2><a name="3.7">3.7 Support for Polymorphism</a></h2>
+
+ <p>By default the XSD/e compiler generates non-polymorphic code. If your
+ vocabulary uses XML Schema polymorphism in the form of <code>xsi:type</code>
+ and/or substitution groups, then you will need to configure the XSD/e
+ runtime with support for polymorphism, compile your schemas with the
+ <code>--generate-polymorphic</code> option to produce polymorphism-aware
+ code, as well as pass <code>true</code> as the last argument to the
+ <code>xml_schema::document_pimpl</code> and
+ <code>xml_schema::document_simpl</code> constructors (see
+ <a href="#6">Chapter 6, "Parsing and Serialization"</a> for details).
+ If some of your schemas do not require support for polymorphism then
+ you can compile them with the <code>--runtime-polymorphic</code> option
+ and still use the XSD/e runtime configured with polymorphism support.
+ </p>
+
+ <p>The XSD/e compiler can often automatically determine which types are
+ polymorphic based on the substitution group declarations. However,
+ if your XML vocabulary is not using substitution groups or if
+ substitution groups are defined in a separate schema, then you will
+ need to use the <code>--polymorphic-type</code> option to specify
+ which types are polymorphic. When using this option you only need
+ to specify the root of a polymorphic type hierarchy and the XSD/e
+ compiler will assume that all the derived types are also polymorphic.
+ Also note that you need to specify this option when compiling every
+ schema file that references the polymorphic type. Consider the following
+ two schemas as an example:</p>
+
+ <pre class="xml">
+&lt;!-- base.xsd -->
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="base">
+ &lt;xs:sequence>
+ &lt;xs:element name="b" type="xs:int"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- substitution group root -->
+ &lt;xs:element name="base" type="base"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <pre class="xml">
+&lt;!-- derived.xsd -->
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;include schemaLocation="base.xsd"/>
+
+ &lt;xs:complexType name="derived">
+ &lt;xs:complexContent>
+ &lt;xs:extension base="base">
+ &lt;xs:sequence>
+ &lt;xs:element name="d" type="xs:string"/>
+ &lt;/xs:sequence>
+ &lt;/xs:extension>
+ &lt;/xs:complexContent>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="derived" type="derived" substitutionGroup="base"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>In this example we need to specify "<code>--polymorphic-type base</code>"
+ when compiling both schemas because the substitution group is declared
+ in a schema other than the one defining type <code>base</code>.</p>
+
+ <p>Another issue that may arise when compiling polymorphic schemas is
+ the situation where the XSD/e compiler is unaware of all the
+ derivations of a polymorphic type while generating parser and
+ serializer aggregates. As a result, the generated code may not
+ be able to parse and serialize these "invisible" to the compiler
+ types. The following example will help illustrate this case.
+ Consider a modified version of <code>base.xsd</code> from the
+ above example:</p>
+
+ <pre class="xml">
+&lt;!-- base.xsd -->
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="base">
+ &lt;xs:sequence>
+ &lt;xs:element name="b" type="xs:int"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- substitution group root -->
+ &lt;xs:element name="base" type="base"/>
+
+ &lt;xs:complexType name="root">
+ &lt;xs:sequence>
+ &lt;xs:element ref="base" maxOccurs="unbounded"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- document root -->
+ &lt;xs:element name="root" type="root"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>Suppose we compile this schema as follows:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root base.xsd
+ </pre>
+
+ <p>The resulting parser and serializer aggregates for the <code>root</code>
+ element will not include the parser and serializer for the
+ <code>derived</code> type that can be used instead of the
+ <code>base</code> type. This is because the XSD/e compiler
+ has no knowledge of the <code>derived</code>'s existence when
+ compiling <code>base.xsd</code>.</p>
+
+ <p>There are two ways to overcome this problem. The easier but
+ potentially slower approach is to compile all your schemas
+ at once, for example:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root base.xsd derived.xsd
+ </pre>
+
+ <p>This will make sure the XSD/e compiler "sees" all the derivations
+ of the polymorphic types. The other approach allows
+ you to explicitly specify, with the <code>--polymorphic-schema</code>
+ option, additional schemas that may contain derivations of the
+ polymorphic types. Using this approach we would compile
+ <code>base.xsd</code> and <code>derived.xsd</code> like this:</p>
+
+ <pre class="terminal">
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root \
+--polymorphic-schema derived.xsd base.xsd
+
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base derived.xsd
+ </pre>
+
+ <p>For information on how to use object models with polymorphic types,
+ refer to <a href="#4.9">Section 4.9, "Polymorphic Object Models"</a>.</p>
+
<!-- Chapater 4 -->
@@ -1672,6 +1822,9 @@ private:
<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.9">Section 4.9, "Polymorphic
+ Object Models"</a> for details)</li>
</ol>
<p>The following build-in XML Schema types are variable-length:
@@ -3536,6 +3689,246 @@ for (people::person_iterator i = ps.begin (); i != ps.end (); ++i)
</pre>
+ <h2><a name="4.9">4.9 Polymorphic Object Models</a></h2>
+
+ <p>When generating polymorphism-aware code (see <a href="#3.7">Section
+ 3.7, "Support for Polymorphism"</a>), some objects
+ in the resulting object model will be polymorphic. By polymorphic
+ we mean that the object's (static) type as specified in the
+ object model's interface may differ from the object's actual
+ (dynamic) type. Because of this, it may be necessary to discover
+ the object's actual type at runtime and cast it to this type to
+ gain access to the object's extended interface. Consider the
+ following schema as an example:</p>
+
+ <pre class="xml">
+&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ &lt;xs:complexType name="person">
+ &lt;xs:sequence>
+ &lt;xs:element name="name" type="xs:string"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;!-- substitution group root -->
+ &lt;xs:element name="person" type="person"/>
+
+ &lt;xs:complexType name="superman">
+ &lt;xs:complexContent>
+ &lt;xs:extension base="person">
+ &lt;xs:attribute name="can-fly" type="xs:boolean"/>
+ &lt;/xs:extension>
+ &lt;/xs:complexContent>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="superman"
+ type="superman"
+ substitutionGroup="person"/>
+
+ &lt;xs:complexType name="batman">
+ &lt;xs:complexContent>
+ &lt;xs:extension base="superman">
+ &lt;xs:attribute name="wing-span" type="xs:unsignedInt"/>
+ &lt;/xs:extension>
+ &lt;/xs:complexContent>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="batman"
+ type="batman"
+ substitutionGroup="superman"/>
+
+ &lt;xs:complexType name="supermen">
+ &lt;xs:sequence>
+ &lt;xs:element ref="person" maxOccurs="unbounded"/>
+ &lt;/xs:sequence>
+ &lt;/xs:complexType>
+
+ &lt;xs:element name="supermen" type="supermen"/>
+
+&lt;/xs:schema>
+ </pre>
+
+ <p>Conforming XML documents can use the <code>superman</code>
+ and <code>batman</code> types in place of the <code>person</code>
+ type either by specifying the type with the <code>xsi:type</code>
+ attributes or by using the elements from the substitution
+ group, for instance:</p>
+
+
+ <pre class="xml">
+&lt;supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ &lt;person>
+ &lt;name>John Doe&lt;/name>
+ &lt;/person>
+
+ &lt;superman can-fly="false">
+ &lt;name>James "007" Bond&lt;/name>
+ &lt;/superman>
+
+ &lt;superman can-fly="true" wing-span="10" xsi:type="batman">
+ &lt;name>Bruce Wayne&lt;/name>
+ &lt;/superman>
+
+&lt;/supermen>
+ </pre>
+
+ <p>When compiling the schema above with the
+ <code>--generate-polymorphic</code> option, the XSD/e compiler
+ automatically detects that the type hierarchy starting with
+ the <code>person</code> type is polymorphic. A polymorphic
+ type is always variable-length which means objects of polymorphic
+ types are allocated dynamically and are stored and passed around
+ as pointers or references. A polymorphic type also defines a
+ virtual destructor which allows you to delete an instance of a
+ polymorphic type via a pointer to its base. The following code
+ fragment shows how we can parse, access, modify, and serialize
+ the above XML document:</p>
+
+ <pre class="c++">
+// Parse.
+//
+supermen_paggr supermen_p;
+
+// The last argument to the document's constructor indicates that we
+// are parsing polymorphic XML documents.
+//
+xml_schema::document_pimpl doc_p (
+ supermen_p.root_parser (),
+ supermen_p.root_name (),
+ true);
+
+supermen_p.pre ();
+doc_p.parse ("supermen.xml");
+auto_ptr&lt;supermen> sm (supermen_p.post ());
+
+// Print what we've got.
+//
+for (supermen::person_iterator i = sm->person ().begin ();
+ i != sm->person ().end ();
+ ++i)
+{
+ person&amp; p = *i;
+
+ if (batman* b = dynamic_cast&lt;batman*> (&amp;p))
+ {
+ cerr &lt;&lt; b->name () &lt;&lt; ", batman, wing span " &lt;&lt;
+ b->wing_span () &lt;&lt; endl;
+ }
+ else if (superman* s = dynamic_cast&lt;superman*> (&amp;p))
+ {
+ cerr &lt;&lt; s->name () &lt;&lt; ", ";
+
+ if (s->can_fly ())
+ cerr &lt;&lt; "flying ";
+
+ cerr &lt;&lt; "superman" &lt;&lt; endl;
+ }
+ else
+ {
+ cerr &lt;&lt; p.name () &lt;&lt; ", ordinary person" &lt;&lt; endl;
+ }
+}
+
+// Add another superman entry.
+//
+auto_ptr&lt;superman> s (new superman);
+s->name ("Clark Kent");
+s->can_fly (true);
+sm->person ().push_back (s.release ());
+
+// Serialize.
+//
+supermen_saggr supermen_s;
+
+// The last argument to the document's constructor indicates that we
+// are serializing polymorphic XML documents.
+//
+xml_schema::document_simpl doc_s (
+ supermen_s.root_serializer (),
+ supermen_s.root_name (),
+ true);
+
+doc_s.add_no_namespace_schema ("supermen.xsd");
+
+supermen_s.pre (*sm);
+doc_s.serialize (cout);
+supermen_s.post ();
+ </pre>
+
+ <p>In the example above we used the standard C++ RTTI mechanism
+ to detect the object's actual (dynamic) type. If RTTI is not
+ available on your platform, then you can request the generation
+ of custom runtime type information for polymorphic types
+ with the <code>--generate-typeinfo</code> XSD/e compiler
+ option. When this option is specified, each polymorphic
+ type provides the following two public functions:</p>
+
+ <pre class="c++">
+virtual const std::string&amp;
+_dynamic_type () const;
+
+static const std::string&amp;
+_static_type ();
+ </pre>
+
+ <p>Or, if STL is disabled (<a href="#3.1">Section 3.1, "Standard Template
+ Library"</a>), the following two functions:</p>
+
+ <pre class="c++">
+virtual const char*
+_dynamic_type () const;
+
+static const char*
+_static_type ();
+ </pre>
+
+ <p>The <code>_dynamic_type()</code> function returns the object's
+ dynamic type id. The <code>_static_type()</code> function
+ returns the type's static id that can be compared to the
+ dynamic id. The following code fragment shows how
+ we can change the previous example to use custom type information
+ instead of C++ RTTI:</p>
+
+ <pre class="c++">
+for (supermen::person_iterator i = sm->person ().begin ();
+ i != sm->person ().end ();
+ ++i)
+{
+ person&amp; p = *i;
+ const string&amp; dt = p._dynamic_type ();
+
+ if (dt == batman::_static_type ())
+ {
+ batman&amp; b = static_cast&lt;batman&amp;> (p)
+ cerr &lt;&lt; b.name () &lt;&lt; ", batman, wing span " &lt;&lt;
+ b.wing_span () &lt;&lt; endl;
+ }
+ else if (dt == superman::_static_type ())
+ {
+ superman&amp; s = static_cast&lt;superman&amp;> (p)
+ cerr &lt;&lt; s.name () &lt;&lt; ", ";
+
+ if (s.can_fly ())
+ cerr &lt;&lt; "flying ";
+
+ cerr &lt;&lt; "superman" &lt;&lt; endl;
+ }
+ else
+ {
+ cerr &lt;&lt; p.name () &lt;&lt; ", ordinary person" &lt;&lt; endl;
+ }
+}
+ </pre>
+
+ <p>Most of the code presented in this section is taken from the
+ <code>polymorphism</code> example which can be found in the
+ <code>examples/cxx/hybrid/</code> directory of the XSD/e distribution.
+ Handling of <code>xsi:type</code> and substitution groups when used
+ on root elements requires a number of special actions as shown in
+ the <code>polyroot</code> example.</p>
+
+
<!-- Built-in XML Schema Type Parsers -->
diff --git a/documentation/cxx/parser/guide/index.xhtml b/documentation/cxx/parser/guide/index.xhtml
index 85b5092..ac69845 100644
--- a/documentation/cxx/parser/guide/index.xhtml
+++ b/documentation/cxx/parser/guide/index.xhtml
@@ -522,7 +522,7 @@
&lt;greeting>Hello&lt;/greeting>
&lt;name>sun&lt;/name>
- &lt;name>earth&lt;/name>
+ &lt;name>moon&lt;/name>
&lt;name>world&lt;/name>
&lt;/hello>
@@ -2322,7 +2322,7 @@ protected:
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
+ <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.
diff --git a/documentation/cxx/serializer/guide/index.xhtml b/documentation/cxx/serializer/guide/index.xhtml
index 4deacf0..bd681cc 100644
--- a/documentation/cxx/serializer/guide/index.xhtml
+++ b/documentation/cxx/serializer/guide/index.xhtml
@@ -529,7 +529,7 @@
&lt;greeting>Hello&lt;/greeting>
&lt;name>sun&lt;/name>
- &lt;name>earth&lt;/name>
+ &lt;name>moon&lt;/name>
&lt;name>world&lt;/name>
&lt;/hello>
diff --git a/documentation/xsde.1 b/documentation/xsde.1
index f9fe998..62cc55d 100644
--- a/documentation/xsde.1
+++ b/documentation/xsde.1
@@ -1005,6 +1005,43 @@ Suppress the generation of parser and serializer reset code.
Reset support allows you to reuse parsers and serializers
after an error.
+.IP "\fB\--generate-polymorphic\fR"
+Generate polymorphism-aware code. Specify this option if you use substitution
+groups or
+.BR xsi:type .
+Use the
+.B --polymorphic-type
+option to specify which type hierarchies are polymorphic.
+
+.IP "\fB\--runtime-polymorphic\fR"
+Generate non-polymorphic code that uses the runtime library configured with
+polymorphism support.
+
+.IP "\fB\--polymorphic-type \fItype\fR"
+Indicate that
+.I type
+is a root of a polymorphic type hierarchy. The compiler can often
+automatically determine which types are polymorphic based on the
+substitution group declarations. However, you may need to use this
+option if you are not using substitution groups or if substitution
+groups are defined in another schema. You need to specify this option
+when compiling every schema file that references
+.IR type .
+
+.IP "\fB\--generate-typeinfo\fR"
+Generate custom type information querying functions for polymorphic
+object model types. These functions can be used instead of the standard
+C++ RTTI mechanism to determine object's type at runtime.
+
+.IP "\fB\--polymorphic-schema \fIfile\fR"
+Indicate that
+.I file
+contains derivations of polymorphic types that are not otherwise visible
+from the schema being compiled. This option is used to make sure that
+during the generation of parser and serializer aggregates the compiler
+is aware of all possible derivations of polymorphic types. Repeat this
+option to specify more than one schema file.
+
.IP "\fB\--reuse-style-mixin\fR"
Generate code that supports the mixin base parser/serializer
implementation reuse style. Note that this reuse style
diff --git a/documentation/xsde.xhtml b/documentation/xsde.xhtml
index 312d5f9..c8f602a 100644
--- a/documentation/xsde.xhtml
+++ b/documentation/xsde.xhtml
@@ -870,6 +870,39 @@
Reset support allows you to reuse parsers and serializers
after an error.</dd>
+ <dt><code><b>--generate-polymorphic</b></code></dt>
+ <dd>Generate polymorphism-aware code. Specify this option if you use
+ substitution groups or <code><b>xsi:type</b></code>. Use the
+ <code><b>--polymorphic-type</b></code> option to specify which
+ type hierarchies are polymorphic.</dd>
+
+ <dt><code><b>--runtime-polymorphic</b></code></dt>
+ <dd>Generate non-polymorphic code that uses the runtime library
+ configured with polymorphism support.</dd>
+
+ <dt><code><b>--polymorphic-type</b></code> <i>type</i></dt>
+ <dd>Indicate that <code><i>type</i></code> is a root of a polymorphic
+ type hierarchy. The compiler can often automatically determine
+ which types are polymorphic based on the substitution group
+ declarations. However, you may need to use this option if you are
+ not using substitution groups or if substitution groups are defined
+ in another schema. You need to specify this option when compiling
+ every schema file that references <code><i>type</i></code>.</dd>
+
+ <dt><code><b>--generate-typeinfo</b></code></dt>
+ <dd>Generate custom type information querying functions for
+ polymorphic object model types. These functions can be used
+ instead of the standard C++ RTTI mechanism to determine
+ object's type at runtime.</dd>
+
+ <dt><code><b>--polymorphic-schema</b></code> <i>file</i></dt>
+ <dd>Indicate that <code><i>file</i></code> contains derivations of
+ polymorphic types that are not otherwise visible from the schema
+ being compiled. This option is used to make sure that during the
+ generation of parser and serializer aggregates the compiler is
+ aware of all possible derivations of polymorphic types. Repeat
+ this option to specify more than one schema file.</dd>
+
<dt><code><b>--reuse-style-mixin</b></code></dt>
<dd>Generate code that supports the mixin base parser/serializer
implementation reuse style. Note that this reuse style
@@ -877,7 +910,6 @@
object code size increase for large vocabularies. By default
the tiein reuse style is used.</dd>
-
<dt><code><b>--custom-data</b></code> <i>type</i></dt>
<dd>Add the ability to store custom data to the C++ class generated
for XML Schema type <code><i>type</i></code>. To add custom