aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-10-18 11:17:51 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-10-18 11:17:51 +0200
commitd80d096ee8743fd6f7382d274272b0b6d7faf9bf (patch)
treed0f0bee1e645cb2b86b6837ac0db8a7d2821e533 /examples
parent0e4637025fa8d1b4234b0512561d31f0dd023843 (diff)
Support for schema evolution using substitution groups
New examples: hybrid/evolution/ignore and hybrid/evolution/passthrough.
Diffstat (limited to 'examples')
-rw-r--r--examples/cxx/hybrid/README3
-rw-r--r--examples/cxx/hybrid/evolution/README13
-rw-r--r--examples/cxx/hybrid/evolution/ignore/README61
-rw-r--r--examples/cxx/hybrid/evolution/ignore/driver.cxx131
-rw-r--r--examples/cxx/hybrid/evolution/ignore/makefile103
-rw-r--r--examples/cxx/hybrid/evolution/ignore/transform-v2.xsd93
-rw-r--r--examples/cxx/hybrid/evolution/ignore/transform.xml32
-rw-r--r--examples/cxx/hybrid/evolution/ignore/transform.xsd69
-rw-r--r--examples/cxx/hybrid/evolution/makefile45
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/README104
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/driver.cxx193
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/makefile120
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd103
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/transform.xml32
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/transform.xsd79
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx142
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx66
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx80
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx34
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx17
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx51
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/xml.cxx19
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/xml.hxx111
-rw-r--r--examples/cxx/hybrid/evolution/passthrough/xml.ixx129
-rw-r--r--examples/cxx/hybrid/makefile3
25 files changed, 1832 insertions, 1 deletions
diff --git a/examples/cxx/hybrid/README b/examples/cxx/hybrid/README
index dabc11f..2761db4 100644
--- a/examples/cxx/hybrid/README
+++ b/examples/cxx/hybrid/README
@@ -53,6 +53,9 @@ custom/
to the generated ones. See the accompanying README file for an
overview of each example in this directory.
+evolution/
+ A collection of examples that show how to handle schema evolution.
+
binary/
A collection of examples that show how to serialize the object model
into a number of predefined and custom binary formats.
diff --git a/examples/cxx/hybrid/evolution/README b/examples/cxx/hybrid/evolution/README
new file mode 100644
index 0000000..878cb50
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/README
@@ -0,0 +1,13 @@
+This directory contains a number of examples that show how to handle schema
+evolution using the C++/Hybrid mapping. The following list gives an overview
+of each example:
+
+ignore
+ Shows how to handle schema evolution using substitution groups. This
+ example ignores unknown elements.
+
+passthrough
+ Shows how to handle schema evolution using substitution groups. This
+ example passes the unknown content through parsing and serialization
+ so that the output XML contains all the unknown elements.
+
diff --git a/examples/cxx/hybrid/evolution/ignore/README b/examples/cxx/hybrid/evolution/ignore/README
new file mode 100644
index 0000000..fb7272d
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/ignore/README
@@ -0,0 +1,61 @@
+This example shows how to handle schema evolution using substitution groups.
+The general idea is as follows: the initial version of the schema defines
+extension points using the XML Schema substitution group mechanism. The
+subsequent versions of the schema add new elements to the substitution
+groups. The goal here is for applications that were built using earlier
+versions of the schema to be able to handle documents corresponding to the
+newer versions without validation errors or any other failures. This example
+shows how to ignore such new elements. The 'passthrough' example shows how
+to pass the unknown content through parsing and serialization so that the
+output XML contains all the unknown elements.
+
+This example uses XML Schema polymorphism in the form of substitution groups.
+If you are not familiar with how to work with polymorphic object models,
+refer to the C++/Hybrid Mapping Getting Started Guide as well as the
+'polymorphism' example in the examples/cxx/hybrid/ directory.
+
+The example consists of the following files:
+
+transform.xsd
+ The initial version of the schema that describes simple transformations,
+ such as move and rotate. The schema makes it possible to add new
+ transformations in subsequent versions of the schema. Our example is built
+ using this schema.
+
+transform-v2.xsd
+ The second version of the schema which adds the scale transformation. This
+ schema is provided as an example.
+
+transform.xml
+ Sample XML document corresponding to the second version of the schema. In
+ particular, it contains the scale transformation which is unknown in
+ transform.xsd.
+
+transform.hxx
+transform.cxx
+
+transform-pskel.hxx
+transform-pskel.cxx
+
+transform-pimpl.hxx
+transform-pimpl.cxx
+ Object model (the first pair of files), parser skeletons (the second pair)
+ and parser implementations (the third pair). These files are generated by
+ the XSD/e compiler from transform.xsd. The --generate-parser and
+ --generate-aggregate options were used to request the generation of the
+ parsing code. The --generate-polymorphic option was used to request the
+ generation of the polymorphism-aware code.
+
+driver.cxx
+ Driver for the example. It first sets the substitution map callback that
+ is used to tell the parser which elements should be ignored. The driver
+ then calls the parser that constructs the object model from the input XML
+ file. Finally, it prints the content of the object model to STDERR.
+
+To run the example on the sample XML instance document simply execute:
+
+$ ./driver transform.xml
+
+The example reads from STDIN if input file is not specified:
+
+$ ./driver <transform.xml
diff --git a/examples/cxx/hybrid/evolution/ignore/driver.cxx b/examples/cxx/hybrid/evolution/ignore/driver.cxx
new file mode 100644
index 0000000..6c1c45f
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/ignore/driver.cxx
@@ -0,0 +1,131 @@
+// file : examples/cxx/hybrid/evolution/ignore/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <memory> // std::auto_ptr
+#include <string>
+#include <iostream>
+
+#include "transform.hxx"
+#include "transform-pimpl.hxx"
+
+using namespace std;
+using namespace transform;
+
+// Parser substitution map callback. This callback is called when the
+// parser needs to check whether an element belongs to a substitution
+// group. We use this callback to return a special ignored type marker
+// for unknown transformations.
+//
+static bool
+parser_callback (const xml_schema::ro_string& root_ns,
+ const xml_schema::ro_string& root_name,
+ const xml_schema::ro_string& /*member_ns*/,
+ const xml_schema::ro_string& member_name,
+ const char*& type)
+{
+ // Check that the root of the substitution group is 'transformation'.
+ //
+ if (root_name == "transformation" &&
+ root_ns == "http://www.codesynthesis.com/transform")
+ {
+ // Check that the element's name has the '-transformation' suffix. This
+ // is the convention we use in our schema to minimize the chance of
+ // treating any unknown elements as a transformation.
+ //
+ //
+ string s ("-transformation");
+ string n (member_name);
+
+ if (n.size () > s.size () &&
+ string (n, n.size () - s.size (), s.size ()) == s)
+ {
+ // Set type to the special ignore marker.
+ //
+ type = "*";
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int
+main (int argc, char* argv[])
+{
+ const char* input;
+
+ if (argc < 2)
+ {
+ input = "STDIN";
+ cerr << "XML file not specified, reading from STDIN" << endl;
+ }
+ else
+ input = argv[1];
+
+ try
+ {
+ // Set the substitution map callback.
+ //
+ xml_schema::parser_smap_callback (&parser_callback);
+
+ // Parse.
+ //
+ transformations_paggr transformations_p;
+
+ // The last argument to the document's constructor indicates that we
+ // are parsing polymorphic XML documents.
+ //
+ xml_schema::document_pimpl doc_p (
+ transformations_p.root_parser (),
+ transformations_p.root_namespace (),
+ transformations_p.root_name (),
+ true);
+
+ transformations_p.pre ();
+
+ if (argc < 2)
+ doc_p.parse (cin);
+ else
+ doc_p.parse (argv[1]);
+
+ auto_ptr<transformations_type> tf (transformations_p.post ());
+
+ // Print what we've got.
+ //
+ for (transformations_type::transformation_iterator i =
+ tf->transformation ().begin ();
+ i != tf->transformation ().end ();
+ ++i)
+ {
+ transformation_type& t = *i;
+
+ if (move_type* m = dynamic_cast<move_type*> (&t))
+ {
+ cout << m->name () << ": " << m->description () << endl
+ << "\tx: " << m->x () << endl
+ << "\ty: " << m->y () << endl
+ << endl;
+ }
+ else if (rotate_type* r = dynamic_cast<rotate_type*> (&t))
+ {
+ cout << r->name () << ": " << r->description () << endl
+ << "\tangle: " << r->angle () << endl
+ << endl;
+ }
+ }
+ }
+ 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/write failure" << endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/examples/cxx/hybrid/evolution/ignore/makefile b/examples/cxx/hybrid/evolution/ignore/makefile
new file mode 100644
index 0000000..cde32fb
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/ignore/makefile
@@ -0,0 +1,103 @@
+# file : examples/cxx/hybrid/evolution/ignore/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make
+
+xsd := transform.xsd
+cxx := driver.cxx
+
+obj := $(addprefix $(out_base)/,\
+$(cxx:.cxx=.o) \
+$(xsd:.xsd=.o) \
+$(xsd:.xsd=-pskel.o) \
+$(xsd:.xsd=-pimpl.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)
+
+gen := $(addprefix $(out_base)/,$(genf))
+
+$(gen): $(out_root)/xsde/xsde
+$(gen): xsde := $(out_root)/xsde/xsde
+$(gen): xsde_options += --generate-parser --generate-aggregate \
+--root-element transformations --generate-polymorphic
+
+$(call include-dep,$(dep))
+
+# Convenience alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Dist.
+#
+dist-common := $(out_base)/.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)/transform.xsd,$(dist_prefix)/$(path)/transform.xsd)
+ $(call install-data,$(src_base)/transform-v2.xsd,$(dist_prefix)/$(path)/transform-v2.xsd)
+ $(call install-data,$(src_base)/transform.xml,$(dist_prefix)/$(path)/transform.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.
+#
+$(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/evolution/ignore/transform-v2.xsd b/examples/cxx/hybrid/evolution/ignore/transform-v2.xsd
new file mode 100644
index 0000000..d9ceaec
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/ignore/transform-v2.xsd
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/evolution/ignore/transform-v2.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:tf="http://www.codesynthesis.com/transform"
+ targetNamespace="http://www.codesynthesis.com/transform"
+ elementFormDefault="qualified">
+
+ <xsd:complexType name="transformation_type" abstract="true">
+ <xsd:sequence>
+ <xsd:element name="description" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:element name="transformation" type="tf:transformation_type"/>
+
+ <!-- Document root. -->
+
+ <xsd:complexType name="transformations_type">
+ <xsd:sequence>
+ <xsd:element ref="tf:transformation" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="transformations" type="tf:transformations_type"/>
+
+ <!-- Move. -->
+
+ <xsd:complexType name="move_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="x" type="xsd:float"/>
+ <xsd:element name="y" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="move-transformation"
+ type="tf:move_type"
+ substitutionGroup="tf:transformation"/>
+
+ <!-- Rotate. -->
+
+ <xsd:complexType name="rotate_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="angle" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="rotate-transformation"
+ type="tf:rotate_type"
+ substitutionGroup="tf:transformation"/>
+
+ <!-- Scale. -->
+
+ <xsd:complexType name="ratio_type">
+ <xsd:sequence>
+ <xsd:element name="x" type="xsd:float"/>
+ <xsd:element name="y" type="xsd:float"/>
+ </xsd:sequence>
+ <xsd:attribute name="unit" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="scale_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="ratios" type="tf:ratio_type"/>
+ </xsd:sequence>
+ <xsd:attribute name="proportional" type="xsd:boolean"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="scale-transformation"
+ type="tf:scale_type"
+ substitutionGroup="tf:transformation"/>
+
+</xsd:schema>
diff --git a/examples/cxx/hybrid/evolution/ignore/transform.xml b/examples/cxx/hybrid/evolution/ignore/transform.xml
new file mode 100644
index 0000000..d7e8cef
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/ignore/transform.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/evolution/ignore/transform.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<transformations xmlns="http://www.codesynthesis.com/transform">
+
+ <move-transformation name="move">
+ <description>Move an object.</description>
+ <x>1.1</x>
+ <y>2.1</y>
+ </move-transformation>
+
+ <rotate-transformation name="rotate">
+ <description>Rotate an object.</description>
+ <angle>90</angle>
+ </rotate-transformation>
+
+ <scale-transformation name="scale" proportional="true">
+ <description>Scale an object.</description>
+ <ratios unit="percent">
+ <x>210</x>
+ <y>210</y>
+ </ratios>
+ </scale-transformation>
+
+</transformations>
diff --git a/examples/cxx/hybrid/evolution/ignore/transform.xsd b/examples/cxx/hybrid/evolution/ignore/transform.xsd
new file mode 100644
index 0000000..59cf48f
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/ignore/transform.xsd
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/evolution/ignore/transform.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:tf="http://www.codesynthesis.com/transform"
+ targetNamespace="http://www.codesynthesis.com/transform"
+ elementFormDefault="qualified">
+
+ <xsd:complexType name="transformation_type" abstract="true">
+ <xsd:sequence>
+ <xsd:element name="description" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:element name="transformation" type="tf:transformation_type"/>
+
+ <!-- Document root. -->
+
+ <xsd:complexType name="transformations_type">
+ <xsd:sequence>
+ <xsd:element ref="tf:transformation" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="transformations" type="tf:transformations_type"/>
+
+ <!-- Move. -->
+
+ <xsd:complexType name="move_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="x" type="xsd:float"/>
+ <xsd:element name="y" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="move-transformation"
+ type="tf:move_type"
+ substitutionGroup="tf:transformation"/>
+
+ <!-- Rotate. -->
+
+ <xsd:complexType name="rotate_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="angle" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="rotate-transformation"
+ type="tf:rotate_type"
+ substitutionGroup="tf:transformation"/>
+
+
+</xsd:schema>
diff --git a/examples/cxx/hybrid/evolution/makefile b/examples/cxx/hybrid/evolution/makefile
new file mode 100644
index 0000000..79f1873
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/makefile
@@ -0,0 +1,45 @@
+# file : examples/cxx/hybrid/evolution/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+all_examples := ignore passthrough
+build_examples :=
+
+ifeq ($(xsde_iostream),y)
+ifeq ($(xsde_exceptions),y)
+
+ifeq ($(xsde_stl),y)
+build_examples += ignore passthrough
+endif
+
+endif
+endif
+
+default := $(out_base)/
+dist := $(out_base)/.dist
+dist-win := $(out_base)/.dist-win
+clean := $(out_base)/.clean
+
+$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples)))
+$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples)))
+
+# Dist.
+#
+$(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base))
+
+$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples)))
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README)
+
+$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples)))
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+
+ifneq ($(filter $(MAKECMDGOALS),dist dist-win),)
+$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile))
+else
+$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile))
+endif
diff --git a/examples/cxx/hybrid/evolution/passthrough/README b/examples/cxx/hybrid/evolution/passthrough/README
new file mode 100644
index 0000000..a4a3803
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/README
@@ -0,0 +1,104 @@
+This example shows how to handle schema evolution using substitution groups.
+The general idea is as follows: the initial version of the schema defines
+extension points using the XML Schema substitution group mechanism. The
+subsequent versions of the schema add new elements to the substitution
+groups. The goal here is for applications that were built using earlier
+versions of the schema to be able to handle documents corresponding to the
+newer versions without validation errors or any other failures. This example
+shows how to pass the unknown content through parsing and serialization so
+that the output XML contains all the unknown elements. The 'ignore' example
+shows how to ignore such unknown elements.
+
+This example uses XML Schema polymorphism in the form of substitution groups.
+If you are not familiar with how to work with polymorphic object models,
+refer to the C++/Hybrid Mapping Getting Started Guide as well as the
+'polymorphism' example in the examples/cxx/hybrid/ directory.
+
+This example also customizes a generated object model type as well as parser
+and serializer implementations. If you are not familiar with the customization
+mechanisms, refer to the C++/Hybrid Mapping Getting Started Guide as well as
+the examples in the examples/cxx/hybrid/custom/ directory.
+
+The example consists of the following files:
+
+transform.xsd
+ The initial version of the schema that describes simple transformations,
+ such as move and rotate. The schema makes it possible to add new
+ transformations in subsequent versions of the schema. It also defines a
+ special unknown_type type which is used to handle unknown transformations.
+ Our example is built using this schema.
+
+transform-v2.xsd
+ The second version of the schema which adds the scale transformation. This
+ schema is provided as an example.
+
+transform.xml
+ Sample XML document corresponding to the second version of the schema. In
+ particular, it contains the scale transformation which is unknown in
+ transform.xsd.
+
+transform.hxx
+transform.cxx
+
+transform-pskel.hxx
+transform-pskel.cxx
+transform-pimpl.hxx
+transform-pimpl.cxx
+
+transform-sskel.hxx
+transform-sskel.cxx
+transform-simpl.hxx
+transform-simpl.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 transform.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. The --custom-type, --custom-parser, and
+ --custom-serializer options were used to customize the object model class
+ as well as the parser and serializer implementations for the unknown_type
+ XML Schema type.
+
+xml.hxx
+xml.ixx
+xml.cxx
+ Simple in-memory representation for raw XML. It is used to store the content
+ of unknown transformations.
+
+unknown-type.hxx
+unknown-type.cxx
+ Custom unknown_type class. It uses the generated version as a base and adds
+ members that store the raw XML representation of an unknown transformation
+ as well as the parsed element name and namespace from the substitution group.
+
+unknown-type-pimpl.hxx
+unknown-type-pimpl.cxx
+ Custom unknown_type parser implementation. It uses the implementation
+ generated by the XSD/e compiler as a base and overrides the raw XML
+ callbacks to parse the unknown content and store it in the customized
+ unknown_type class.
+
+unknown-type-simpl.hxx
+unknown-type-simpl.cxx
+ Custom unknown_type serializer implementation. It uses the implementation
+ generated by the XSD/e compiler as a base and overrides the raw XML
+ callbacks to serialize the unknown content stored in the customized
+ unknown_type class.
+
+driver.cxx
+ Driver for the example. It first sets the substitution map callbacks that
+ are used to alter the default element mapping in the parser and serializer.
+ The driver then calls the parser that constructs the object model from the
+ input XML file. It then prints the content of the object model to STDERR.
+ Finally, the driver calls the serializer to serialize the object model
+ back to XML.
+
+To run the example on the sample XML instance document simply execute:
+
+$ ./driver transform.xml
+
+The example reads from STDIN if input file is not specified:
+
+$ ./driver <transform.xml
diff --git a/examples/cxx/hybrid/evolution/passthrough/driver.cxx b/examples/cxx/hybrid/evolution/passthrough/driver.cxx
new file mode 100644
index 0000000..35a334c
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/driver.cxx
@@ -0,0 +1,193 @@
+// file : examples/cxx/hybrid/evolution/passthrough/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <memory> // std::auto_ptr
+#include <string>
+#include <iostream>
+
+#include "transform.hxx"
+#include "transform-pimpl.hxx"
+#include "transform-simpl.hxx"
+
+using namespace std;
+using namespace transform;
+
+// Parser substitution map callback. This callback is called when the
+// parser needs to check whether an element belongs to a substitution
+// group. We use this callback to handle unknown transformations.
+//
+static bool
+parser_callback (const xml_schema::ro_string& root_ns,
+ const xml_schema::ro_string& root_name,
+ const xml_schema::ro_string& /*member_ns*/,
+ const xml_schema::ro_string& member_name,
+ const char*& type)
+{
+ // Check that the root of the substitution group is 'transformation'.
+ //
+ if (root_name == "transformation" &&
+ root_ns == "http://www.codesynthesis.com/transform")
+ {
+ // Check that the element's name has the '-transformation' suffix. This
+ // is the convention we use in our schema to minimize the chance of
+ // treating any unknown elements as a transformation.
+ //
+ //
+ string s ("-transformation");
+ string n (member_name);
+
+ if (n.size () > s.size () &&
+ string (n, n.size () - s.size (), s.size ()) == s)
+ {
+ // Tell the parser to use unknown_type to parse this element.
+ //
+ type = unknown_type_pimpl::_static_type ();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Serializer substitution map callback. This callback is called when
+// the serializer needs to map a type to an element belonging to a
+// substitution group. We use this callback to handle unknown
+// transformations.
+//
+static bool
+serializer_callback (const char* type,
+ const void* obj,
+ const char*& ns,
+ const char*& name)
+{
+ // Check whether this is unknown_type.
+ //
+ if (string (type) == unknown_type_simpl::_static_type ())
+ {
+ // Cast the opaque obj pointer to unknown_type.
+ //
+ const unknown_type* u = reinterpret_cast<const unknown_type*> (obj);
+
+ // Extract the actual element name from the object.
+ //
+ const xml::qname& n (u->element_name ());
+ ns = n.ns ().c_str ();
+ name = n.name ().c_str ();
+
+ return true;
+ }
+
+ return false;
+}
+
+int
+main (int argc, char* argv[])
+{
+ const char* input;
+
+ if (argc < 2)
+ {
+ input = "STDIN";
+ cerr << "XML file not specified, reading from STDIN" << endl;
+ }
+ else
+ input = argv[1];
+
+ try
+ {
+ // Set the substitution map callbacks.
+ //
+ xml_schema::parser_smap_callback (&parser_callback);
+ xml_schema::serializer_smap_callback (&serializer_callback);
+
+ // Parse.
+ //
+ transformations_paggr transformations_p;
+
+ // The last argument to the document's constructor indicates that we
+ // are parsing polymorphic XML documents.
+ //
+ xml_schema::document_pimpl doc_p (
+ transformations_p.root_parser (),
+ transformations_p.root_namespace (),
+ transformations_p.root_name (),
+ true);
+
+ transformations_p.pre ();
+
+ if (argc < 2)
+ doc_p.parse (cin);
+ else
+ doc_p.parse (argv[1]);
+
+ auto_ptr<transformations_type> tf (transformations_p.post ());
+
+ // Print what we've got.
+ //
+ for (transformations_type::transformation_iterator i =
+ tf->transformation ().begin ();
+ i != tf->transformation ().end ();
+ ++i)
+ {
+ transformation_type& t = *i;
+
+ if (move_type* m = dynamic_cast<move_type*> (&t))
+ {
+ cout << m->name () << ": " << m->description () << endl
+ << "\tx: " << m->x () << endl
+ << "\ty: " << m->y () << endl
+ << endl;
+ }
+ else if (rotate_type* r = dynamic_cast<rotate_type*> (&t))
+ {
+ cout << r->name () << ": " << r->description () << endl
+ << "\tangle: " << r->angle () << endl
+ << endl;
+ }
+ else if (unknown_type* u = dynamic_cast<unknown_type*> (&t))
+ {
+ cout << u->name () << ": " << u->description () << endl
+ << "\ttransformation is unknown" << endl
+ << endl;
+ }
+ }
+
+ // Serialize.
+ //
+ transformations_saggr transformations_s;
+
+ // The last argument to the document's constructor indicates that we
+ // are serializing polymorphic XML documents.
+ //
+ xml_schema::document_simpl doc_s (
+ transformations_s.root_serializer (),
+ transformations_s.root_namespace (),
+ transformations_s.root_name (),
+ true);
+
+ doc_s.add_prefix ("", "http://www.codesynthesis.com/transform");
+
+ transformations_s.pre (*tf);
+ doc_s.serialize (cout, xml_schema::document_simpl::pretty_print);
+ transformations_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;
+}
diff --git a/examples/cxx/hybrid/evolution/passthrough/makefile b/examples/cxx/hybrid/evolution/passthrough/makefile
new file mode 100644
index 0000000..1f31f5c
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/makefile
@@ -0,0 +1,120 @@
+# file : examples/cxx/hybrid/evolution/passthrough/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make
+
+xsd := transform.xsd
+cxx := driver.cxx xml.cxx unknown-type.cxx unknown-type-pimpl.cxx \
+unknown-type-simpl.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 --root-element transformations --generate-polymorphic \
+--custom-type unknown_type=//unknown_type_base/unknown-type.hxx \
+--custom-parser unknown_type=unknown_type_base_pimpl/unknown-type-pimpl.hxx \
+--custom-serializer unknown_type=unknown_type_base_simpl/unknown-type-simpl.hxx
+
+$(call include-dep,$(dep))
+
+# Convenience alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Dist.
+#
+dist-common := $(out_base)/.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)/xml.hxx,$(dist_prefix)/$(path)/xml.hxx)
+ $(call install-data,$(src_base)/xml.ixx,$(dist_prefix)/$(path)/xml.ixx)
+ $(call install-data,$(src_base)/xml.cxx,$(dist_prefix)/$(path)/xml.cxx)
+ $(call install-data,$(src_base)/unknown-type.hxx,$(dist_prefix)/$(path)/unknown-type.hxx)
+ $(call install-data,$(src_base)/unknown-type.cxx,$(dist_prefix)/$(path)/unknown-type.cxx)
+ $(call install-data,$(src_base)/unknown-type-pimpl.hxx,$(dist_prefix)/$(path)/unknown-type-pimpl.hxx)
+ $(call install-data,$(src_base)/unknown-type-pimpl.cxx,$(dist_prefix)/$(path)/unknown-type-pimpl.cxx)
+ $(call install-data,$(src_base)/unknown-type-simpl.hxx,$(dist_prefix)/$(path)/unknown-type-simpl.hxx)
+ $(call install-data,$(src_base)/unknown-type-simpl.cxx,$(dist_prefix)/$(path)/unknown-type-simpl.cxx)
+ $(call install-data,$(src_base)/transform.xsd,$(dist_prefix)/$(path)/transform.xsd)
+ $(call install-data,$(src_base)/transform-v2.xsd,$(dist_prefix)/$(path)/transform-v2.xsd)
+ $(call install-data,$(src_base)/transform.xml,$(dist_prefix)/$(path)/transform.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.
+#
+$(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/evolution/passthrough/transform-v2.xsd b/examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd
new file mode 100644
index 0000000..72cc12c
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/evolution/passthrough/transform-v2.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:tf="http://www.codesynthesis.com/transform"
+ targetNamespace="http://www.codesynthesis.com/transform"
+ elementFormDefault="qualified">
+
+ <xsd:complexType name="transformation_type" abstract="true">
+ <xsd:sequence>
+ <xsd:element name="description" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:element name="transformation" type="tf:transformation_type"/>
+
+ <!-- Document root. -->
+
+ <xsd:complexType name="transformations_type">
+ <xsd:sequence>
+ <xsd:element ref="tf:transformation" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="transformations" type="tf:transformations_type"/>
+
+ <!-- Special type for unknown transformations. -->
+
+ <xsd:complexType name="unknown_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+
+ <!-- Move. -->
+
+ <xsd:complexType name="move_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="x" type="xsd:float"/>
+ <xsd:element name="y" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="move-transformation"
+ type="tf:move_type"
+ substitutionGroup="tf:transformation"/>
+
+ <!-- Rotate. -->
+
+ <xsd:complexType name="rotate_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="angle" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="rotate-transformation"
+ type="tf:rotate_type"
+ substitutionGroup="tf:transformation"/>
+
+ <!-- Scale. -->
+
+ <xsd:complexType name="ratio_type">
+ <xsd:sequence>
+ <xsd:element name="x" type="xsd:float"/>
+ <xsd:element name="y" type="xsd:float"/>
+ </xsd:sequence>
+ <xsd:attribute name="unit" type="xsd:string"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="scale_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="ratios" type="tf:ratio_type"/>
+ </xsd:sequence>
+ <xsd:attribute name="proportional" type="xsd:boolean"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="scale-transformation"
+ type="tf:scale_type"
+ substitutionGroup="tf:transformation"/>
+
+</xsd:schema>
diff --git a/examples/cxx/hybrid/evolution/passthrough/transform.xml b/examples/cxx/hybrid/evolution/passthrough/transform.xml
new file mode 100644
index 0000000..6747e3e
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/transform.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/evolution/passthrough/transform.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<transformations xmlns="http://www.codesynthesis.com/transform">
+
+ <move-transformation name="move">
+ <description>Move an object.</description>
+ <x>1.1</x>
+ <y>2.1</y>
+ </move-transformation>
+
+ <rotate-transformation name="rotate">
+ <description>Rotate an object.</description>
+ <angle>90</angle>
+ </rotate-transformation>
+
+ <scale-transformation name="scale" proportional="true">
+ <description>Scale an object.</description>
+ <ratios unit="percent">
+ <x>210</x>
+ <y>210</y>
+ </ratios>
+ </scale-transformation>
+
+</transformations>
diff --git a/examples/cxx/hybrid/evolution/passthrough/transform.xsd b/examples/cxx/hybrid/evolution/passthrough/transform.xsd
new file mode 100644
index 0000000..2400de1
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/transform.xsd
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/evolution/passthrough/transform.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:tf="http://www.codesynthesis.com/transform"
+ targetNamespace="http://www.codesynthesis.com/transform"
+ elementFormDefault="qualified">
+
+ <xsd:complexType name="transformation_type" abstract="true">
+ <xsd:sequence>
+ <xsd:element name="description" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:element name="transformation" type="tf:transformation_type"/>
+
+ <!-- Document root. -->
+
+ <xsd:complexType name="transformations_type">
+ <xsd:sequence>
+ <xsd:element ref="tf:transformation" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="transformations" type="tf:transformations_type"/>
+
+ <!-- Special type for unknown transformations. -->
+
+ <xsd:complexType name="unknown_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+
+ <!-- Move. -->
+
+ <xsd:complexType name="move_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="x" type="xsd:float"/>
+ <xsd:element name="y" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="move-transformation"
+ type="tf:move_type"
+ substitutionGroup="tf:transformation"/>
+
+ <!-- Rotate. -->
+
+ <xsd:complexType name="rotate_type">
+ <xsd:complexContent>
+ <xsd:extension base="tf:transformation_type">
+ <xsd:sequence>
+ <xsd:element name="angle" type="xsd:float"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:element name="rotate-transformation"
+ type="tf:rotate_type"
+ substitutionGroup="tf:transformation"/>
+
+
+</xsd:schema>
diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx
new file mode 100644
index 0000000..31da98e
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx
@@ -0,0 +1,142 @@
+// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <memory> // std::auto_ptr
+
+// Include transform-pimpl.hxx (which includes unknown-type-pimpl.hxx)
+// instead of unknown-type-pimpl.hxx.
+//
+#include "transform-pimpl.hxx"
+
+namespace transform
+{
+ void unknown_type_pimpl::
+ _pre ()
+ {
+ unknown_type_base_pimpl::_pre ();
+
+ // Set the element name and namespace.
+ //
+ unknown_type* obj = unknown_type_base_pimpl_state_.unknown_type_;
+
+ obj->element_name (
+ xml::qname (_context ().element_namespace (),
+ _context ().element_name ()));
+
+ // Initialize the current element.
+ //
+ cur_ = &obj->content ();
+ }
+
+ void unknown_type_pimpl::
+ _start_any_element (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const char*)
+ {
+ // Create a new child element and add it to cur_.
+ //
+ std::auto_ptr<xml::element> e (
+ new xml::element (xml::qname (ns, name), cur_));
+
+ cur_->children ().push_back (e.get ());
+ cur_ = e.get ();
+ e.release ();
+ }
+
+ void unknown_type_pimpl::
+ _end_any_element (const xml_schema::ro_string&,
+ const xml_schema::ro_string&)
+ {
+ // Make the parent of cur_ the new cur_.
+ //
+ cur_ = cur_->parent ();
+ }
+
+ void unknown_type_pimpl::
+ _any_attribute (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const xml_schema::ro_string& value)
+ {
+ // Add a new attribute to cur_.
+ //
+ cur_->attributes ()[xml::qname (ns, name)] = value;
+ }
+
+ void unknown_type_pimpl::
+ _any_characters (const xml_schema::ro_string& s)
+ {
+ // Set the character value of cur_.
+ //
+ cur_->value (s);
+ }
+
+ //
+ // Low-level content callbacks.
+ //
+
+ void unknown_type_pimpl::
+ _start_element (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const char* type)
+ {
+ // If this is one of the elements from transformation_type, then
+ // delegate it to our base. Otherwise, forward it to the wildcard
+ // callback.
+ //
+ if (name == "description" &&
+ ns == "http://www.codesynthesis.com/transform")
+ {
+ unknown_type_base_pimpl::_start_element (ns, name, type);
+ }
+ else
+ {
+ _context ().start_wildcard_content ();
+ _start_any_element (ns, name, type);
+ }
+ }
+
+
+ void unknown_type_pimpl::
+ _end_element (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name)
+ {
+ // If this is one of the elements from transformation_type, then
+ // delegate it to our base. Otherwise, forward it to the wildcard
+ // callback.
+ //
+ if (name == "description" &&
+ ns == "http://www.codesynthesis.com/transform")
+ {
+ unknown_type_base_pimpl::_end_element (ns, name);
+ }
+ else
+ _end_any_element (ns, name);
+ }
+
+ void unknown_type_pimpl::
+ _attribute (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const xml_schema::ro_string& value)
+ {
+ // If this is one of the elements from transformation_type, then
+ // delegate it to our base. Otherwise, forward it to the wildcard
+ // callback.
+ //
+ if (name == "name" && ns.empty ())
+ {
+ unknown_type_base_pimpl::_attribute (ns, name, value);
+ }
+ else
+ _any_attribute (ns, name, value);
+ }
+
+ void unknown_type_pimpl::
+ _characters (const xml_schema::ro_string& s)
+ {
+ // transformation_type has no character content so forward this
+ // straight to the wildcard callback.
+ //
+ _any_characters (s);
+ }
+}
diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx
new file mode 100644
index 0000000..1956e2c
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx
@@ -0,0 +1,66 @@
+// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-pimpl.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#ifndef UNKNOWN_TYPE_PIMPL_HXX
+#define UNKNOWN_TYPE_PIMPL_HXX
+
+namespace transform
+{
+ // Customized unknown_type parser implementation.
+ //
+ class unknown_type_pimpl: public unknown_type_base_pimpl
+ {
+ public:
+ virtual void
+ _pre ();
+
+ // Wildcard content callbacks. All the unknown content is routed
+ // to these functions. We use them to construct the raw XML
+ // representation of the unknown transformation.
+ //
+ virtual void
+ _start_any_element (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const char* type);
+
+ virtual void
+ _end_any_element (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name);
+
+ virtual void
+ _any_attribute (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const xml_schema::ro_string& value);
+
+ virtual void
+ _any_characters (const xml_schema::ro_string&);
+
+ // Low-level content callbacks. These are normally implemented by
+ // the generated parsers. However, we need to intercept them and
+ // re-route the known elements and attributes to the base parser
+ // and the unknown content to the wildcard callbacks above.
+ //
+ virtual void
+ _start_element (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const char* type);
+
+ virtual void
+ _end_element (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name);
+
+ virtual void
+ _attribute (const xml_schema::ro_string& ns,
+ const xml_schema::ro_string& name,
+ const xml_schema::ro_string& value);
+
+ virtual void
+ _characters (const xml_schema::ro_string&);
+
+ private:
+ xml::element* cur_;
+ };
+}
+
+#endif // UNKNOWN_TYPE_PIMPL_HXX
diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx
new file mode 100644
index 0000000..142c1ee
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx
@@ -0,0 +1,80 @@
+// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+// Include transform-simpl.hxx (which includes unknown-type-simpl.hxx)
+// instead of unknown-type-simpl.hxx.
+//
+#include "transform-simpl.hxx"
+
+namespace transform
+{
+ void unknown_type_simpl::
+ _serialize_attributes ()
+ {
+ // Allow the base to serialize its attributes.
+ //
+ unknown_type_base_simpl::_serialize_attributes ();
+
+ // Serialize attributes from the unknown content.
+ //
+ const xml::element& e =
+ unknown_type_base_simpl_state_.unknown_type_->content ();
+
+ serialize (e.attributes ());
+ }
+
+ void unknown_type_simpl::
+ _serialize_content ()
+ {
+ // Allow the base to serialize its elements.
+ //
+ unknown_type_base_simpl::_serialize_content ();
+
+ // Serialize elements from the unknown content.
+ //
+ const xml::element& e =
+ unknown_type_base_simpl_state_.unknown_type_->content ();
+
+ serialize (e.children ());
+ }
+
+ void unknown_type_simpl::
+ serialize (const xml::attributes& as)
+ {
+ for (xml::attributes::const_iterator i (as.begin ()); i != as.end (); ++i)
+ {
+ const xml::qname& n = i->first;
+ const std::string& v = i->second;
+
+ if (n.ns ().empty ())
+ _attribute (n.name ().c_str (), v.c_str ());
+ else
+ _attribute (n.ns ().c_str (), n.name ().c_str (), v.c_str ());
+ }
+ }
+
+ void unknown_type_simpl::
+ serialize (const xml::elements& es)
+ {
+ for (xml::elements::const_iterator i (es.begin ()); i != es.end (); ++i)
+ {
+ const xml::element& e = **i;
+ const xml::qname& n = e.name ();
+
+ if (n.ns ().empty ())
+ _start_element (n.name ().c_str ());
+ else
+ _start_element (n.ns ().c_str (), n.name ().c_str ());
+
+ serialize (e.attributes ());
+
+ if (!e.children ().empty ())
+ serialize (e.children ());
+ else if (!e.value ().empty ())
+ _characters (e.value ().c_str ());
+
+ _end_element ();
+ }
+ }
+}
diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx
new file mode 100644
index 0000000..c2cabf7
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx
@@ -0,0 +1,34 @@
+// file : examples/cxx/hybrid/evolution/passthrough/unknown-type-simpl.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#ifndef UNKNOWN_TYPE_SIMPL_HXX
+#define UNKNOWN_TYPE_SIMPL_HXX
+
+namespace transform
+{
+ // Customized unknown_type serializer implementation.
+ //
+ class unknown_type_simpl: public unknown_type_base_simpl
+ {
+ public:
+ // Low-level raw XML serialization callbacks.
+ //
+ virtual void
+ _serialize_attributes ();
+
+ virtual void
+ _serialize_content ();
+
+ // Helper functions.
+ //
+ private:
+ void
+ serialize (const xml::attributes&);
+
+ void
+ serialize (const xml::elements&);
+ };
+}
+
+#endif // UNKNOWN_TYPE_SIMPL_HXX
diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx
new file mode 100644
index 0000000..ba3a9f4
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx
@@ -0,0 +1,17 @@
+// file : examples/cxx/hybrid/evolution/passthrough/unknown-type.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+// Include transform.hxx (which includes unknown-type.hxx) instead of
+// unknown-type.hxx.
+//
+#include "transform.hxx"
+
+namespace transform
+{
+ unknown_type::
+ unknown_type ()
+ : name_ ("unknown"), content_ ("unknown", 0) // Dummy names.
+ {
+ }
+}
diff --git a/examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx b/examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx
new file mode 100644
index 0000000..c3e544c
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx
@@ -0,0 +1,51 @@
+// file : examples/cxx/hybrid/evolution/passthrough/unknown-type.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#ifndef UNKNOWN_TYPE_HXX
+#define UNKNOWN_TYPE_HXX
+
+#include "xml.hxx"
+
+namespace transform
+{
+ // Customized unknown_type. We add members that store the raw XML
+ // representation of an unknown transformation as well as the parsed
+ // element name and namespace from the substitution group.
+ //
+ class unknown_type: public unknown_type_base
+ {
+ public:
+ unknown_type ();
+
+ const xml::qname&
+ element_name () const
+ {
+ return name_;
+ }
+
+ void
+ element_name (const xml::qname& n)
+ {
+ name_ = n;
+ }
+
+ const xml::element&
+ content () const
+ {
+ return content_;
+ }
+
+ xml::element&
+ content ()
+ {
+ return content_;
+ }
+
+ private:
+ xml::qname name_;
+ xml::element content_;
+ };
+}
+
+#endif // UNKNOWN_TYPE_HXX
diff --git a/examples/cxx/hybrid/evolution/passthrough/xml.cxx b/examples/cxx/hybrid/evolution/passthrough/xml.cxx
new file mode 100644
index 0000000..d60ba81
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/xml.cxx
@@ -0,0 +1,19 @@
+// file : examples/cxx/hybrid/evolution/passthrough/xml.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include "xml.hxx"
+
+namespace xml
+{
+ element::
+ ~element ()
+ {
+ for (elements::iterator i = children_.begin ();
+ i != children_.end ();
+ ++i)
+ {
+ delete *i;
+ }
+ }
+}
diff --git a/examples/cxx/hybrid/evolution/passthrough/xml.hxx b/examples/cxx/hybrid/evolution/passthrough/xml.hxx
new file mode 100644
index 0000000..fbcae6e
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/xml.hxx
@@ -0,0 +1,111 @@
+// file : examples/cxx/hybrid/evolution/passthrough/xml.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+//
+// In-memory representation for raw XML. The primary goal here is to provide
+// a simple, if not very efficient, implementation. As a result, it probably
+// shouldn't be used in production, especially if performance is important.
+// It also does not support mixed content (interleaved elements and text).
+//
+
+#ifndef XML_HXX
+#define XML_HXX
+
+#include <map>
+#include <vector>
+#include <string>
+
+namespace xml
+{
+ // Qualified name.
+ //
+ class qname
+ {
+ public:
+ qname (const char* name);
+ qname (const std::string& name);
+ qname (const std::string& ns, const std::string& name);
+
+ const std::string&
+ ns () const;
+
+ const std::string&
+ name () const;
+
+ private:
+ std::string ns_;
+ std::string name_;
+ };
+
+ bool
+ operator== (const qname&, const qname&);
+
+ bool
+ operator!= (const qname&, const qname&);
+
+ bool
+ operator< (const qname&, const qname&);
+
+ // Attribute.
+ //
+ typedef std::map<qname, std::string> attributes;
+
+ // Element.
+ //
+ class element;
+ typedef std::vector<element*> elements;
+
+ class element
+ {
+ public:
+ ~element ();
+ element (const qname& name, element* parent);
+ element (const qname& name, const std::string value, element* parent);
+
+ private:
+ element (const element&);
+ element& operator= (const element&);
+
+ public:
+ const qname&
+ name () const;
+
+ const element*
+ parent () const;
+
+ element*
+ parent ();
+
+ typedef xml::attributes attributes_type;
+
+ const attributes_type&
+ attributes () const;
+
+ attributes_type&
+ attributes ();
+
+ const std::string&
+ value () const;
+
+ void
+ value (const std::string&);
+
+ const elements&
+ children () const;
+
+ elements&
+ children ();
+
+ private:
+ qname name_;
+ element* parent_;
+ attributes_type attributes_;
+ std::string value_;
+ elements children_;
+ };
+}
+
+#include "xml.ixx"
+
+#endif // XML_HXX
diff --git a/examples/cxx/hybrid/evolution/passthrough/xml.ixx b/examples/cxx/hybrid/evolution/passthrough/xml.ixx
new file mode 100644
index 0000000..52fb999
--- /dev/null
+++ b/examples/cxx/hybrid/evolution/passthrough/xml.ixx
@@ -0,0 +1,129 @@
+// file : examples/cxx/hybrid/evolution/passthrough/xml.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+namespace xml
+{
+ //
+ // qname
+ //
+
+ inline qname::
+ qname (const char* name)
+ : name_ (name)
+ {
+ }
+
+ inline qname::
+ qname (const std::string& name)
+ : name_ (name)
+ {
+ }
+
+ inline qname::
+ qname (const std::string& ns, const std::string& name)
+ : ns_ (ns), name_ (name)
+ {
+ }
+
+ inline const std::string& qname::
+ ns () const
+ {
+ return ns_;
+ }
+
+ inline const std::string& qname::
+ name () const
+ {
+ return name_;
+ }
+
+ inline bool
+ operator== (const qname& x, const qname& y)
+ {
+ return x.name () == y.name () && x.ns () == y.ns ();
+ }
+
+ inline bool
+ operator!= (const qname& x, const qname& y)
+ {
+ return !(x == y);
+ }
+
+ inline bool
+ operator< (const qname& x, const qname& y)
+ {
+ int r (x.name ().compare (y.name ()));
+ return (r < 0) || (r == 0 && x.ns () < y.ns ());
+ }
+
+ //
+ // element
+ //
+
+ inline element::
+ element (const qname& name, element* parent)
+ : name_ (name), parent_ (parent)
+ {
+ }
+
+ inline element::
+ element (const qname& name, const std::string value, element* parent)
+ : name_ (name), parent_ (parent), value_ (value)
+ {
+ }
+
+ inline const qname& element::
+ name () const
+ {
+ return name_;
+ }
+
+ inline const element* element::
+ parent () const
+ {
+ return parent_;
+ }
+
+ inline element* element::
+ parent ()
+ {
+ return parent_;
+ }
+
+ inline const element::attributes_type& element::
+ attributes () const
+ {
+ return attributes_;
+ }
+
+ inline element::attributes_type& element::
+ attributes ()
+ {
+ return attributes_;
+ }
+
+ inline const std::string& element::
+ value () const
+ {
+ return value_;
+ }
+
+ inline void element::
+ value (const std::string& value)
+ {
+ value_ = value;
+ }
+
+ inline const elements& element::
+ children () const
+ {
+ return children_;
+ }
+
+ inline elements& element::
+ children ()
+ {
+ return children_;
+ }
+}
diff --git a/examples/cxx/hybrid/makefile b/examples/cxx/hybrid/makefile
index 8bdb2de..f54f56b 100644
--- a/examples/cxx/hybrid/makefile
+++ b/examples/cxx/hybrid/makefile
@@ -10,6 +10,7 @@ allocator \
binary \
compositors \
custom \
+evolution \
hello \
multiroot \
polymorphism \
@@ -20,7 +21,7 @@ wildcard \
filter \
minimal
-build_examples := binary compositors custom
+build_examples := binary compositors custom evolution
ifeq ($(xsde_iostream),y)
ifeq ($(xsde_exceptions),y)