diff options
Diffstat (limited to 'documentation')
-rw-r--r-- | documentation/cxx/hybrid/guide/index.xhtml | 397 | ||||
-rw-r--r-- | documentation/cxx/parser/guide/index.xhtml | 4 | ||||
-rw-r--r-- | documentation/cxx/serializer/guide/index.xhtml | 2 | ||||
-rw-r--r-- | documentation/xsde.1 | 37 | ||||
-rw-r--r-- | documentation/xsde.xhtml | 34 |
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 @@ <greeting>Hello</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> </hello> @@ -910,7 +912,7 @@ main (int argc, char* argv[]) <hello> <greeting>Hi</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> <name>mars</name> </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"> +<!-- 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.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"> +<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 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<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); +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 --> 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 @@ <greeting>Hello</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> </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 @@ <greeting>Hello</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> </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 |