From e4c22d3686da0e973e21eae0561c1169c0eeff36 Mon Sep 17 00:00:00 2001
From: Boris Kolpackov 3.4 XML Schema Validation 3.5 64-bit Integer Type
+ 3.6 Parser and Serializer Reuse
@@ -271,6 +272,7 @@
3.7 Support for Polymorphism 4.6 Modifying the Object Model 4.7 Creating the Object Model from Scratch
+ 4.8 Customizing the Object Model
@@ -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" in the Embedded C++/Serializer Mapping Getting
Started Guide for details.4.9 Polymorphic Object Models
By default the XSD/e compiler generates non-polymorphic code. If your
+ vocabulary uses XML Schema polymorphism in the form of xsi:type
+ and/or substitution groups, then you will need to configure the XSD/e
+ runtime with support for polymorphism, compile your schemas with the
+ --generate-polymorphic
option to produce polymorphism-aware
+ code, as well as pass true
as the last argument to the
+ xml_schema::document_pimpl
and
+ xml_schema::document_simpl
constructors (see
+ Chapter 6, "Parsing and Serialization" for details).
+ If some of your schemas do not require support for polymorphism then
+ you can compile them with the --runtime-polymorphic
option
+ and still use the XSD/e runtime configured with polymorphism support.
+
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 --polymorphic-type
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:
+<!-- 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> ++ +
+<!-- 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> ++ +
In this example we need to specify "--polymorphic-type base
"
+ when compiling both schemas because the substitution group is declared
+ in a schema other than the one defining type base
.
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 base.xsd
from the
+ above example:
+<!-- 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> ++ +
Suppose we compile this schema as follows:
+ ++$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base \ +--generate-aggregate --root-element root base.xsd ++ +
The resulting parser and serializer aggregates for the root
+ element will not include the parser and serializer for the
+ derived
type that can be used instead of the
+ base
type. This is because the XSD/e compiler
+ has no knowledge of the derived
's existence when
+ compiling base.xsd
.
There are two ways to overcome this problem. The easier but + potentially slower approach is to compile all your schemas + at once, for example:
+ ++$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base \ +--generate-aggregate --root-element root base.xsd derived.xsd ++ +
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 --polymorphic-schema
+ option, additional schemas that may contain derivations of the
+ polymorphic types. Using this approach we would compile
+ base.xsd
and derived.xsd
like this:
+$ 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 ++ +
For information on how to use object models with polymorphic types, + refer to Section 4.9, "Polymorphic Object Models".
+ @@ -1672,6 +1822,9 @@ private: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) +
When generating polymorphism-aware code (see Section + 3.7, "Support for Polymorphism"), 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:
+ ++<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> ++ +
Conforming XML documents can use the superman
+ and batman
types in place of the person
+ type either by specifying the type with the xsi:type
+ attributes or by using the elements from the substitution
+ group, for instance:
+<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> ++ +
When compiling the schema above with the
+ --generate-polymorphic
option, the XSD/e compiler
+ automatically detects that the type hierarchy starting with
+ the person
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:
+// 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 (); ++ +
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 --generate-typeinfo
XSD/e compiler
+ option. When this option is specified, each polymorphic
+ type provides the following two public functions:
+virtual const std::string& +_dynamic_type () const; + +static const std::string& +_static_type (); ++ +
Or, if STL is disabled (Section 3.1, "Standard Template + Library"), the following two functions:
+ ++virtual const char* +_dynamic_type () const; + +static const char* +_static_type (); ++ +
The _dynamic_type()
function returns the object's
+ dynamic type id. The _static_type()
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:
+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; + } +} ++ +
Most of the code presented in this section is taken from the
+ polymorphism
example which can be found in the
+ examples/cxx/hybrid/
directory of the XSD/e distribution.
+ Handling of xsi:type
and substitution groups when used
+ on root elements requires a number of special actions as shown in
+ the polyroot
example.
--generate-polymorphic
option to produce polymorphism-aware
code, as well as pass true
as the last argument to the
- xml_schema::document
's constructors. If some of your
+ xml_schema::document_pimpl
's constructors. If some of your
schemas do not require support for polymorphism then you can compile
them with the --runtime-polymorphic
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.
+ --generate-polymorphic
xsi:type
. Use the
+ --polymorphic-type
option to specify which
+ type hierarchies are polymorphic.--runtime-polymorphic
--polymorphic-type
typetype
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 type
.--generate-typeinfo
--polymorphic-schema
filefile
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.--reuse-style-mixin
--custom-data
typetype
. To add custom
--
cgit v1.1