aboutsummaryrefslogtreecommitdiff
path: root/examples
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 /examples
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 'examples')
-rw-r--r--examples/cxx/hybrid/README8
-rw-r--r--examples/cxx/hybrid/binary/xdr/driver.cxx1
-rw-r--r--examples/cxx/hybrid/custom/wildcard/driver.cxx1
-rw-r--r--examples/cxx/hybrid/filter/driver.cxx1
-rw-r--r--examples/cxx/hybrid/library/driver.cxx1
-rw-r--r--examples/cxx/hybrid/makefile8
-rw-r--r--examples/cxx/hybrid/minimal/driver.cxx1
-rw-r--r--examples/cxx/hybrid/polymorphism/README57
-rw-r--r--examples/cxx/hybrid/polymorphism/driver.cxx202
-rw-r--r--examples/cxx/hybrid/polymorphism/makefile113
-rw-r--r--examples/cxx/hybrid/polymorphism/supermen.xml26
-rw-r--r--examples/cxx/hybrid/polymorphism/supermen.xsd49
-rw-r--r--examples/cxx/hybrid/polyroot/README60
-rw-r--r--examples/cxx/hybrid/polyroot/batman.xml17
-rw-r--r--examples/cxx/hybrid/polyroot/driver.cxx322
-rw-r--r--examples/cxx/hybrid/polyroot/makefile115
-rw-r--r--examples/cxx/hybrid/polyroot/person.xml16
-rw-r--r--examples/cxx/hybrid/polyroot/superman.xml17
-rw-r--r--examples/cxx/hybrid/polyroot/supermen.xsd40
-rw-r--r--examples/cxx/hybrid/streaming/driver.cxx1
-rw-r--r--examples/cxx/hybrid/wildcard/driver.cxx1
-rw-r--r--examples/cxx/parser/README16
-rw-r--r--examples/cxx/parser/polymorphism/README6
-rw-r--r--examples/cxx/serializer/README16
-rw-r--r--examples/cxx/serializer/polymorphism/README6
25 files changed, 1078 insertions, 23 deletions
diff --git a/examples/cxx/hybrid/README b/examples/cxx/hybrid/README
index d23c10d..7d9312d 100644
--- a/examples/cxx/hybrid/README
+++ b/examples/cxx/hybrid/README
@@ -36,6 +36,14 @@ compositors
Shows how to create, access, and modify object models with complex
nested choice and sequence compositors.
+polymorphism
+ Shows how to handle XML vocabularies that use XML Schema polymorphism
+ features such as the xsi:type attribute and substitution groups.
+
+polyroot
+ Shows how to handle XML vocabularies with polymorphic document root
+ elements.
+
custom/
A collection of examples that show how to customize the C++/Hybrid
object model by using custom C++ classes instead of or in addition
diff --git a/examples/cxx/hybrid/binary/xdr/driver.cxx b/examples/cxx/hybrid/binary/xdr/driver.cxx
index e629849..d587817 100644
--- a/examples/cxx/hybrid/binary/xdr/driver.cxx
+++ b/examples/cxx/hybrid/binary/xdr/driver.cxx
@@ -10,7 +10,6 @@
#include <iostream>
#include "library.hxx"
-
#include "library-pimpl.hxx"
#include "library-simpl.hxx"
diff --git a/examples/cxx/hybrid/custom/wildcard/driver.cxx b/examples/cxx/hybrid/custom/wildcard/driver.cxx
index 02870fa..f5b05ee 100644
--- a/examples/cxx/hybrid/custom/wildcard/driver.cxx
+++ b/examples/cxx/hybrid/custom/wildcard/driver.cxx
@@ -7,7 +7,6 @@
#include <iostream>
#include "email.hxx"
-
#include "email-pimpl.hxx"
#include "email-simpl.hxx"
diff --git a/examples/cxx/hybrid/filter/driver.cxx b/examples/cxx/hybrid/filter/driver.cxx
index 9bc9f64..5c15cef 100644
--- a/examples/cxx/hybrid/filter/driver.cxx
+++ b/examples/cxx/hybrid/filter/driver.cxx
@@ -6,7 +6,6 @@
#include <iostream>
#include "people.hxx"
-
#include "people-pimpl.hxx"
#include "people-simpl.hxx"
diff --git a/examples/cxx/hybrid/library/driver.cxx b/examples/cxx/hybrid/library/driver.cxx
index 2bde50d..628831a 100644
--- a/examples/cxx/hybrid/library/driver.cxx
+++ b/examples/cxx/hybrid/library/driver.cxx
@@ -6,7 +6,6 @@
#include <iostream>
#include "library.hxx"
-
#include "library-pimpl.hxx"
#include "library-simpl.hxx"
diff --git a/examples/cxx/hybrid/makefile b/examples/cxx/hybrid/makefile
index 2defdc5..cc886ec 100644
--- a/examples/cxx/hybrid/makefile
+++ b/examples/cxx/hybrid/makefile
@@ -5,8 +5,8 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
-all_examples := binary compositors custom hello multiroot streaming \
-library wildcard filter minimal
+all_examples := binary compositors custom hello multiroot polymorphism \
+polyroot streaming library wildcard filter minimal
build_examples := binary compositors custom
@@ -19,6 +19,10 @@ ifeq ($(xsde_stl),y)
build_examples += library wildcard filter
endif
+ifeq ($(xsde_polymorphic),y)
+build_examples += polymorphism polyroot
+endif
+
endif
endif
diff --git a/examples/cxx/hybrid/minimal/driver.cxx b/examples/cxx/hybrid/minimal/driver.cxx
index e876b6f..e8e8312 100644
--- a/examples/cxx/hybrid/minimal/driver.cxx
+++ b/examples/cxx/hybrid/minimal/driver.cxx
@@ -5,7 +5,6 @@
#include <stdio.h>
#include "people.hxx"
-
#include "people-pimpl.hxx"
#include "people-simpl.hxx"
diff --git a/examples/cxx/hybrid/polymorphism/README b/examples/cxx/hybrid/polymorphism/README
new file mode 100644
index 0000000..2e00636
--- /dev/null
+++ b/examples/cxx/hybrid/polymorphism/README
@@ -0,0 +1,57 @@
+This example shows how to handle XML vocabularies that use the XML
+Schema polymorphism features such as the xsi:type attribute and
+substitution groups in the Embedded C++/Hybrid mapping. The case
+where xsi:type or substitution groups are used on document root
+elements is covered in the polyroot examples.
+
+The example consists of the following files:
+
+supermen.xsd
+ XML Schema which describes supermen instance documents.
+
+supermen.xml
+ Sample XML instance document.
+
+supermen.hxx
+supermen.cxx
+
+supermen-pskel.hxx
+supermen-pskel.cxx
+supermen-pimpl.hxx
+supermen-pimpl.cxx
+
+supermen-pskel.hxx
+supermen-pskel.cxx
+supermen-pimpl.hxx
+supermen-pimpl.cxx
+ Object model (the first pair of files), parser skeletons (the
+ second pair), parser implementations (the third pair), serializer
+ skeletons (the fourth pair), and serializer implementations (the
+ fifth pair). These files are generated by the XSD/e compiler from
+ supermen.xsd. The --generate-parser, --generate-serializer, and
+ --generate-aggregate options were used to request the generation
+ of the parsing and serialization code. The --generate-polymorphic
+ option was used to request the generation of the polymorphism-aware
+ code. Since our vocabulary uses substitution groups, the XSD/e
+ compiler is able to automatically determine which type hierarchy is
+ polymorphic (otherwise we would have had to use the --polymorphic-type
+ option). The --generate-typeinfo option was used to request the
+ generation of custom type information for polymorphic object model
+ types. Finally, the --root-element option was used to specify the
+ document root element.
+
+driver.cxx
+ Driver for the example. It first calls the parser that constructs
+ the object model from the input XML file. It then prints the content
+ of the object model to STDERR at which point it determines the actual
+ (dynamic) types of polymorphic objects. Finally, the driver modifies
+ the object model by adding another polymorphic instance and calls the
+ serializer to serialize it back to XML.
+
+To run the example on the sample XML instance document simply execute:
+
+$ ./driver supermen.xml
+
+The example reads from STDIN if input file is not specified:
+
+$ ./driver <supermen.xml
diff --git a/examples/cxx/hybrid/polymorphism/driver.cxx b/examples/cxx/hybrid/polymorphism/driver.cxx
new file mode 100644
index 0000000..926bb91
--- /dev/null
+++ b/examples/cxx/hybrid/polymorphism/driver.cxx
@@ -0,0 +1,202 @@
+// file : examples/cxx/hybrid/polymorphism/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <memory> // std::auto_ptr
+#include <iostream>
+
+#include "supermen.hxx"
+#include "supermen-pimpl.hxx"
+#include "supermen-simpl.hxx"
+
+using namespace std;
+
+void
+check_load (); // Defined after main().
+
+int
+main (int argc, char* argv[])
+{
+ // Check that the load in substitution and inheritance hashmaps
+ // is not too high.
+ //
+#ifndef NDEBUG
+ check_load ();
+#endif
+
+ const char* input;
+
+ if (argc < 2)
+ {
+ input = "STDIN";
+ cerr << "XML file not specified, reading from STDIN" << endl;
+ }
+ else
+ input = argv[1];
+
+ try
+ {
+ // 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 ();
+
+ if (argc < 2)
+ doc_p.parse (cin);
+ else
+ doc_p.parse (argv[1]);
+
+ 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;
+
+ // You can use the standard C++ RTTI or custom type information
+ // provided by the object model (--generate-typeinfo option) to
+ // detect the object's actual (dynamic) type.
+ //
+ if (p._dynamic_type () == batman::_static_type ())
+ {
+ batman& b = static_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);
+#ifdef XSDE_STL
+ s->name ("Clark Kent");
+#else
+ s->name (xml_schema::strdupx ("Clark Kent"));
+#endif
+ 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 ();
+ }
+ catch (const xml_schema::parser_exception& e)
+ {
+ cerr << input << ":" << e.line () << ":" << e.column () << ": "
+ << e.text () << endl;
+ return 1;
+ }
+ catch (const xml_schema::serializer_exception& e)
+ {
+ cerr << "error: " << e.text () << endl;
+ return 1;
+ }
+ catch (const std::ios_base::failure&)
+ {
+ cerr << input << ": unable to open or read/write failure" << endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifndef NDEBUG
+// Check that the load in substitution and inheritance hashmaps is not
+// too high. See the C++/Parser and C++/Serializer Mappings Getting
+// Started Guides for details.
+//
+void
+check_load ()
+{
+ // Parser.
+ //
+ float load = (float) 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;
+ }
+
+#ifdef XSDE_PARSER_VALIDATION
+ load = (float) 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
+
+ // Serializer.
+ //
+ load = (float) 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 = (float) 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;
+ }
+
+#ifdef XSDE_SERIALIZER_VALIDATION
+ load = (float) 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
+}
+#endif
diff --git a/examples/cxx/hybrid/polymorphism/makefile b/examples/cxx/hybrid/polymorphism/makefile
new file mode 100644
index 0000000..5a137eb
--- /dev/null
+++ b/examples/cxx/hybrid/polymorphism/makefile
@@ -0,0 +1,113 @@
+# file : examples/cxx/hybrid/polymorphism/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+xsd := supermen.xsd
+cxx := driver.cxx
+
+obj := $(addprefix $(out_base)/,\
+$(cxx:.cxx=.o) \
+$(xsd:.xsd=.o) \
+$(xsd:.xsd=-pskel.o) \
+$(xsd:.xsd=-pimpl.o) \
+$(xsd:.xsd=-sskel.o) \
+$(xsd:.xsd=-simpl.o))
+
+dep := $(obj:.o=.o.d)
+
+xsde.l := $(out_root)/libxsde/xsde/xsde.l
+xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options
+
+driver := $(out_base)/driver
+dist := $(out_base)/.dist
+dist-win := $(out_base)/.dist-win
+clean := $(out_base)/.clean
+
+# Build.
+#
+$(driver): $(obj) $(xsde.l)
+
+$(obj) $(dep): $(xsde.l.cpp-options)
+
+genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \
+ $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \
+ $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) \
+ $(xsd:.xsd=-sskel.hxx) $(xsd:.xsd=-sskel.cxx) \
+ $(xsd:.xsd=-simpl.hxx) $(xsd:.xsd=-simpl.cxx)
+
+gen := $(addprefix $(out_base)/,$(genf))
+
+$(gen): $(out_root)/xsde/xsde
+$(gen): xsde := $(out_root)/xsde/xsde
+$(gen): xsde_options += --generate-parser --generate-serializer \
+--generate-aggregate --generate-polymorphic --generate-typeinfo \
+--root-element supermen
+
+$(call include-dep,$(dep))
+
+# Convenience alias for default target.
+#
+.PHONY: $(out_base)/
+$(out_base)/: $(driver)
+
+
+# Dist.
+#
+dist-common := $(out_base)/.dist-common
+
+.PHONY: $(dist) $(dist-win) $(dist-common)
+
+$(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base))
+
+$(dist-common):
+ $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx)
+ $(call install-data,$(src_base)/supermen.xsd,$(dist_prefix)/$(path)/supermen.xsd)
+ $(call install-data,$(src_base)/supermen.xml,$(dist_prefix)/$(path)/supermen.xml)
+
+$(dist): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README)
+
+$(dist-win): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+
+# Clean.
+#
+.PHONY: $(clean)
+
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean))
+
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(gen): | $(out_base)/.gitignore
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver $(genf)
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+$(call include,$(bld_root)/install.make)
+$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make)
+
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsde/makefile)
+$(call import,$(src_root)/libxsde/xsde/makefile)
diff --git a/examples/cxx/hybrid/polymorphism/supermen.xml b/examples/cxx/hybrid/polymorphism/supermen.xml
new file mode 100644
index 0000000..bfc9e00
--- /dev/null
+++ b/examples/cxx/hybrid/polymorphism/supermen.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/polymorphism/supermen.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="supermen.xsd">
+
+ <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>
diff --git a/examples/cxx/hybrid/polymorphism/supermen.xsd b/examples/cxx/hybrid/polymorphism/supermen.xsd
new file mode 100644
index 0000000..208d560
--- /dev/null
+++ b/examples/cxx/hybrid/polymorphism/supermen.xsd
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/polymorphism/supermen.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsd:complexType name="person">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <!-- substitution group root -->
+ <xsd:element name="person" type="person"/>
+
+
+ <xsd:complexType name="superman">
+ <xsd:complexContent>
+ <xsd:extension base="person">
+ <xsd:attribute name="can-fly" type="xsd:boolean" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="superman" type="superman" substitutionGroup="person"/>
+
+ <xsd:complexType name="batman">
+ <xsd:complexContent>
+ <xsd:extension base="superman">
+ <xsd:attribute name="wing-span" type="xsd:unsignedInt" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="supermen">
+ <xsd:sequence>
+ <xsd:element ref="person" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="supermen" type="supermen"/>
+
+</xsd:schema>
diff --git a/examples/cxx/hybrid/polyroot/README b/examples/cxx/hybrid/polyroot/README
new file mode 100644
index 0000000..3d690f5
--- /dev/null
+++ b/examples/cxx/hybrid/polyroot/README
@@ -0,0 +1,60 @@
+This example shows how to handle XML vocabularies with polymorphic document
+root elements in the Embedded C++/Hybrid mapping. For general coverage of
+XML Schema polymorphism handling see the polymorphism example.
+
+The example consists of the following files:
+
+supermen.xsd
+ XML Schema which describes supermen instance documents.
+
+person.xml
+superman.xml
+batman.xml
+ Sample XML instance documents.
+
+supermen.hxx
+supermen.cxx
+
+supermen-pskel.hxx
+supermen-pskel.cxx
+supermen-pimpl.hxx
+supermen-pimpl.cxx
+
+supermen-pskel.hxx
+supermen-pskel.cxx
+supermen-pimpl.hxx
+supermen-pimpl.cxx
+ Object model (the first pair of files), parser skeletons (the
+ second pair), parser implementations (the third pair), serializer
+ skeletons (the fourth pair), and serializer implementations (the
+ fifth pair). These files are generated by the XSD/e compiler from
+ supermen.xsd. The --generate-parser, --generate-serializer, and
+ --generate-aggregate options were used to request the generation
+ of the parsing and serialization code. The --generate-polymorphic
+ option was used to request the generation of the polymorphism-aware
+ code. Since our vocabulary uses substitution groups, the XSD/e
+ compiler is able to automatically determine which type hierarchy is
+ polymorphic (otherwise we would have had to use the --polymorphic-type
+ option). The --generate-typeinfo option was used to request the
+ generation of custom type information for polymorphic object model
+ types. Finally, the --root-element option was used to specify the
+ document root element.
+
+driver.cxx
+ Driver for the example. It first calls the parser that constructs
+ the object model from the input XML file. It then prints the content
+ of the object model to STDERR at which point it determines the actual
+ (dynamic) types of polymorphic objects. Finally, the driver calls the
+ serializer to serialize the object model back to XML.
+
+To run the example on the sample XML instance documents simply execute:
+
+$ ./driver person.xml
+$ ./driver superman.xml
+$ ./driver batman.xml
+
+The example reads from STDIN if input file is not specified:
+
+$ ./driver <person.xml
+$ ./driver <superman.xml
+$ ./driver <batman.xml
diff --git a/examples/cxx/hybrid/polyroot/batman.xml b/examples/cxx/hybrid/polyroot/batman.xml
new file mode 100644
index 0000000..96248ff
--- /dev/null
+++ b/examples/cxx/hybrid/polyroot/batman.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/polyroot/batman.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="supermen.xsd"
+ xsi:type="batman" can-fly="true" wing-span="10">
+
+ <name>Bruce Wayne</name>
+
+</person>
diff --git a/examples/cxx/hybrid/polyroot/driver.cxx b/examples/cxx/hybrid/polyroot/driver.cxx
new file mode 100644
index 0000000..f41422c
--- /dev/null
+++ b/examples/cxx/hybrid/polyroot/driver.cxx
@@ -0,0 +1,322 @@
+// file : examples/cxx/hybrid/polyroot/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <memory> // std::auto_ptr
+#include <iostream>
+
+#include "supermen.hxx"
+#include "supermen-pimpl.hxx"
+#include "supermen-simpl.hxx"
+
+using namespace std;
+using xml_schema::ro_string;
+
+// Customize the xml_schema::document object to handle a polymorphic
+// root element. For more information see the polyroot and multiroot
+// examples in the examples/cxx/parser/ directory.
+//
+class document_pimpl: public xml_schema::document_pimpl
+{
+public:
+ // Passing the root element name to xml_schema::document_pimpl
+ // constructor indicates that we are doing polymorphic parsing.
+ // The root element name is used to automatically translate
+ // substitutions to type information.
+ //
+ document_pimpl (person_paggr& paggr)
+ : xml_schema::document_pimpl (person_paggr::root_name ()),
+ paggr_ (paggr),
+ parser_used_ (0)
+ {
+ }
+
+ person*
+ result ()
+ {
+ return result_.release ();
+ }
+
+protected:
+ // This function is called to obtain the root element type parser.
+ // If the returned pointer is 0 then the whole document content
+ // is ignored. The type argument contains the XML Schema type
+ // if xsi:type attribute or an element that substitutes the root
+ // was specified and 0 otherwise.
+ //
+ virtual xml_schema::parser_base*
+ start_root_element (const ro_string& ns,
+ const ro_string& name,
+ const char* type)
+ {
+ if (name != person_paggr::root_name () ||
+ ns != person_paggr::root_namespace ())
+ {
+ // If the runtime and the generated code are built with
+ // validation enabled then we can also set an XML Schema
+ // error.
+ //
+#ifdef XSDE_PARSER_VALIDATION
+ context_.schema_error (
+ xml_schema::parser_schema_error::unexpected_element);
+#endif
+ return 0;
+ }
+
+ // Search for the parser. If type is 0 then there is no xsi:type and
+ // static type should be used.
+ //
+ if (type == 0)
+ parser_used_ = &paggr_.root_parser ();
+ else
+ {
+ // The map returns a generic parser_base which we will cast to
+ // person_pskel in order to call the pre() and post_person()
+ // callbacks. If the runtime and the generated code are built
+ // with the mixin parser reuse style then we have to use
+ // dynamic_cast because of the virtual inheritance.
+ //
+ xml_schema::parser_base* p = paggr_.root_map ().find (type);
+
+#ifdef XSDE_REUSE_STYLE_MIXIN
+ parser_used_ = dynamic_cast<person_pskel*> (p);
+#else
+ parser_used_ = static_cast<person_pskel*> (p);
+#endif
+ }
+
+ if (parser_used_ != 0)
+ parser_used_->pre ();
+
+ return parser_used_;
+ }
+
+ // This function is called to indicate the completion of document
+ // parsing. The parser argument contains the pointer returned by
+ // start_root_element.
+ //
+ virtual void
+ end_root_element (const ro_string& /* ns */,
+ const ro_string& /* name */,
+ xml_schema::parser_base* /* parser */)
+ {
+ // Instead of caching the current parser in parser_used_, we
+ // could also cast the parser argument to the person_pskel
+ // type.
+ //
+ if (parser_used_ != 0)
+ result_.reset (parser_used_->post_person ());
+ }
+
+public:
+ // If we need to be able to reset and reuse the parser after
+ // an error then we also need to override reset() and reset
+ // the parser that was used last. Note that you always need
+ // to call _reset() from the base.
+ //
+ virtual void
+ reset ()
+ {
+ xml_schema::document_pimpl::reset ();
+
+ if (parser_used_ != 0)
+ parser_used_->_reset ();
+ }
+
+private:
+ person_paggr& paggr_;
+ person_pskel* parser_used_;
+ std::auto_ptr<person> result_;
+};
+
+void
+check_load (); // Defined after main().
+
+int
+main (int argc, char* argv[])
+{
+ // Check that the load in substitution and inheritance hashmaps
+ // is not too high.
+ //
+#ifndef NDEBUG
+ check_load ();
+#endif
+
+ const char* input;
+
+ if (argc < 2)
+ {
+ input = "STDIN";
+ cerr << "XML file not specified, reading from STDIN" << endl;
+ }
+ else
+ input = argv[1];
+
+ try
+ {
+ // Parse.
+ //
+ person_paggr person_p;
+
+ // Use our customized document parser. It automatically calls
+ // pre() and post() on the chosen parser and stores the result.
+ //
+ document_pimpl doc_p (person_p);
+
+ if (argc < 2)
+ doc_p.parse (cin);
+ else
+ doc_p.parse (argv[1]);
+
+ auto_ptr<person> p (doc_p.result ());
+
+ // Print what we've got. You can use the standard C++ RTTI or custom
+ // type information provided by the object model (--generate-typeinfo
+ // option) to detect the object's actual (dynamic) type.
+ //
+ if (p->_dynamic_type () == batman::_static_type ())
+ {
+ batman& b = static_cast<batman&> (*p);
+ cerr << b.name () << ", batman, wing span " << b.wing_span () << endl;
+ }
+ else if (superman* s = dynamic_cast<superman*> (p.get ()))
+ {
+ cerr << s->name () << ", ";
+
+ if (s->can_fly ())
+ cerr << "flying ";
+
+ cerr << "superman" << endl;
+ }
+ else
+ {
+ cerr << p->name () << ", ordinary person" << endl;
+ }
+
+ // Serialize.
+ //
+ person_saggr person_s;
+ person_sskel* ps = 0;
+
+ // Determine the root element serializer to use based on the object's
+ // dynamic type.
+ //
+ const string& dt = p->_dynamic_type ();
+
+ if (dt == person::_static_type ())
+ ps = &person_s.root_serializer ();
+ else
+ {
+ // The map returns a generic serializer_base which we will cast to
+ // person_sskel in order to call the pre() and post() callbacks. If
+ // the runtime and the generated code are built with the mixin
+ // serializer reuse style then we have to use dynamic_cast because
+ // of the virtual inheritance.
+ //
+ xml_schema::serializer_base* s =
+ person_s.root_map ().find (dt.c_str ());
+
+#ifdef XSDE_REUSE_STYLE_MIXIN
+ ps = dynamic_cast<person_sskel*> (s);
+#else
+ ps = static_cast<person_sskel*> (s);
+#endif
+ }
+
+ // Create a document serializer for this object. Note that we pass
+ // true as the third argument to indicate polymorphic serialization
+ // as well as the root element's static type as the last argument
+ // which is necessary if the actual root type can differ from its
+ // static type.
+ //
+ xml_schema::document_simpl doc_s (
+ *ps, person_s.root_name (), true, person_sskel::_static_type ());
+
+ doc_s.add_no_namespace_schema ("supermen.xsd");
+
+ ps->pre (*p);
+ doc_s.serialize (std::cout);
+ ps->post ();
+ }
+ catch (const xml_schema::parser_exception& e)
+ {
+ cerr << input << ":" << e.line () << ":" << e.column () << ": "
+ << e.text () << endl;
+ return 1;
+ }
+ catch (const xml_schema::serializer_exception& e)
+ {
+ cerr << "error: " << e.text () << endl;
+ return 1;
+ }
+ catch (const std::ios_base::failure&)
+ {
+ cerr << input << ": unable to open or read/write failure" << endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifndef NDEBUG
+// Check that the load in substitution and inheritance hashmaps is not
+// too high. See the C++/Parser and C++/Serializer Mappings Getting
+// Started Guides for details.
+//
+void
+check_load ()
+{
+ // Parser.
+ //
+ float load = (float) 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;
+ }
+
+#ifdef XSDE_PARSER_VALIDATION
+ load = (float) 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
+
+ // Serializer.
+ //
+ load = (float) 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 = (float) 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;
+ }
+
+#ifdef XSDE_SERIALIZER_VALIDATION
+ load = (float) 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
+}
+#endif
diff --git a/examples/cxx/hybrid/polyroot/makefile b/examples/cxx/hybrid/polyroot/makefile
new file mode 100644
index 0000000..6bcc4ee
--- /dev/null
+++ b/examples/cxx/hybrid/polyroot/makefile
@@ -0,0 +1,115 @@
+# file : examples/cxx/hybrid/polyroot/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+xsd := supermen.xsd
+cxx := driver.cxx
+
+obj := $(addprefix $(out_base)/,\
+$(cxx:.cxx=.o) \
+$(xsd:.xsd=.o) \
+$(xsd:.xsd=-pskel.o) \
+$(xsd:.xsd=-pimpl.o) \
+$(xsd:.xsd=-sskel.o) \
+$(xsd:.xsd=-simpl.o))
+
+dep := $(obj:.o=.o.d)
+
+xsde.l := $(out_root)/libxsde/xsde/xsde.l
+xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options
+
+driver := $(out_base)/driver
+dist := $(out_base)/.dist
+dist-win := $(out_base)/.dist-win
+clean := $(out_base)/.clean
+
+# Build.
+#
+$(driver): $(obj) $(xsde.l)
+
+$(obj) $(dep): $(xsde.l.cpp-options)
+
+genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \
+ $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \
+ $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) \
+ $(xsd:.xsd=-sskel.hxx) $(xsd:.xsd=-sskel.cxx) \
+ $(xsd:.xsd=-simpl.hxx) $(xsd:.xsd=-simpl.cxx)
+
+gen := $(addprefix $(out_base)/,$(genf))
+
+$(gen): $(out_root)/xsde/xsde
+$(gen): xsde := $(out_root)/xsde/xsde
+$(gen): xsde_options += --generate-parser --generate-serializer \
+--generate-aggregate --generate-polymorphic --generate-typeinfo \
+--root-element person
+
+$(call include-dep,$(dep))
+
+# Convenience alias for default target.
+#
+.PHONY: $(out_base)/
+$(out_base)/: $(driver)
+
+
+# Dist.
+#
+dist-common := $(out_base)/.dist-common
+
+.PHONY: $(dist) $(dist-win) $(dist-common)
+
+$(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base))
+
+$(dist-common):
+ $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx)
+ $(call install-data,$(src_base)/supermen.xsd,$(dist_prefix)/$(path)/supermen.xsd)
+ $(call install-data,$(src_base)/person.xml,$(dist_prefix)/$(path)/person.xml)
+ $(call install-data,$(src_base)/superman.xml,$(dist_prefix)/$(path)/superman.xml)
+ $(call install-data,$(src_base)/batman.xml,$(dist_prefix)/$(path)/batman.xml)
+
+$(dist): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README)
+
+$(dist-win): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+
+# Clean.
+#
+.PHONY: $(clean)
+
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean))
+
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(gen): | $(out_base)/.gitignore
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver $(genf)
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+$(call include,$(bld_root)/install.make)
+$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make)
+
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsde/makefile)
+$(call import,$(src_root)/libxsde/xsde/makefile)
diff --git a/examples/cxx/hybrid/polyroot/person.xml b/examples/cxx/hybrid/polyroot/person.xml
new file mode 100644
index 0000000..c6ab1ff
--- /dev/null
+++ b/examples/cxx/hybrid/polyroot/person.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/polyroot/person.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="supermen.xsd">
+
+ <name>John Doe</name>
+
+</person>
diff --git a/examples/cxx/hybrid/polyroot/superman.xml b/examples/cxx/hybrid/polyroot/superman.xml
new file mode 100644
index 0000000..94a4f0b
--- /dev/null
+++ b/examples/cxx/hybrid/polyroot/superman.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/polyroot/superman.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<superman xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="supermen.xsd"
+ can-fly="false">
+
+ <name>James "007" Bond</name>
+
+</superman>
diff --git a/examples/cxx/hybrid/polyroot/supermen.xsd b/examples/cxx/hybrid/polyroot/supermen.xsd
new file mode 100644
index 0000000..9178168
--- /dev/null
+++ b/examples/cxx/hybrid/polyroot/supermen.xsd
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/polyroot/supermen.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsd:complexType name="person">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <!-- substitution group root -->
+ <xsd:element name="person" type="person"/>
+
+ <xsd:complexType name="superman">
+ <xsd:complexContent>
+ <xsd:extension base="person">
+ <xsd:attribute name="can-fly" type="xsd:boolean" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="superman" type="superman" substitutionGroup="person"/>
+
+ <xsd:complexType name="batman">
+ <xsd:complexContent>
+ <xsd:extension base="superman">
+ <xsd:attribute name="wing-span" type="xsd:unsignedInt" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+</xsd:schema>
diff --git a/examples/cxx/hybrid/streaming/driver.cxx b/examples/cxx/hybrid/streaming/driver.cxx
index ab2cd3a..86d0b87 100644
--- a/examples/cxx/hybrid/streaming/driver.cxx
+++ b/examples/cxx/hybrid/streaming/driver.cxx
@@ -5,7 +5,6 @@
#include <iostream>
#include "position.hxx"
-
#include "position-pimpl.hxx"
#include "position-simpl.hxx"
diff --git a/examples/cxx/hybrid/wildcard/driver.cxx b/examples/cxx/hybrid/wildcard/driver.cxx
index eea5bc7..69b6e67 100644
--- a/examples/cxx/hybrid/wildcard/driver.cxx
+++ b/examples/cxx/hybrid/wildcard/driver.cxx
@@ -8,7 +8,6 @@
#include "email.hxx"
#include "body.hxx"
-
#include "email-pimpl.hxx"
#include "email-simpl.hxx"
diff --git a/examples/cxx/parser/README b/examples/cxx/parser/README
index eaf9342..8afc5f9 100644
--- a/examples/cxx/parser/README
+++ b/examples/cxx/parser/README
@@ -1,7 +1,7 @@
-This directory contains a number of examples that show how to
-use the Embedded C++/Parser mapping. The following list gives
-an overview of each example. See the README files in example
-directories for more information on each example.
+This directory contains a number of examples that show how to use the
+Embedded C++/Parser mapping. The following list gives an overview of
+each example. See the README files in example directories for more
+information on each example.
hello
A simple "Hello, world!" example that shows how to parse XML
@@ -30,3 +30,11 @@ multiroot
mixed
Shows how to handle raw, "type-less content" such as mixed content
models, anyType/anySimpleType, and any/anyAttribute.
+
+polymorphism
+ Shows how to handle XML vocabularies that use XML Schema polymorphism
+ features such as the xsi:type attribute and substitution groups.
+
+polyroot
+ Shows how to handle XML vocabularies with polymorphic document root
+ elements.
diff --git a/examples/cxx/parser/polymorphism/README b/examples/cxx/parser/polymorphism/README
index 0b3d749..88140de 100644
--- a/examples/cxx/parser/polymorphism/README
+++ b/examples/cxx/parser/polymorphism/README
@@ -1,7 +1,7 @@
-This example shows how to handle XML Schema polymorphism features such
+This example shows how to handle the XML Schema polymorphism features such
as xsi:type attributes and substitution groups in the Embedded C++/Parser
-mapping. The case when xsi:type or substitution groups are used on root
-elements is covered in the polyroot examples.
+mapping. The case where xsi:type or substitution groups are used on document
+root elements is covered in the polyroot examples.
The example consists of the following files:
diff --git a/examples/cxx/serializer/README b/examples/cxx/serializer/README
index fa71ea3..f65f6b8 100644
--- a/examples/cxx/serializer/README
+++ b/examples/cxx/serializer/README
@@ -1,7 +1,7 @@
-This directory contains a number of examples that show how to
-use the Embedded C++/Serializer mapping. The following list
-gives an overview of each example. See the README files in
-example directories for more information on each example.
+This directory contains a number of examples that show how to use the
+Embedded C++/Serializer mapping. The following list gives an overview
+of each example. See the README files in example directories for more
+information on each example.
hello
A simple "Hello, world!" example that shows how to serialize
@@ -18,3 +18,11 @@ minimal
wildcard
Shows how to serialize XML data matched by XML Schema wildcards
(any and anyAttribute).
+
+polymorphism
+ Shows how to handle XML vocabularies that use XML Schema polymorphism
+ features such as the xsi:type attribute and substitution groups.
+
+polyroot
+ Shows how to handle XML vocabularies with polymorphic document root
+ elements.
diff --git a/examples/cxx/serializer/polymorphism/README b/examples/cxx/serializer/polymorphism/README
index 0e2c5b8..2d1ff6e 100644
--- a/examples/cxx/serializer/polymorphism/README
+++ b/examples/cxx/serializer/polymorphism/README
@@ -1,7 +1,7 @@
-This example shows how to handle XML Schema polymorphism features such as
+This example shows how to handle the XML Schema polymorphism features such as
xsi:type attributes and substitution groups in the Embedded C++/Serializer
-mapping. The case when xsi:type or substitution groups are used on root
-elements is covered in the polyroot examples.
+mapping. The case where xsi:type or substitution groups are used on document
+root elements is covered in the polyroot examples.
The example consists of the following files: