aboutsummaryrefslogtreecommitdiff
path: root/examples/cxx/parser/polyroot
diff options
context:
space:
mode:
Diffstat (limited to 'examples/cxx/parser/polyroot')
-rw-r--r--examples/cxx/parser/polyroot/README47
-rw-r--r--examples/cxx/parser/polyroot/batman.xml17
-rw-r--r--examples/cxx/parser/polyroot/driver.cxx216
-rw-r--r--examples/cxx/parser/polyroot/makefile71
-rw-r--r--examples/cxx/parser/polyroot/person.xml16
-rw-r--r--examples/cxx/parser/polyroot/superman.xml17
-rw-r--r--examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx83
-rw-r--r--examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx65
-rw-r--r--examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx101
-rw-r--r--examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx77
-rw-r--r--examples/cxx/parser/polyroot/supermen.xsd40
11 files changed, 750 insertions, 0 deletions
diff --git a/examples/cxx/parser/polyroot/README b/examples/cxx/parser/polyroot/README
new file mode 100644
index 0000000..4b01b56
--- /dev/null
+++ b/examples/cxx/parser/polyroot/README
@@ -0,0 +1,47 @@
+This example shows how to handle the xsi:type attributes and substitution
+groups when they are used on root elements. For general coverage of XML
+Schema polymorphism handling in the Embedded C++/Parser mapping 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-pskel.hxx
+supermen-pskel.cxx
+ Parser skeletons generated by the XSD/e compiler from supermen.xsd.
+ Note the use of the --generate-polymorphic command line option.
+
+supermen-pimpl-mixin.hxx
+supermen-pimpl-mixin.cxx
+
+supermen-pimpl-tiein.hxx
+supermen-pimpl-tiein.cxx
+ Parser implementations (using either mixin or tiein parser reuse
+ style) that print the XML data to STDOUT.
+
+driver.cxx
+ Driver for the example. It implements a custom document parser
+ that determines which XML Schema type is being parsed and uses
+ the corresponding parser implementation. The driver first
+ constructs a parser instance from all the individual parsers
+ found in one of supermen-pimpl-*.hxx. In then invokes this parser
+ instance to parse the input file.
+
+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/parser/polyroot/batman.xml b/examples/cxx/parser/polyroot/batman.xml
new file mode 100644
index 0000000..70abdf7
--- /dev/null
+++ b/examples/cxx/parser/polyroot/batman.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/parser/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/parser/polyroot/driver.cxx b/examples/cxx/parser/polyroot/driver.cxx
new file mode 100644
index 0000000..592ccfd
--- /dev/null
+++ b/examples/cxx/parser/polyroot/driver.cxx
@@ -0,0 +1,216 @@
+// file : examples/cxx/parser/polyroot/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <iostream>
+
+#include "supermen-pskel.hxx" // Get the configuration macros (XSDE_*).
+
+#if defined(XSDE_REUSE_STYLE_MIXIN)
+# include "supermen-pimpl-mixin.hxx"
+#elif defined(XSDE_REUSE_STYLE_TIEIN)
+# include "supermen-pimpl-tiein.hxx"
+#else
+# error this example requires mixin or tiein parser reuse support
+#endif
+
+using std::cerr;
+using std::endl;
+using xml_schema::ro_string;
+
+// Customize the xml_schema::document object to handle polymorphic
+// root element. For more information see the multiroot example.
+//
+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 (xml_schema::parser_map& parser_map)
+ : xml_schema::document_pimpl ("person"),
+ parser_map_ (parser_map),
+ parser_used_ (0)
+ {
+ }
+
+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" || !ns.empty ())
+ {
+ // 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 the parser map. If type is 0 then there is no xsi:type and
+ // static type should be used.
+ //
+ xml_schema::parser_base* p = parser_map_.find (
+ type ? type : person_pskel::_static_type ());
+
+ if (p != 0)
+ {
+ // 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.
+ //
+#ifdef XSDE_REUSE_STYLE_MIXIN
+ parser_used_ = dynamic_cast<person_pskel*> (p);
+#else
+ parser_used_ = static_cast<person_pskel*> (p);
+#endif
+ parser_used_->pre ();
+ }
+ else
+ {
+ // No parser for this type. We could also make this an error
+ // by calling the schema_error() function as above.
+ //
+ parser_used_ = 0;
+ }
+
+ return p;
+ }
+
+ // 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_)
+ 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_)
+ parser_used_->_reset ();
+ }
+
+private:
+ xml_schema::parser_map& parser_map_;
+ person_pskel* parser_used_;
+};
+
+int
+main (int argc, char* argv[])
+{
+ // Check that the load in substitution and inheritance hashmaps
+ // is not too high.
+ //
+#ifndef NDEBUG
+ 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
+#endif
+
+ const char* input;
+
+ if (argc < 2)
+ {
+ input = "STDIN";
+ cerr << "XML file not specified, reading from STDIN" << endl;
+ }
+ else
+ input = argv[1];
+
+ try
+ {
+ // Construct the parser.
+ //
+ xml_schema::string_pimpl string_p;
+ xml_schema::boolean_pimpl boolean_p;
+ xml_schema::unsigned_int_pimpl unsigned_int_p;
+
+ person_pimpl person_p;
+ superman_pimpl superman_p;
+ batman_pimpl batman_p;
+
+ person_p.parsers (string_p);
+ superman_p.parsers (string_p, boolean_p);
+ batman_p.parsers (string_p, boolean_p, unsigned_int_p);
+
+ // Parse the XML document.
+ //
+ xml_schema::parser_map_impl person_map (5); // 5 hashtable buckets
+
+ person_map.insert (person_p);
+ person_map.insert (superman_p);
+ person_map.insert (batman_p);
+
+ document_pimpl doc_p (person_map);
+
+ // pre() and post() will be called as part of the start_root_element()
+ // and end_root_element() calls.
+ //
+ if (argc < 2)
+ doc_p.parse (std::cin);
+ else
+ doc_p.parse (argv[1]);
+ }
+ catch (const xml_schema::parser_exception& e)
+ {
+ cerr << input << ":" << e.line () << ":" << e.column () << ": "
+ << e.text () << endl;
+ return 1;
+ }
+ catch (const std::ios_base::failure&)
+ {
+ cerr << input << ": unable to open or read failure" << endl;
+ return 1;
+ }
+}
diff --git a/examples/cxx/parser/polyroot/makefile b/examples/cxx/parser/polyroot/makefile
new file mode 100644
index 0000000..0f4d6eb
--- /dev/null
+++ b/examples/cxx/parser/polyroot/makefile
@@ -0,0 +1,71 @@
+# file : examples/cxx/parser/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
+
+ifeq ($(xsde_reuse_style),mixin)
+cxx += supermen-pimpl-mixin.cxx
+else
+cxx += supermen-pimpl-tiein.cxx
+endif
+
+obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.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
+clean := $(out_base)/.clean
+
+
+# Build.
+#
+$(driver): $(obj) $(xsde.l)
+
+$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base)
+$(obj) $(dep): $(xsde.l.cpp-options)
+
+skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \
+ $(out_base)/$(xsd:.xsd=-pskel.ixx) \
+ $(out_base)/$(xsd:.xsd=-pskel.cxx)
+
+$(skel): xsde := $(out_root)/xsde/xsde
+$(skel): xsde_options += --generate-polymorphic
+$(skel): $(out_root)/xsde/xsde
+
+$(call include-dep,$(dep))
+
+# Convenience alias for default target.
+#
+.PHONY: $(out_base)/
+$(out_base)/: $(driver)
+
+
+# Clean.
+#
+.PHONY: $(clean)
+
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean))
+
+
+# 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,$(scf_root)/xsde/parser/xsd-cxx.make)
+
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsde/makefile)
+$(call import,$(src_root)/libxsde/xsde/makefile)
diff --git a/examples/cxx/parser/polyroot/person.xml b/examples/cxx/parser/polyroot/person.xml
new file mode 100644
index 0000000..157a5af
--- /dev/null
+++ b/examples/cxx/parser/polyroot/person.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/parser/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/parser/polyroot/superman.xml b/examples/cxx/parser/polyroot/superman.xml
new file mode 100644
index 0000000..0f4b89c
--- /dev/null
+++ b/examples/cxx/parser/polyroot/superman.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/parser/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/parser/polyroot/supermen-pimpl-mixin.cxx b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx
new file mode 100644
index 0000000..fb339ac
--- /dev/null
+++ b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx
@@ -0,0 +1,83 @@
+// file : examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+//
+
+#include <iostream>
+
+#include "supermen-pimpl-mixin.hxx"
+
+using std::cout;
+using std::endl;
+
+// person_pimpl
+//
+void person_pimpl::
+pre ()
+{
+ cout << "starting to parse person" << endl;
+}
+
+void person_pimpl::
+name (const std::string& v)
+{
+ cout << "name: " << v << endl;
+}
+
+void person_pimpl::
+post_person ()
+{
+ cout << "finished parsing person" << endl;
+}
+
+// superman_pimpl
+//
+void superman_pimpl::
+pre ()
+{
+ cout << "starting to parse superman" << endl;
+}
+
+void superman_pimpl::
+can_fly (bool v)
+{
+ cout << "can-fly: " << v << endl;
+}
+
+void superman_pimpl::
+post_person ()
+{
+ post_superman ();
+}
+
+void superman_pimpl::
+post_superman ()
+{
+ cout << "finished parsing superman" << endl;
+}
+
+// batman_pimpl
+//
+void batman_pimpl::
+pre ()
+{
+ cout << "starting to parse batman" << endl;
+}
+
+void batman_pimpl::
+wing_span (unsigned int v)
+{
+ cout << "wing-span: " << v << endl;
+}
+
+void batman_pimpl::
+post_superman ()
+{
+ post_batman ();
+}
+
+void batman_pimpl::
+post_batman ()
+{
+ cout << "finished parsing batman" << endl;
+}
diff --git a/examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx
new file mode 100644
index 0000000..1f66062
--- /dev/null
+++ b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx
@@ -0,0 +1,65 @@
+// file : examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#ifndef SUPERMEN_PIMPL_HXX
+#define SUPERMEN_PIMPL_HXX
+
+#include "supermen-pskel.hxx"
+
+class person_pimpl: public virtual person_pskel
+{
+public:
+ virtual void
+ pre ();
+
+ virtual void
+ name (const std::string&);
+
+ virtual void
+ post_person ();
+};
+
+class superman_pimpl: public virtual superman_pskel,
+ public person_pimpl
+{
+public:
+ virtual void
+ pre ();
+
+ virtual void
+ can_fly (bool);
+
+ // By default, post_superman() calls post_person(). In case of
+ // polymorphic parsing we want the opposite: post_person() calls
+ // post_superman().
+ //
+ virtual void
+ post_person ();
+
+ virtual void
+ post_superman ();
+};
+
+class batman_pimpl: public virtual batman_pskel,
+ public superman_pimpl
+{
+public:
+ virtual void
+ pre ();
+
+ virtual void
+ wing_span (unsigned int);
+
+ // By default, post_batman() calls post_superman(). In case of
+ // polymorphic parsing we want the opposite: post_superman()
+ // calls post_batman().
+ //
+ virtual void
+ post_superman ();
+
+ virtual void
+ post_batman ();
+};
+
+#endif // SUPERMEN_PIMPL_HXX
diff --git a/examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx
new file mode 100644
index 0000000..b02eeef
--- /dev/null
+++ b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx
@@ -0,0 +1,101 @@
+// file : examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+//
+
+#include <iostream>
+
+#include "supermen-pimpl-tiein.hxx"
+
+using std::cout;
+using std::endl;
+
+// person_pimpl
+//
+void person_pimpl::
+pre ()
+{
+ cout << "starting to parse person" << endl;
+}
+
+void person_pimpl::
+name (const std::string& v)
+{
+ cout << "name: " << v << endl;
+}
+
+void person_pimpl::
+post_person ()
+{
+ cout << "finished parsing person" << endl;
+}
+
+// superman_pimpl
+//
+superman_pimpl::
+superman_pimpl ()
+ : superman_pskel (&base_impl_)
+{
+}
+
+void superman_pimpl::
+pre ()
+{
+ cout << "starting to parse superman" << endl;
+}
+
+void superman_pimpl::
+can_fly (bool v)
+{
+ cout << "can-fly: " << v << endl;
+}
+
+void superman_pimpl::
+post_person ()
+{
+ post_superman ();
+}
+
+void superman_pimpl::
+post_superman ()
+{
+ cout << "finished parsing superman" << endl;
+}
+
+// batman_pimpl
+//
+batman_pimpl::
+batman_pimpl ()
+ : batman_pskel (&base_impl_)
+{
+}
+
+void batman_pimpl::
+pre ()
+{
+ cout << "starting to parse batman" << endl;
+}
+
+void batman_pimpl::
+wing_span (unsigned int v)
+{
+ cout << "wing-span: " << v << endl;
+}
+
+void batman_pimpl::
+post_person ()
+{
+ post_superman ();
+}
+
+void batman_pimpl::
+post_superman ()
+{
+ post_batman ();
+}
+
+void batman_pimpl::
+post_batman ()
+{
+ cout << "finished parsing batman" << endl;
+}
diff --git a/examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx
new file mode 100644
index 0000000..41dfe84
--- /dev/null
+++ b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx
@@ -0,0 +1,77 @@
+// file : examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#ifndef SUPERMEN_PIMPL_HXX
+#define SUPERMEN_PIMPL_HXX
+
+#include "supermen-pskel.hxx"
+
+class person_pimpl: public person_pskel
+{
+public:
+ virtual void
+ pre ();
+
+ virtual void
+ name (const std::string&);
+
+ virtual void
+ post_person ();
+};
+
+class superman_pimpl: public superman_pskel
+{
+public:
+ superman_pimpl ();
+
+ virtual void
+ pre ();
+
+ virtual void
+ can_fly (bool);
+
+ // By default, post_superman() calls post_person(). In case of
+ // polymorphic parsing we want the opposite: post_person() calls
+ // post_superman().
+ //
+ virtual void
+ post_person ();
+
+ virtual void
+ post_superman ();
+
+private:
+ person_pimpl base_impl_;
+};
+
+class batman_pimpl: public batman_pskel
+{
+public:
+ batman_pimpl ();
+
+ virtual void
+ pre ();
+
+ virtual void
+ wing_span (unsigned int);
+
+ // By default, post_batman() calls post_superman() which calls
+ // post_person(). In case of polymorphic parsing we want the
+ // opposite: post_person() calls post_superman() which calls
+ // post_batman().
+ //
+ virtual void
+ post_person ();
+
+ virtual void
+ post_superman ();
+
+ virtual void
+ post_batman ();
+
+private:
+ superman_pimpl base_impl_;
+};
+
+#endif // SUPERMEN_PIMPL_HXX
diff --git a/examples/cxx/parser/polyroot/supermen.xsd b/examples/cxx/parser/polyroot/supermen.xsd
new file mode 100644
index 0000000..722d59b
--- /dev/null
+++ b/examples/cxx/parser/polyroot/supermen.xsd
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/parser/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>