diff options
Diffstat (limited to 'examples/cxx/serializer/polymorphism')
-rw-r--r-- | examples/cxx/serializer/polymorphism/README | 44 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/driver.cxx | 120 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/makefile | 73 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/supermen-simpl-mixin.cxx | 83 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/supermen-simpl-mixin.hxx | 51 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/supermen-simpl-tiein.cxx | 108 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/supermen-simpl-tiein.hxx | 69 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/supermen.hxx | 129 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/supermen.map | 10 | ||||
-rw-r--r-- | examples/cxx/serializer/polymorphism/supermen.xsd | 49 |
10 files changed, 736 insertions, 0 deletions
diff --git a/examples/cxx/serializer/polymorphism/README b/examples/cxx/serializer/polymorphism/README new file mode 100644 index 0000000..0e2c5b8 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/README @@ -0,0 +1,44 @@ +This example shows how to handle 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. + +The example consists of the following files: + +supermen.xsd + XML Schema which describes supermen instance documents. + +supermen.hxx + Types that describe the supermen object model in C++. These + are hand-written. + +supermen.map + Type map. It maps XML Schema types defined in supermen.xsd to + C++ types defined in supermen.hxx. + +supermen-sskel.hxx +supermen-sskel.cxx + Serializer skeletons generated by XSD/e from supermen.xsd and + supermen.map. + +supermen-simpl-mixin.hxx +supermen-simpl-mixin.cxx + +supermen-simpl-tiein.hxx +supermen-simpl-tiein.cxx + Serializer implementations (using either mixin or tiein parser + reuse style) that serialize the custom in-memory object model to + XML. These are hand-written implementations of the serializer + skeletons defined in supermen-sskel.hxx. + +driver.cxx + Driver for the example. It first constructs a sample object model + using the types from supermen.hxx. It then creates a serializer + instance using all the individual serializers found in one of + supermen-simpl-*.hxx. Finally, it invokes this serializer instance + to serialize the sample object model to an XML document which is + printed to STDOUT. + +To run the example simply execute: + +$ ./driver diff --git a/examples/cxx/serializer/polymorphism/driver.cxx b/examples/cxx/serializer/polymorphism/driver.cxx new file mode 100644 index 0000000..3015133 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/driver.cxx @@ -0,0 +1,120 @@ +// file : examples/cxx/serializer/polymorphism/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "supermen.hxx" + +#include "supermen-sskel.hxx" // Get the configuration macros (XSDE_*). + +#if defined(XSDE_REUSE_STYLE_MIXIN) +# include "supermen-simpl-mixin.hxx" +#elif defined(XSDE_REUSE_STYLE_TIEIN) +# include "supermen-simpl-tiein.hxx" +#else +# error this example requires mixin or tiein serializer reuse support +#endif + +using std::cerr; +using std::endl; + +int +main () +{ + // Check that the load in substitution and inheritance hashmaps + // is not too high. + // +#ifndef NDEBUG + float 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 + + try + { + // Create a sample supermen catalog. To keep things simple the + // following code is not exception-safe. + // + supermen sm; + + sm.push_back (new person ("John Doe")); + sm.push_back (new superman ("James 007 Bond", false)); + sm.push_back (new batman ("Bruce Wayne", 10)); + + // Construct the serializer. + // + xml_schema::string_simpl string_s; + xml_schema::boolean_simpl boolean_s; + xml_schema::unsigned_int_simpl unsigned_int_s; + + person_simpl person_s; + superman_simpl superman_s; + batman_simpl batman_s; + + xml_schema::serializer_map_impl person_map (5); // 5 hashtable buckets + supermen_simpl supermen_s; + + person_s.serializers (string_s); + superman_s.serializers (string_s, boolean_s); + batman_s.serializers (string_s, boolean_s, unsigned_int_s); + + // Here we are specifying several serializers that can be + // used to serialize the person element. + // + person_map.insert (person_s); + person_map.insert (superman_s); + person_map.insert (batman_s); + + supermen_s.person_serializer (person_map); + + // Create the XML instance document. The last argument to the + // document's constructor indicates that we are serializing + // polymorphic XML documents. + // + xml_schema::document_simpl doc_s (supermen_s, "supermen", true); + + doc_s.add_no_namespace_schema ("supermen.xsd"); + + supermen_s.pre (sm); + doc_s.serialize (std::cout); + supermen_s.post (); + } + catch (const xml_schema::serializer_exception& e) + { + cerr << "error: " << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << "error: write failure" << endl; + return 1; + } + + return 0; +} diff --git a/examples/cxx/serializer/polymorphism/makefile b/examples/cxx/serializer/polymorphism/makefile new file mode 100644 index 0000000..1841794 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/makefile @@ -0,0 +1,73 @@ +# file : examples/cxx/serializer/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 + +ifeq ($(xsde_reuse_style),mixin) +cxx += supermen-simpl-mixin.cxx +else +cxx += supermen-simpl-tiein.cxx +endif + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-sskel.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=-sskel.hxx) \ + $(out_base)/$(xsd:.xsd=-sskel.ixx) \ + $(out_base)/$(xsd:.xsd=-sskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): xsde_options += --generate-polymorphic \ +--type-map $(src_base)/supermen.map + +$(skel): $(out_root)/xsde/xsde $(src_base)/supermen.map + +$(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=-sskel.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/serializer/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/serializer/polymorphism/supermen-simpl-mixin.cxx b/examples/cxx/serializer/polymorphism/supermen-simpl-mixin.cxx new file mode 100644 index 0000000..328cc2f --- /dev/null +++ b/examples/cxx/serializer/polymorphism/supermen-simpl-mixin.cxx @@ -0,0 +1,83 @@ +// file : examples/cxx/serializer/polymorphism/supermen-simpl-mixin.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "supermen-simpl-mixin.hxx" + +// +// +void person_simpl:: +pre (const person& p) +{ + person_ = &p; +} + +std::string person_simpl:: +name () +{ + return person_->name (); +} + +// +// +bool superman_simpl:: +can_fly () +{ + return static_cast<const superman*> (person_)->can_fly (); +} + +// +// +unsigned int batman_simpl:: +wing_span () +{ + return static_cast<const batman*> (person_)->wing_span (); +} + +// +// +void supermen_simpl:: +pre (const supermen& s) +{ + supermen_ = &s; + i_ = s.begin (); +} + +bool supermen_simpl:: +person_next () +{ + return i_ != supermen_->end (); +} + +const person& supermen_simpl:: +person () +{ + const ::person& p = **i_++; + + // Map type id to serializer type. We could have also done this in a + // custom serializer_map implementation in which case we could simply + // pass a pointer to the person instance as type id. + // + xml_schema::serializer_context& ctx = _context (); + + switch (p.type ()) + { + case person_type: + { + ctx.type_id (person_sskel::_static_type ()); + break; + } + case superman_type: + { + ctx.type_id (superman_sskel::_static_type ()); + break; + } + case batman_type: + { + ctx.type_id (batman_sskel::_static_type ()); + break; + } + } + + return p; +} diff --git a/examples/cxx/serializer/polymorphism/supermen-simpl-mixin.hxx b/examples/cxx/serializer/polymorphism/supermen-simpl-mixin.hxx new file mode 100644 index 0000000..04b8b18 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/supermen-simpl-mixin.hxx @@ -0,0 +1,51 @@ +// file : examples/cxx/serializer/polymorphism/library-simpl-mixin.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SUPERMEN_SIMPL_HXX +#define SUPERMEN_SIMPL_HXX + +#include "supermen.hxx" +#include "supermen-sskel.hxx" + +struct person_simpl: virtual person_sskel +{ + virtual void + pre (const person&); + + virtual std::string + name (); + +protected: + const person* person_; +}; + +struct superman_simpl: virtual superman_sskel, person_simpl +{ + virtual bool + can_fly (); +}; + +struct batman_simpl: virtual batman_sskel, superman_simpl +{ + virtual unsigned int + wing_span (); +}; + +struct supermen_simpl: virtual supermen_sskel +{ + virtual void + pre (const supermen&); + + virtual bool + person_next (); + + virtual const ::person& + person (); + +private: + const supermen* supermen_; + supermen::const_iterator i_; +}; + +#endif // SUPERMEN_SIMPL_HXX diff --git a/examples/cxx/serializer/polymorphism/supermen-simpl-tiein.cxx b/examples/cxx/serializer/polymorphism/supermen-simpl-tiein.cxx new file mode 100644 index 0000000..77466b3 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/supermen-simpl-tiein.cxx @@ -0,0 +1,108 @@ +// file : examples/cxx/serializer/polymorphism/supermen-simpl-tiein.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "supermen-simpl-tiein.hxx" + +// +// +void person_simpl:: +pre (const person& p) +{ + person_ = &p; +} + +std::string person_simpl:: +name () +{ + return person_->name (); +} + +// +// +superman_simpl:: +superman_simpl () + : superman_sskel (&base_impl_) +{ +} + +bool superman_simpl:: +can_fly () +{ + return superman_ ().can_fly (); +} + +const superman& superman_simpl:: +superman_ () +{ + return *static_cast<const superman*> (base_impl_.person_); +} + +// +// +batman_simpl:: +batman_simpl () + : batman_sskel (&base_impl_) +{ +} + +unsigned int batman_simpl:: +wing_span () +{ + return batman_ ().wing_span (); +} + +const batman& batman_simpl:: +batman_ () +{ + return static_cast<const batman&> (base_impl_.superman_ ()); +} + +// +// +void supermen_simpl:: +pre (const supermen& s) +{ + supermen_ = &s; + i_ = s.begin (); +} + +bool supermen_simpl:: +person_next () +{ + return i_ != supermen_->end (); +} + +const person& supermen_simpl:: +person () +{ + const ::person& p = **i_++; + + // Map type id to serializer type. We could have also done this in a + // custom serializer_map implementation in which case we could simply + // pass a pointer to the person instance as type id. + // + xml_schema::serializer_context& ctx = _context (); + + switch (p.type ()) + { + case person_type: + { + ctx.type_id (person_sskel::_static_type ()); + break; + } + case superman_type: + { + ctx.type_id (superman_sskel::_static_type ()); + break; + } + case batman_type: + { + ctx.type_id (batman_sskel::_static_type ()); + break; + } + } + + return p; +} + diff --git a/examples/cxx/serializer/polymorphism/supermen-simpl-tiein.hxx b/examples/cxx/serializer/polymorphism/supermen-simpl-tiein.hxx new file mode 100644 index 0000000..806d017 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/supermen-simpl-tiein.hxx @@ -0,0 +1,69 @@ +// file : examples/cxx/serializer/polymorphism/supermen-simpl-tiein.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SUPERMEN_SIMPL_HXX +#define SUPERMEN_SIMPL_HXX + +#include "supermen.hxx" +#include "supermen-sskel.hxx" + +struct person_simpl: person_sskel +{ + virtual void + pre (const person&); + + virtual std::string + name (); + + // Derived serializers need access to this variable. + // +public: + const person* person_; +}; + +struct superman_simpl: superman_sskel +{ + superman_simpl (); + + virtual bool + can_fly (); + + const superman& + superman_ (); + +private: + person_simpl base_impl_; +}; + +struct batman_simpl: batman_sskel +{ + batman_simpl (); + + virtual unsigned int + wing_span (); + + const batman& + batman_ (); + +private: + superman_simpl base_impl_; +}; + +struct supermen_simpl: supermen_sskel +{ + virtual void + pre (const supermen&); + + virtual bool + person_next (); + + virtual const ::person& + person (); + +private: + const supermen* supermen_; + supermen::const_iterator i_; +}; + +#endif // SUPERMEN_SIMPL_HXX diff --git a/examples/cxx/serializer/polymorphism/supermen.hxx b/examples/cxx/serializer/polymorphism/supermen.hxx new file mode 100644 index 0000000..a04b8dd --- /dev/null +++ b/examples/cxx/serializer/polymorphism/supermen.hxx @@ -0,0 +1,129 @@ +// file : examples/cxx/serializer/polymorphism/supermen.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SUPERMEN_HXX +#define SUPERMEN_HXX + +#include <string> +#include <vector> + +// Custom type id. We could also use standard C++ typeid/type_info +// if it is available. +// +enum type_id +{ + person_type, + superman_type, + batman_type +}; + +// +// +struct person +{ + virtual + ~person () + { + } + + person (const std::string& name) + : name_ (name) + { + } + + const std::string& + name () const + { + return name_; + } + + void + name (const std::string& n) + { + name_ = n; + } + + virtual type_id + type () const + { + return person_type; + } + +private: + std::string name_; +}; + +// +// +struct superman: person +{ + superman (const std::string& name, bool can_fly) + : person (name), can_fly_ (can_fly) + { + } + + bool + can_fly () const + { + return can_fly_; + } + + void + can_fly (bool cf) + { + can_fly_ = cf; + } + + virtual type_id + type () const + { + return superman_type; + } + +private: + bool can_fly_; +}; + +struct batman: superman +{ + batman (const std::string& name, unsigned int wing_span) + : superman (name, true), wing_span_ (wing_span) + { + } + + unsigned int + wing_span () const + { + return wing_span_; + } + + void + wing_span (unsigned int ws) + { + wing_span_ = ws; + } + + virtual type_id + type () const + { + return batman_type; + } + +private: + unsigned int wing_span_; +}; + +// Poor man's polymorphic sequence which also assumes ownership of the +// elements. +// +struct supermen: std::vector<person*> +{ + ~supermen () + { + for (iterator i = begin (); i != end (); ++i) + delete *i; + } +}; + +#endif // SUPERMEN_HXX diff --git a/examples/cxx/serializer/polymorphism/supermen.map b/examples/cxx/serializer/polymorphism/supermen.map new file mode 100644 index 0000000..ef39a19 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/supermen.map @@ -0,0 +1,10 @@ +# file : examples/cxx/serializer/polymorphism/supermen.map +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : not copyrighted - public domain + +include "supermen.hxx"; + +person "const ::person&"; +superman "const ::person&"; +batman "const ::person&"; +supermen "const ::supermen&"; diff --git a/examples/cxx/serializer/polymorphism/supermen.xsd b/examples/cxx/serializer/polymorphism/supermen.xsd new file mode 100644 index 0000000..890c7e4 --- /dev/null +++ b/examples/cxx/serializer/polymorphism/supermen.xsd @@ -0,0 +1,49 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/serializer/polymorphism/schema.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> |