diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2010-10-18 11:17:51 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2010-10-18 11:17:51 +0200 |
commit | d80d096ee8743fd6f7382d274272b0b6d7faf9bf (patch) | |
tree | d0f0bee1e645cb2b86b6837ac0db8a7d2821e533 /examples | |
parent | 0e4637025fa8d1b4234b0512561d31f0dd023843 (diff) |
Support for schema evolution using substitution groups
New examples: hybrid/evolution/ignore and hybrid/evolution/passthrough.
Diffstat (limited to 'examples')
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) |