diff options
Diffstat (limited to 'examples/cxx/hybrid')
57 files changed, 3631 insertions, 0 deletions
diff --git a/examples/cxx/hybrid/README b/examples/cxx/hybrid/README new file mode 100644 index 0000000..ee55a90 --- /dev/null +++ b/examples/cxx/hybrid/README @@ -0,0 +1,37 @@ +This directory contains a number of examples that show how to +use the Embedded C++/Hybrid mapping. The following list gives +an overview of each example. See the README files in example +directories for more information on each example. + +hello + A simple "Hello, world!" example that shows how to parse XML + documents. + +library + Shows how to handle more complex data structures, modify the + object model, and serialize the modified object model back to + XML. + +minimal + Shows how to perform parsing and serialization as well as use the + object model when the mapping is configured without support for + STL, iostream, or C++ exceptions. + +multiroot + Shows how to parse XML vocabularies with multiple root elements. + +wildcard + Shows how to parse, store in the object model, and serialize XML + data matched by XML Schema wildcards (any and anyAttribute). + +filter + Shows how to filter the XML data during parsing and object model + during serialization. + +streaming + Shows how to perform partially event-driven, partially in-memory + XML processing. + +compositors + Shows how to create, access, and modify object models with complex + nested choice and sequence compositors. diff --git a/examples/cxx/hybrid/compositors/README b/examples/cxx/hybrid/compositors/README new file mode 100644 index 0000000..b02a023 --- /dev/null +++ b/examples/cxx/hybrid/compositors/README @@ -0,0 +1,28 @@ +This example shows how to create, access, and modify object models with +complex nested choice and sequence compositors in the Embedded C++/Hybrid +mapping. + +For more information about nested compositors see Section 4.4, "Compositors" +in the Embedded C++/Hybrid Mapping Getting Started Guide. + + +The example consists of the following files: + +compositors.xsd + XML Schema which defines a number of types with nested compositors. + +compositors.hxx +compositors.cxx + + Object model classes. These are generated by the XSD/e compiler from + compositors.xsd. + +driver.cxx + Driver for the example. It shows how to create, access, and modify object + models that use nested choice and sequence compositors. The driver does + not produce any output. + + +To run the example simply execute: + +$ ./driver diff --git a/examples/cxx/hybrid/compositors/compositors.xsd b/examples/cxx/hybrid/compositors/compositors.xsd new file mode 100644 index 0000000..85f0db7 --- /dev/null +++ b/examples/cxx/hybrid/compositors/compositors.xsd @@ -0,0 +1,44 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/compositors/compositors.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:complexType name="simple_choice"> + <xsd:choice> + <xsd:element name="a" type="xsd:int"/> + <xsd:element name="b" type="xsd:string" minOccurs="0"/> + <xsd:element name="c" type="xsd:boolean" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:complexType> + + <xsd:complexType name="nested_choice"> + <xsd:sequence> + <xsd:choice minOccurs="0"> + <xsd:element name="a" type="xsd:int"/> + <xsd:sequence> + <xsd:element name="b" type="xsd:int"/> + <xsd:element name="c" type="xsd:boolean"/> + </xsd:sequence> + </xsd:choice> + <xsd:element name="d" type="xsd:int"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="nested_sequence"> + <xsd:sequence maxOccurs="unbounded"> + <xsd:element name="a" type="xsd:int"/> + <xsd:sequence minOccurs="0"> + <xsd:element name="b" type="xsd:int"/> + <xsd:element name="c" type="xsd:boolean"/> + </xsd:sequence> + </xsd:sequence> + </xsd:complexType> + +</xsd:schema> diff --git a/examples/cxx/hybrid/compositors/driver.cxx b/examples/cxx/hybrid/compositors/driver.cxx new file mode 100644 index 0000000..5d7dd01 --- /dev/null +++ b/examples/cxx/hybrid/compositors/driver.cxx @@ -0,0 +1,89 @@ +// file : examples/cxx/hybrid/compositors/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "compositors.hxx" + +int +main (int, char*[]) +{ + // Simple choice. + // + simple_choice sc; + + sc.a (123); // Automatically sets arm to a_tag. + + switch (sc.choice_arm ()) + { + case simple_choice::a_tag: + { + sc.a ()++; + break; + } + case simple_choice::b_tag: + { + // The b element is optional so we first need to check + // if it is present. + // + if (sc.b_present ()) + { + sc.b_present (false); + } + + break; + } + case simple_choice::c_tag: + { + // The c element is a sequence. + // + simple_choice::c_sequence& s = sc.c (); + + for (simple_choice::c_iterator i = s.begin (); i != s.end(); ++i) + { + *i = !*i; + } + + break; + } + } + + + // Nested choice. + // + nested_choice nc; + + // Initialize the choice with the 'sequence' arm. + // + nc.choice_present (true); + nested_choice::choice_type& c = nc.choice (); + c.choice_arm (nested_choice::choice_type::sequence_tag); + c.sequence ().b (123); + c.sequence ().c (true); + + nc.d (456); + + + // Nested sequence. + // + nested_sequence ns; + nested_sequence::sequence_sequence& s = ns.sequence (); + + for (int i = 0; i < 10; ++i) + { + nested_sequence::sequence_type x; + x.a (i); + + if (i % 2) + { + // Initialize the nested sequence. + // + x.sequence1_present (true); + x.sequence1 ().b (i); + x.sequence1 ().c (true); + } + + s.push_back (x); + } + + return 0; +} diff --git a/examples/cxx/hybrid/compositors/makefile b/examples/cxx/hybrid/compositors/makefile new file mode 100644 index 0000000..2bab6e1 --- /dev/null +++ b/examples/cxx/hybrid/compositors/makefile @@ -0,0 +1,62 @@ +# file : examples/cxx/hybrid/compositors/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := compositors.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-inline + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/filter/README b/examples/cxx/hybrid/filter/README new file mode 100644 index 0000000..6ff8f76 --- /dev/null +++ b/examples/cxx/hybrid/filter/README @@ -0,0 +1,71 @@ +This example shows how to filter the XML data during parsing and object +model during serialization in the Embedded C++/Hybrid mapping. Filtering +allows only parts of the XML document to be parsed into the object model +or only parts of the object model to be serialized to XML. + +This example uses the parser and serializer customization mechanisms +provided by the C++/Hybrid mapping. For more information, see Section +4.8, "Customizing the Object Model" and Section 6.1, "Customizing +Parsers and Serializers" in the Embedded C++/Hybrid Mapping Getting +Started Guide. + +The example consists of the following files: + +people.xsd + XML Schema which describes a collection of person records. + +people.xml + Sample XML instance document. + +people.hxx +people.cxx + +people-pskel.hxx +people-pskel.cxx +people-pimpl.hxx +people-pimpl.cxx + +people-pskel.hxx +people-pskel.cxx +people-pimpl.hxx +people-pimpl.cxx + Object model (the first pair of files), parser skeletons (the second + pair), parser implementations (the third pair), serializer skeletons + (the fourth pair), and serializer implementations (the fifth pair). + These files are generated by the XSD/e compiler from people.xsd. The + --generate-parser, --generate-serializer, and --generate-aggregate + options were used to request the generation of the parsing and + serialization code. The --custom-parser option was used to customize + the people_pimpl parser implementation. The --custom-serializer + option was used to customize the people_simpl serializer + implementation. + +people-custom-pimpl.hxx +people-custom-pimpl.cxx + Custom people parser implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the person() + callback to filter the records being parsed. + +people-custom-simpl.hxx +people-custom-simpl.cxx + Custom people serializer implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the + person_next() callbacks to filter the records being serialized. + +driver.cxx + Driver for the example. It first sets the filter parameters on the + parser object and then calls it to construct the object model from + the input XML file. Only records matching the parser filter end up + in the object model. The driver then prints the content of the object + model to STDERR. Finally, the driver sets the filter parameters on + the serializer object and calls it to serialize the object model back + to XML. Only records matching the serializer filter end up in the + resulting XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver people.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <people.xml diff --git a/examples/cxx/hybrid/filter/driver.cxx b/examples/cxx/hybrid/filter/driver.cxx new file mode 100644 index 0000000..9bc9f64 --- /dev/null +++ b/examples/cxx/hybrid/filter/driver.cxx @@ -0,0 +1,98 @@ +// file : examples/cxx/hybrid/filter/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <iostream> + +#include "people.hxx" + +#include "people-pimpl.hxx" +#include "people-simpl.hxx" + +using namespace std; + +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 + { + // Parse. + // + people_paggr people_p; + people_pimpl& root_p = people_p.root_parser (); + + // Initialize the filter. + // + root_p.age_filter (1, 30); + + xml_schema::document_pimpl doc_p (root_p, people_p.root_name ()); + + people_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr<people> ppl (people_p.post ()); + + // Print what we've got. + // + people::person_sequence& ps = ppl->person (); + + for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) + { + cerr << "first: " << i->first_name () << endl + << "last: " << i->last_name () << endl + << "gender: " << i->gender () << endl + << "age: " << i->age () << endl + << endl; + } + + // Serialize. + // + people_saggr people_s; + people_simpl& root_s = people_s.root_serializer (); + + // Initialize the filter. + // + gender g; + g.assign ("female"); + root_s.gender_filter (g); + + xml_schema::document_simpl doc_s (root_s, people_s.root_name ()); + + people_s.pre (*ppl); + doc_s.serialize (cout); + people_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/filter/makefile b/examples/cxx/hybrid/filter/makefile new file mode 100644 index 0000000..4273a59 --- /dev/null +++ b/examples/cxx/hybrid/filter/makefile @@ -0,0 +1,80 @@ +# file : examples/cxx/hybrid/filter/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := people.xsd +cxx := driver.cxx people-custom-pimpl.cxx people-custom-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 +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) \ + $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) \ + $(out_base)/$(xsd:.xsd=-sskel.hxx) \ + $(out_base)/$(xsd:.xsd=-sskel.cxx) \ + $(out_base)/$(xsd:.xsd=-simpl.hxx) \ + $(out_base)/$(xsd:.xsd=-simpl.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate \ +--custom-parser people=people_base_pimpl/people-custom-pimpl.hxx \ +--custom-serializer people=people_base_simpl/people-custom-simpl.hxx + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/filter/people-custom-pimpl.cxx b/examples/cxx/hybrid/filter/people-custom-pimpl.cxx new file mode 100644 index 0000000..e8a096f --- /dev/null +++ b/examples/cxx/hybrid/filter/people-custom-pimpl.cxx @@ -0,0 +1,26 @@ +// file : examples/cxx/hybrid/filter/people-custom-pimpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +// Include people-pimpl.hxx (which includes people-custom-pimpl.hxx) +// instead of people-custom-pimpl.hxx. +// +#include "people-pimpl.hxx" + +void people_pimpl:: +age_filter (unsigned short min, unsigned short max) +{ + min_age_ = min; + max_age_ = max; +} + +void people_pimpl:: +person (const ::person& p) +{ + // Check if the age constraints are met. + // + unsigned short age = p.age (); + + if (age >= min_age_ && age <= max_age_) + people_base_pimpl::person (p); +} diff --git a/examples/cxx/hybrid/filter/people-custom-pimpl.hxx b/examples/cxx/hybrid/filter/people-custom-pimpl.hxx new file mode 100644 index 0000000..1856811 --- /dev/null +++ b/examples/cxx/hybrid/filter/people-custom-pimpl.hxx @@ -0,0 +1,24 @@ +// file : examples/cxx/hybrid/filter/people-custom-pimpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PEOPLE_CUSTOM_PIMPL_HXX +#define PEOPLE_CUSTOM_PIMPL_HXX + +// Customized people parser implementation. +// +class people_pimpl: public people_base_pimpl +{ +public: + void + age_filter (unsigned short min, unsigned short max); + + virtual void + person (const ::person&); + +private: + unsigned short min_age_; + unsigned short max_age_; +}; + +#endif // PEOPLE_CUSTOM_PIMPL_HXX diff --git a/examples/cxx/hybrid/filter/people-custom-simpl.cxx b/examples/cxx/hybrid/filter/people-custom-simpl.cxx new file mode 100644 index 0000000..3e7d9ff --- /dev/null +++ b/examples/cxx/hybrid/filter/people-custom-simpl.cxx @@ -0,0 +1,32 @@ +// file : examples/cxx/hybrid/filter/people-custom-simpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +// Include people-simpl.hxx (which includes people-custom-simpl.hxx) +// instead of people-custom-simpl.hxx. +// +#include "people-simpl.hxx" + +void people_simpl:: +gender_filter (gender g) +{ + gender_ = g; +} + +bool people_simpl:: +person_next () +{ + // See if we have any more person records with the gender we + // are interested in. + // + people::person_const_iterator& i = people_base_simpl_state_.person_; + people::person_const_iterator& e = people_base_simpl_state_.person_end_; + + for (; i != e; ++i) + { + if (i->gender () == gender_) + break; + } + + return i != e; +} diff --git a/examples/cxx/hybrid/filter/people-custom-simpl.hxx b/examples/cxx/hybrid/filter/people-custom-simpl.hxx new file mode 100644 index 0000000..c3df238 --- /dev/null +++ b/examples/cxx/hybrid/filter/people-custom-simpl.hxx @@ -0,0 +1,23 @@ +// file : examples/cxx/hybrid/filter/people-custom-simpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PEOPLE_CUSTOM_SIMPL_HXX +#define PEOPLE_CUSTOM_SIMPL_HXX + +// Customized people serializer implementation. +// +class people_simpl: public people_base_simpl +{ +public: + void + gender_filter (gender); + + virtual bool + person_next (); + +private: + gender gender_; +}; + +#endif // PEOPLE_CUSTOM_SIMPL_HXX diff --git a/examples/cxx/hybrid/filter/people.xml b/examples/cxx/hybrid/filter/people.xml new file mode 100644 index 0000000..2a3fd11 --- /dev/null +++ b/examples/cxx/hybrid/filter/people.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/filter/people.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <person> + <first-name>John</first-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>32</age> + </person> + + <person> + <first-name>Jane</first-name> + <last-name>Doe</last-name> + <gender>female</gender> + <age>28</age> + </person> + + <person> + <first-name>Joe</first-name> + <last-name>Dirt</last-name> + <gender>male</gender> + <age>25</age> + </person> + +</people> diff --git a/examples/cxx/hybrid/filter/people.xsd b/examples/cxx/hybrid/filter/people.xsd new file mode 100644 index 0000000..bb6e5dd --- /dev/null +++ b/examples/cxx/hybrid/filter/people.xsd @@ -0,0 +1,37 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/filter/people.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:simpleType name="gender"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="male"/> + <xsd:enumeration value="female"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:complexType name="person"> + <xsd:sequence> + <xsd:element name="first-name" type="xsd:string"/> + <xsd:element name="last-name" type="xsd:string"/> + <xsd:element name="gender" type="gender"/> + <xsd:element name="age" type="xsd:unsignedShort"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="people"> + <xsd:sequence> + <xsd:element name="person" type="person" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="people" type="people"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/hello/README b/examples/cxx/hybrid/hello/README new file mode 100644 index 0000000..dd5a2bb --- /dev/null +++ b/examples/cxx/hybrid/hello/README @@ -0,0 +1,37 @@ +This is a "Hello, world!" example that shows how to use the Embedded +C++/Hybrid mapping to parse XML documents. + +The example consists of the following files: + +hello.xsd + XML Schema which describes "hello" instance documents. + +hello.xml + Sample XML instance document. + +hello.hxx +hello.cxx + +hello-pskel.hxx +hello-pskel.cxx +hello-pimpl.hxx +hello-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 hello.xsd. The + --generate-parser and --generate-aggregate options were used + to request the generation of the parsing code. + +driver.cxx + Driver for the example. It first calls the parser that + constructs the object model from the input XML file. It + then prints the content of the object model to STDERR. + +To run the example on the sample XML instance document simply +execute: + +$ ./driver hello.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <hello.xml diff --git a/examples/cxx/hybrid/hello/driver.cxx b/examples/cxx/hybrid/hello/driver.cxx new file mode 100644 index 0000000..ac99149 --- /dev/null +++ b/examples/cxx/hybrid/hello/driver.cxx @@ -0,0 +1,66 @@ +// file : examples/cxx/hybrid/hello/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "hello.hxx" +#include "hello-pimpl.hxx" + +using namespace std; + +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 + { + // Parse. + // + hello_paggr hello_p; + + xml_schema::document_pimpl doc_p (hello_p.root_parser (), + hello_p.root_name ()); + hello_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + hello* h = hello_p.post (); + + // Print what we've got. + // + for (hello::name_const_iterator i = h->name ().begin (); + i != h->name ().end (); + ++i) + { + cout << h->greeting () << ", " << *i << "!" << endl; + } + + delete h; + } + catch (const xml_schema::parser_exception& e) + { + cerr << input << ":" << e.line () << ":" << e.column () << ": " + << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << input << ": unable to open or read failure" << endl; + return 1; + } + + return 0; +} diff --git a/examples/cxx/hybrid/hello/hello.xml b/examples/cxx/hybrid/hello/hello.xml new file mode 100644 index 0000000..32e70f1 --- /dev/null +++ b/examples/cxx/hybrid/hello/hello.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/hello/hello.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="hello.xsd"> + + <greeting>Hello</greeting> + + <name>sun</name> + <name>moon</name> + <name>world</name> + +</hello> diff --git a/examples/cxx/hybrid/hello/hello.xsd b/examples/cxx/hybrid/hello/hello.xsd new file mode 100644 index 0000000..66ea021 --- /dev/null +++ b/examples/cxx/hybrid/hello/hello.xsd @@ -0,0 +1,22 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/hello/hello.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:complexType name="hello"> + <xsd:sequence> + <xsd:element name="greeting" type="xsd:string"/> + <xsd:element name="name" type="xsd:string" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="hello" type="hello"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/hello/makefile b/examples/cxx/hybrid/hello/makefile new file mode 100644 index 0000000..b347837 --- /dev/null +++ b/examples/cxx/hybrid/hello/makefile @@ -0,0 +1,71 @@ +# file : examples/cxx/hybrid/hello/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := hello.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 +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) \ + $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-aggregate + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/library/README b/examples/cxx/hybrid/library/README new file mode 100644 index 0000000..b44c462 --- /dev/null +++ b/examples/cxx/hybrid/library/README @@ -0,0 +1,45 @@ +This example shows how to use the Embedded C++/Hybrid mapping to parse +XML documents into an in-memory object model, modify this object model, +and serialize it back to XML. + +The example consists of the following files: + +library.xsd + XML Schema which describes a library of books. + +library.xml + Sample XML instance document. + +library.hxx +library.cxx + +library-pskel.hxx +library-pskel.cxx +library-pimpl.hxx +library-pimpl.cxx + +library-pskel.hxx +library-pskel.cxx +library-pimpl.hxx +library-pimpl.cxx + Object model (the first pair of files), parser skeletons (the + second pair), parser implementations (the third pair), serializer + skeletons (the fourth pair), and serializer implementations (the + fifth pair). These files are generated by the XSD/e compiler from + library.xsd. The --generate-parser, --generate-serializer, and + --generate-aggregate options were used to request the generation + of the parsing and serialization code. + +driver.cxx + Driver for the example. It first calls the parser that constructs + the object model from the input XML file. It then prints the content + of the object model to STDERR. Finally, the driver modifies the + object model and calls the serializer to serialize it back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver library.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <library.xml diff --git a/examples/cxx/hybrid/library/driver.cxx b/examples/cxx/hybrid/library/driver.cxx new file mode 100644 index 0000000..2bde50d --- /dev/null +++ b/examples/cxx/hybrid/library/driver.cxx @@ -0,0 +1,159 @@ +// file : examples/cxx/hybrid/library/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <iostream> + +#include "library.hxx" + +#include "library-pimpl.hxx" +#include "library-simpl.hxx" + +using namespace std; + +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 + { + using namespace library; + + // Parse. + // + catalog_paggr catalog_p; + + xml_schema::document_pimpl doc_p ( + catalog_p.root_parser (), + catalog_p.root_namespace (), + catalog_p.root_name ()); + + catalog_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr<catalog> c (catalog_p.post ()); + + // Print what we've got. + // + catalog::book_sequence& books (c->book ()); + + for (catalog::book_const_iterator i = books.begin (); + i != books.end (); + ++i) + { + cerr << "ISBN : " << i->isbn () << endl + << "Title : " << i->title () << endl + << "Genre : " << i->genre () << endl; + + for (book::author_const_iterator j = i->author ().begin (); + j != i->author ().end (); + ++j) + { + cerr << "Author : " << j->name () << endl; + + xml_schema::date born (j->born ()); + + cerr << " Born : " + << born.year () << '-' + << born.month () << '-' + << born.day () << endl; + + if (j->died_present ()) + { + xml_schema::date died (j->died ()); + + cerr << " Died : " + << died.year () << '-' + << died.month () << '-' + << died.day () << endl; + } + } + + cerr << "Available : " << i->available () << endl; + } + + // Remove all unavailable books. + // + for (catalog::book_iterator j = books.begin (); j != books.end ();) + { + if (!j->available ()) + j = books.erase (j); + else + ++j; + } + + // Insert a new book. + // + { + auto_ptr<book> b (new book); + b->available (true); + + isbn n; + n.base_value (679776443); + b->isbn (n); + + title t; + t.assign ("Dead Souls"); + b->title (t); + + genre g; + g.assign ("philosophy"); + b->genre (g); + + author a; + a.name ("Nikolai Gogol"); + a.born (xml_schema::date (1809, 3, 31)); + b->author ().push_back (a); + + books.insert (books.begin (), b.release ()); + } + + // Serialize. + // + catalog_saggr catalog_s; + + xml_schema::document_simpl doc_s ( + catalog_s.root_serializer (), + catalog_s.root_namespace (), + catalog_s.root_name ()); + + doc_s.add_prefix ("lib", "http://www.codesynthesis.com/library"); + doc_s.add_schema ("http://www.codesynthesis.com/library", "library.xsd"); + + catalog_s.pre (*c); + doc_s.serialize (cout); + catalog_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/library/library.xml b/examples/cxx/hybrid/library/library.xml new file mode 100644 index 0000000..6c75d3c --- /dev/null +++ b/examples/cxx/hybrid/library/library.xml @@ -0,0 +1,53 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/library/library.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<lib:catalog xmlns:lib="http://www.codesynthesis.com/library" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.codesynthesis.com/library library.xsd"> + + <book available="false"> + <isbn>0679760806</isbn> + <title>The Master and Margarita</title> + <genre>fiction</genre> + + <author> + <name>Mikhail Bulgakov</name> + <born>1891-05-15</born> + <died>1940-03-10</died> + </author> + </book> + + + <book available="true" > + <isbn>0679600841</isbn> + <title>War and Peace</title> + <genre>history</genre> + + <author> + <name>Leo Tolstoy</name> + <born>1828-09-09</born> + <died>1910-11-20</died> + </author> + </book> + + + <book available="false"> + <isbn>0679420290</isbn> + <title>Crime and Punishment</title> + <genre>philosophy</genre> + + <author> + <name>Fyodor Dostoevsky</name> + <born>1821-11-11</born> + <died>1881-02-09</died> + </author> + </book> + +</lib:catalog> diff --git a/examples/cxx/hybrid/library/library.xsd b/examples/cxx/hybrid/library/library.xsd new file mode 100644 index 0000000..d276894 --- /dev/null +++ b/examples/cxx/hybrid/library/library.xsd @@ -0,0 +1,69 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/library/library.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:lib="http://www.codesynthesis.com/library" + targetNamespace="http://www.codesynthesis.com/library"> + + <xsd:simpleType name="isbn"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + + + <xsd:complexType name="title"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="lang" type="xsd:string"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + + <xsd:simpleType name="genre"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="romance"/> + <xsd:enumeration value="fiction"/> + <xsd:enumeration value="horror"/> + <xsd:enumeration value="history"/> + <xsd:enumeration value="philosophy"/> + </xsd:restriction> + </xsd:simpleType> + + + <xsd:complexType name="author"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + <xsd:element name="born" type="xsd:date"/> + <xsd:element name="died" type="xsd:date" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + + <xsd:complexType name="book"> + <xsd:sequence> + <xsd:element name="isbn" type="lib:isbn"/> + <xsd:element name="title" type="lib:title"/> + <xsd:element name="genre" type="lib:genre"/> + <xsd:element name="author" type="lib:author" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="available" type="xsd:boolean" use="required"/> + </xsd:complexType> + + + <xsd:complexType name="catalog"> + <xsd:sequence> + <xsd:element name="book" type="lib:book" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + + <xsd:element name="catalog" type="lib:catalog"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/library/makefile b/examples/cxx/hybrid/library/makefile new file mode 100644 index 0000000..91f6997 --- /dev/null +++ b/examples/cxx/hybrid/library/makefile @@ -0,0 +1,78 @@ +# file : examples/cxx/hybrid/library/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := library.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) \ + $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) \ + $(out_base)/$(xsd:.xsd=-sskel.hxx) \ + $(out_base)/$(xsd:.xsd=-sskel.cxx) \ + $(out_base)/$(xsd:.xsd=-simpl.hxx) \ + $(out_base)/$(xsd:.xsd=-simpl.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/makefile b/examples/cxx/hybrid/makefile new file mode 100644 index 0000000..d3f0729 --- /dev/null +++ b/examples/cxx/hybrid/makefile @@ -0,0 +1,36 @@ +# file : examples/cxx/hybrid/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make + +examples := compositors + +ifeq ($(xsde_iostream),y) +ifeq ($(xsde_exceptions),y) + +examples += hello multiroot streaming + +ifeq ($(xsde_stl),y) +examples += library wildcard filter +endif + +endif +endif + +ifeq ($(xsde_stl),n) +ifeq ($(xsde_exceptions),n) +examples += minimal +endif +endif + +default := $(out_base)/ +clean := $(out_base)/.clean + +.PHONY: $(default) $(clean) + +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(examples))) +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(examples))) + +$(foreach e,$(examples),$(call import,$(src_base)/$e/makefile)) diff --git a/examples/cxx/hybrid/minimal/README b/examples/cxx/hybrid/minimal/README new file mode 100644 index 0000000..bba2467 --- /dev/null +++ b/examples/cxx/hybrid/minimal/README @@ -0,0 +1,46 @@ +This example shows how to perform parsing and serialization as well as +use the object model when the Embedded C++/Hybrid mapping is configured +without support for STL, iostream, or C++ exceptions. + +The example consists of the following files: + +people.xsd + XML Schema which describes a collection of person records. + +people.xml + Sample XML instance document. + +people.hxx +people.cxx + +people-pskel.hxx +people-pskel.cxx +people-pimpl.hxx +people-pimpl.cxx + +people-pskel.hxx +people-pskel.cxx +people-pimpl.hxx +people-pimpl.cxx + Object model (the first pair of files), parser skeletons (the second + pair), parser implementations (the third pair), serializer skeletons + (the fourth pair), and serializer implementations (the fifth pair). + These files are generated by the XSD/e compiler from people.xsd. The + --generate-parser, --generate-serializer, --generate-aggregate, + --no-stl, --no-iostream, and --no-exceptions options were used to + request the generation of the parsing and serialization code as well + as to disable the use of STL, iostream, and C++ exceptions. + +driver.cxx + Driver for the example. It first calls the parser that constructs the + object model from the input XML file. It then prints the content of + the object model to STDERR. Finally, the driver modifies the object + model and calls the serializer to serialize it back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver people.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <people.xml diff --git a/examples/cxx/hybrid/minimal/driver.cxx b/examples/cxx/hybrid/minimal/driver.cxx new file mode 100644 index 0000000..e876b6f --- /dev/null +++ b/examples/cxx/hybrid/minimal/driver.cxx @@ -0,0 +1,265 @@ +// file : examples/cxx/hybrid/minimal/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <stdio.h> + +#include "people.hxx" + +#include "people-pimpl.hxx" +#include "people-simpl.hxx" + +using namespace std; + +// eVC++ 4.0 does not like using xml_schema::strdupx; +// +inline char* +strdupx (const char* s) +{ + return xml_schema::strdupx (s); +} + +struct writer: xml_schema::writer +{ + virtual bool + write (const char* s, size_t n) + { + return fwrite (s, n, 1, stdout) == 1; + } + + virtual bool + flush () + { + return fflush (stdout) == 0; + } +}; + +int +main (int argc, char* argv[]) +{ + const char* input; + + if (argc < 2) + { + input = "STDIN"; + fprintf (stderr, "XML file not specified, reading from STDIN\n"); + } + else + input = argv[1]; + + // Open the file or use STDIN. + // + FILE* f = argc > 1 ? fopen (argv[1], "rb") : stdin; + + if (f == 0) + { + fprintf (stderr, "%s: unable to open\n", input); + return 1; + } + + // Parse. + // + using xml_schema::parser_error; + + parser_error pe; + bool io_error = false; + people* ppl = 0; + + do + { + people_paggr people_p; + xml_schema::document_pimpl doc_p (people_p.root_parser (), + people_p.root_name ()); + + if (pe = doc_p._error ()) + break; + + people_p.pre (); + + if (pe = people_p._error ()) + break; + + char buf[4096]; + + do + { + size_t s = fread (buf, 1, sizeof (buf), f); + + if (s != sizeof (buf) && ferror (f)) + { + io_error = true; + break; + } + + doc_p.parse (buf, s, feof (f) != 0); + pe = doc_p._error (); + + } while (!pe && !feof (f)); + + if (io_error || pe) + break; + + ppl = people_p.post (); + + pe = people_p._error (); + + } while (false); + + if (argc > 1) + fclose (f); + + // Handle parsing errors. + // + if (io_error) + { + fprintf (stderr, "%s: read failure\n", input); + return 1; + } + + if (pe) + { + switch (pe.type ()) + { + case parser_error::sys: + { + fprintf (stderr, "%s: %s\n", input, pe.sys_text ()); + break; + } + case parser_error::xml: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + input, pe.line (), pe.column (), pe.xml_text ()); + break; + } +#ifdef XSDE_PARSER_VALIDATION + case parser_error::schema: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + input, pe.line (), pe.column (), pe.schema_text ()); + break; + } +#endif + case parser_error::app: + { + fprintf (stderr, "%s:%lu:%lu: application error %d\n", + input, pe.line (), pe.column (), pe.app_code ()); + break; + } + default: + break; + } + + return 1; + } + + // Print what we've got. + // + people::person_sequence& ps = ppl->person (); + + for (people::person_const_iterator i = ps.begin (); i != ps.end (); ++i) + { + printf ("first: %s\n" "last: %s\n" "gender: %s\n" "age: %hu\n\n", + i->first_name (), + i->last_name (), + i->gender ().base_value (), + i->age ()); + } + + // Remove people that are younger than 30. + // + for (people::person_iterator j = ps.begin (); j != ps.end ();) + { + if (j->age () < 30) + j = ps.erase (j); + else + ++j; + } + + // Insert a new person. + // + { + person* p = new person; + p->first_name (strdupx ("Joe")); + p->last_name (strdupx ("Dirt")); + p->age (36); + + gender* g = new gender; + g->base_value (strdupx ("male")); + p->gender (g); + + ps.insert (ps.begin (), p); + } + + // Serialize. + // + using xml_schema::serializer_error; + + serializer_error se; + writer w; + + do + { + people_saggr people_s; + xml_schema::document_simpl doc_s (people_s.root_serializer (), + people_s.root_name ()); + + doc_s.add_no_namespace_schema ("people.xsd"); + + if (se = doc_s._error ()) + break; + + people_s.pre (*ppl); + + if (se = people_s._error ()) + break; + + doc_s.serialize (w); + + if (se = doc_s._error ()) + break; + + people_s.post (); + + se = people_s._error (); + + } while (false); + + delete ppl; + + // Handle serializer errors. + // + if (se) + { + switch (se.type ()) + { + case serializer_error::sys: + { + fprintf (stderr, "error: %s\n", se.sys_text ()); + break; + } + case serializer_error::xml: + { + fprintf (stderr, "error: %s\n", se.xml_text ()); + break; + } +#ifdef XSDE_SERIALIZER_VALIDATION + case serializer_error::schema: + { + fprintf (stderr, "error: %s\n", se.schema_text ()); + break; + } +#endif + case serializer_error::app: + { + fprintf (stderr, "application error: %d\n", se.app_code ()); + break; + } + default: + break; + } + + return 1; + } + + return 0; +} diff --git a/examples/cxx/hybrid/minimal/makefile b/examples/cxx/hybrid/minimal/makefile new file mode 100644 index 0000000..3401af6 --- /dev/null +++ b/examples/cxx/hybrid/minimal/makefile @@ -0,0 +1,78 @@ +# file : examples/cxx/hybrid/minimal/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := people.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) \ + $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) \ + $(out_base)/$(xsd:.xsd=-sskel.hxx) \ + $(out_base)/$(xsd:.xsd=-sskel.cxx) \ + $(out_base)/$(xsd:.xsd=-simpl.hxx) \ + $(out_base)/$(xsd:.xsd=-simpl.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/minimal/people.xml b/examples/cxx/hybrid/minimal/people.xml new file mode 100644 index 0000000..83f71cf --- /dev/null +++ b/examples/cxx/hybrid/minimal/people.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/minimal/people.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="people.xsd"> + + <person> + <first-name>John</first-name> + <last-name>Doe</last-name> + <gender>male</gender> + <age>32</age> + </person> + + <person> + <first-name>Jane</first-name> + <last-name>Doe</last-name> + <gender>female</gender> + <age>28</age> + </person> + +</people> diff --git a/examples/cxx/hybrid/minimal/people.xsd b/examples/cxx/hybrid/minimal/people.xsd new file mode 100644 index 0000000..d5c2995 --- /dev/null +++ b/examples/cxx/hybrid/minimal/people.xsd @@ -0,0 +1,37 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/minimal/people.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:simpleType name="gender"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="male"/> + <xsd:enumeration value="female"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:complexType name="person"> + <xsd:sequence> + <xsd:element name="first-name" type="xsd:string"/> + <xsd:element name="last-name" type="xsd:string"/> + <xsd:element name="gender" type="gender"/> + <xsd:element name="age" type="xsd:unsignedShort"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="people"> + <xsd:sequence> + <xsd:element name="person" type="person" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="people" type="people"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/multiroot/README b/examples/cxx/hybrid/multiroot/README new file mode 100644 index 0000000..3a7cfae --- /dev/null +++ b/examples/cxx/hybrid/multiroot/README @@ -0,0 +1,48 @@ +This example shows how to parse XML vocabularies with multiple root +elements using the Embedded C++/Hybrid mapping. + +The example consists of the following files: + +protocol.xsd + XML Schema which defines a simple bank account protocol with + requests such as withdraw and deposit. + +balance.xml +withdraw.xml +deposit.xml + Sample XML instances for the protocol requests. + +protocol.hxx +protocol.cxx + +protocol-pskel.hxx +protocol-pskel.cxx +protocol-pimpl.hxx +protocol-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 protocol.xsd. The + --generate-parser and --generate-aggregate options were used to + request the generation of the parsing code. + +driver.cxx + Driver for the example. It implements a custom document parser + that determines which request is being parsed and uses the + corresponding parser implementation. The document parser + intentionally does not support the deposit request to show how + to handle unknown documents. The driver first calls the parser + that constructs the object model from the input XML file. It + then prints the content of the object model to STDERR. + +To run the example on the sample XML request documents simply +execute: + +$ ./driver balance.xml +$ ./driver withdraw.xml +$ ./driver deposit.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <balance.xml +$ ./driver <withdraw.xml +$ ./driver <deposit.xml diff --git a/examples/cxx/hybrid/multiroot/balance.xml b/examples/cxx/hybrid/multiroot/balance.xml new file mode 100644 index 0000000..9cffa83 --- /dev/null +++ b/examples/cxx/hybrid/multiroot/balance.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/multiroot/balance.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<p:balance xmlns:p="http://www.codesynthesis.com/protocol" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.codesynthesis.com/protocol protocol.xsd"> + + <account>123456789</account> + +</p:balance> diff --git a/examples/cxx/hybrid/multiroot/deposit.xml b/examples/cxx/hybrid/multiroot/deposit.xml new file mode 100644 index 0000000..6b5ed30 --- /dev/null +++ b/examples/cxx/hybrid/multiroot/deposit.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/multiroot/deposit.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<p:deposit xmlns:p="http://www.codesynthesis.com/protocol" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.codesynthesis.com/protocol protocol.xsd"> + + <account>123456789</account> + <amount>1000000</amount> + +</p:deposit> diff --git a/examples/cxx/hybrid/multiroot/driver.cxx b/examples/cxx/hybrid/multiroot/driver.cxx new file mode 100644 index 0000000..5611222 --- /dev/null +++ b/examples/cxx/hybrid/multiroot/driver.cxx @@ -0,0 +1,224 @@ +// file : examples/cxx/hybrid/multiroot/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "protocol.hxx" +#include "protocol-pimpl.hxx" + +using namespace std; +using xml_schema::ro_string; + +namespace protocol +{ + // We are going to use our own "type ids" for the request types. + // + enum request_type + { + unknown_type, + balance_type, + withdraw_type + }; + + // Customize the xml_schema::document_pimpl object to handle our protocol + // vocabulary with multiple root elements. + // + class document_pimpl: public xml_schema::document_pimpl + { + public: + document_pimpl () + : result_type_ (unknown_type) + { + } + + request_type + result_type () const + { + return result_type_; + } + + protocol::balance + balance () const + { + return balance_; + } + + protocol::withdraw + withdraw () const + { + return withdraw_; + } + + protected: + // This function is called to obtain the root element type parser. + // If the returned pointed is 0 then the whole document content + // is ignored. Note that the signature of this function varies + // depending on whether the runtime was built with polymorphism + // support. + // + virtual xml_schema::parser_base* +#ifndef XSDE_POLYMORPHIC + start_root_element (const ro_string& ns, + const ro_string& name) +#else + start_root_element (const ro_string& ns, + const ro_string& name, + const char* /* xsi:type */) +#endif + { + if (ns == "http://www.codesynthesis.com/protocol") + { + if (name == balance_p_.root_name ()) + { + balance_p_.pre (); + return &balance_p_.root_parser (); + } + else if (name == "withdraw") + { + balance_p_.pre (); + return &withdraw_p_.root_parser (); + } + + // Ignore unknown request. + // + return 0; + } + else + { + // This document is from the wrong namespace. If the runtime and + // the generated code are built with validation enabled then we + // can set an XML Schema error. Otherwise, we ignore it. + // +#ifdef XSDE_PARSER_VALIDATION + context_.schema_error ( + xml_schema::parser_schema_error::unexpected_element); +#endif + return 0; + } + } + + // This function is called to indicate the completion of document + // parsing. The parser argument contains the pointer returned by + // start_root_element. + // + virtual void + end_root_element (const ro_string& /* ns */, + const ro_string& /* name */, + xml_schema::parser_base* parser) + { + // We could have handled the result directly in this function + // instead of storing it in the result variables. + // + if (parser == &balance_p_.root_parser ()) + { + result_type_ = balance_type; + balance_ = balance_p_.post (); + } + else if (parser == &withdraw_p_.root_parser ()) + { + result_type_ = withdraw_type; + withdraw_ = withdraw_p_.post (); + } + else + result_type_ = unknown_type; + } + + + public: + // If we need to be able to reset and reuse the parser after + // an error then we also need to override reset() and reset + // the root parsers. We can also get smarter here by caching + // the parser that was used last and only reset that. Note + // that you always need to call _reset() from the base. + // + virtual void + reset () + { + xml_schema::document_pimpl::reset (); + + balance_p_.reset (); + withdraw_p_.reset (); + } + + private: + // Result. + // + request_type result_type_; + protocol::balance balance_; + protocol::withdraw withdraw_; + + // Parsers for various root elements. + // + balance_paggr balance_p_; + withdraw_paggr withdraw_p_; + }; +} + +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 + { + using namespace protocol; + + // Parse. + // + document_pimpl doc_p; + + // pre() and post() are called as part of the start_root_element() + // and end_root_element() calls. + // + if (argc < 2) + doc_p.parse (std::cin); + else + doc_p.parse (argv[1]); + + // Print what we've got. + // + switch (doc_p.result_type ()) + { + case balance_type: + { + balance b (doc_p.balance ()); + cerr << "balance request for acc# " << b.account () << endl; + break; + } + case withdraw_type: + { + withdraw w (doc_p.withdraw ()); + cerr << "withdrawal request for acc# " << w.account () << ", " + << "amount: " << w.amount () << endl; + break; + } + case unknown_type: + { + cerr << "unknown request" << endl; + break; + } + } + } + catch (const xml_schema::parser_exception& e) + { + cerr << input << ":" << e.line () << ":" << e.column () << ": " + << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << input << ": unable to open or read failure" << endl; + return 1; + } + + return 0; +} diff --git a/examples/cxx/hybrid/multiroot/makefile b/examples/cxx/hybrid/multiroot/makefile new file mode 100644 index 0000000..1426d38 --- /dev/null +++ b/examples/cxx/hybrid/multiroot/makefile @@ -0,0 +1,72 @@ +# file : examples/cxx/hybrid/multiroot/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := protocol.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 +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) \ + $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-aggregate \ +--root-element-all + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/multiroot/protocol.xsd b/examples/cxx/hybrid/multiroot/protocol.xsd new file mode 100644 index 0000000..78a275d --- /dev/null +++ b/examples/cxx/hybrid/multiroot/protocol.xsd @@ -0,0 +1,51 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/multiroot/protocol.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:p="http://www.codesynthesis.com/protocol" + targetNamespace="http://www.codesynthesis.com/protocol"> + + <xsd:complexType name="request"> + <xsd:sequence> + <xsd:element name="account" type="xsd:unsignedInt"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="balance"> + <xsd:complexContent> + <xsd:extension base="p:request"/> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="withdraw"> + <xsd:complexContent> + <xsd:extension base="p:request"> + <xsd:sequence> + <xsd:element name="amount" type="xsd:unsignedInt"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="deposit"> + <xsd:complexContent> + <xsd:extension base="p:request"> + <xsd:sequence> + <xsd:element name="amount" type="xsd:unsignedInt"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="balance" type="p:balance"/> + <xsd:element name="withdraw" type="p:withdraw"/> + <xsd:element name="deposit" type="p:deposit"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/multiroot/withdraw.xml b/examples/cxx/hybrid/multiroot/withdraw.xml new file mode 100644 index 0000000..36c7d6c --- /dev/null +++ b/examples/cxx/hybrid/multiroot/withdraw.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/multiroot/withdraw.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<p:withdraw xmlns:p="http://www.codesynthesis.com/protocol" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.codesynthesis.com/protocol protocol.xsd"> + + <account>123456789</account> + <amount>1000000</amount> + +</p:withdraw> diff --git a/examples/cxx/hybrid/streaming/README b/examples/cxx/hybrid/streaming/README new file mode 100644 index 0000000..216c370 --- /dev/null +++ b/examples/cxx/hybrid/streaming/README @@ -0,0 +1,71 @@ +This example shows how to perform partially event-driven, partially in- +memory processing using the Embedded C++/Hybrid mapping. With partially +event-driven parsing and serialization we can process parts of the +document as they become available as well as handle documents that +are too large to fit into memory. + +This example uses the parser and serializer customization mechanisms +provided by the C++/Hybrid mapping. For more information, see Section +4.8, "Customizing the Object Model" and Section 6.1, "Customizing +Parsers and Serializers" in the Embedded C++/Hybrid Mapping Getting +Started Guide. + +The example consists of the following files: + +position.xsd + XML Schema which describes a simple object position vocabulary. + The position is represented as a potentially large series of + latitude/longitude measurements. + +position.xml + Sample object position document. + +position.hxx +position.cxx + +position-pskel.hxx +position-pskel.cxx +position-pimpl.hxx +position-pimpl.cxx + +position-pskel.hxx +position-pskel.cxx +position-pimpl.hxx +position-pimpl.cxx + Object model (the first pair of files), parser skeletons (the + second pair), parser implementations (the third pair), serializer + skeletons (the fourth pair), and serializer implementations (the + fifth pair). These files are generated by the XSD/e compiler from + position.xsd. The --generate-parser, --generate-serializer, and + --generate-aggregate options were used to request the generation + of the parsing and serialization code. The --custom-parser option + was used to customize the object_pimpl parser implementation. The + --custom-serializer option was used to customize the object_simpl + serializer implementation. + +object-pimpl.hxx +object-pimpl.cxx + Custom object parser implementation. It calculates the average + latitude and longitude values as position measurements become + available. At the end it prints the object position based on + these calculations. + +object-simpl.hxx +object-simpl.cxx + Custom object serializer implementation. It performs a number of + measurements of the object position and serializes them as they + become available. + +driver.cxx + Driver for the example. It first calls the parser that calculates + and prints the object position without constructing the object + model. It then serializes a new set of measurements which are + taken as serialization progresses. + +To run the example on the sample XML instance document simply execute: + +$ ./driver position.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <position.xml diff --git a/examples/cxx/hybrid/streaming/driver.cxx b/examples/cxx/hybrid/streaming/driver.cxx new file mode 100644 index 0000000..ab2cd3a --- /dev/null +++ b/examples/cxx/hybrid/streaming/driver.cxx @@ -0,0 +1,83 @@ +// file : examples/cxx/hybrid/streaming/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "position.hxx" + +#include "position-pimpl.hxx" +#include "position-simpl.hxx" + +using namespace std; + +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 + { + // Parse. + // + object_paggr object_p; + + xml_schema::document_pimpl doc_p ( + object_p.root_parser (), + object_p.root_name ()); + + object_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + object_p.post (); // Ignore the NULL return value. + + // Serialize. + // + object_saggr object_s; + + xml_schema::document_simpl doc_s ( + object_s.root_serializer (), + object_s.root_name ()); + + // Create an object instance. Its only purpose is to carry the + // object id. The position measurements will be supplied directly + // by the custom serializer. + // + object obj; + obj.id (456); + + object_s.pre (obj); + doc_s.serialize (cout); + object_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/streaming/makefile b/examples/cxx/hybrid/streaming/makefile new file mode 100644 index 0000000..9fbedb3 --- /dev/null +++ b/examples/cxx/hybrid/streaming/makefile @@ -0,0 +1,79 @@ +# file : examples/cxx/hybrid/streaming/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := position.xsd +cxx := driver.cxx object-pimpl.cxx object-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 +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) \ + $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) \ + $(out_base)/$(xsd:.xsd=-sskel.hxx) \ + $(out_base)/$(xsd:.xsd=-sskel.cxx) \ + $(out_base)/$(xsd:.xsd=-simpl.hxx) \ + $(out_base)/$(xsd:.xsd=-simpl.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate --custom-parser object=/object-pimpl.hxx \ +--custom-serializer object=/object-simpl.hxx + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/hybrid/streaming/object-pimpl.cxx b/examples/cxx/hybrid/streaming/object-pimpl.cxx new file mode 100644 index 0000000..3f45c79 --- /dev/null +++ b/examples/cxx/hybrid/streaming/object-pimpl.cxx @@ -0,0 +1,47 @@ +// file : examples/cxx/hybrid/streaming/object-pimpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +// Include position-pimpl.hxx (which includes object-pimpl.hxx) +// instead of object-pimpl.hxx. +// +#include "position-pimpl.hxx" + +using namespace std; + +void object_pimpl:: +pre () +{ + // Initialize the variables. + // + count_ = 0; + avg_lat_ = 0.0; + avg_lon_ = 0.0; +} + +void object_pimpl:: +id (unsigned int id) +{ + id_ = id; +} + +void object_pimpl:: +position (const ::position& p) +{ + count_++; + avg_lat_ += p.lat (); + avg_lon_ += p.lon (); +} + +object* object_pimpl:: +post_object () +{ + avg_lat_ /= count_; + avg_lon_ /= count_; + + cerr << "object " << id_ << ": " << avg_lat_ << " " << avg_lon_ << endl; + + return 0; // We don't construct the object so return NULL. +} diff --git a/examples/cxx/hybrid/streaming/object-pimpl.hxx b/examples/cxx/hybrid/streaming/object-pimpl.hxx new file mode 100644 index 0000000..8d59063 --- /dev/null +++ b/examples/cxx/hybrid/streaming/object-pimpl.hxx @@ -0,0 +1,33 @@ +// file : examples/cxx/hybrid/streaming/object-pimpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef OBJECT_PIMPL_HXX +#define OBJECT_PIMPL_HXX + +// Customized object parser implementation. +// +class object_pimpl: public object_pskel +{ +public: + virtual void + pre (); + + virtual void + id (unsigned int); + + virtual void + position (const ::position&); + + virtual object* + post_object (); + +private: + unsigned int id_; + + unsigned int count_; + float avg_lat_; + float avg_lon_; +}; + +#endif // OBJECT_PIMPL_HXX diff --git a/examples/cxx/hybrid/streaming/object-simpl.cxx b/examples/cxx/hybrid/streaming/object-simpl.cxx new file mode 100644 index 0000000..f23e0d4 --- /dev/null +++ b/examples/cxx/hybrid/streaming/object-simpl.cxx @@ -0,0 +1,69 @@ +// file : examples/cxx/hybrid/streaming/object-simpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +// Include position-simpl.hxx (which includes object-simpl.hxx) +// instead of object-simpl.hxx. +// +#include "position-simpl.hxx" + +// Position measurement instrument interface. +// +struct measurements +{ + float lat; + float lon; +}; + +measurements test_measurements [8] = +{ + {-33.8569F, 18.5083F}, + {-33.8568F, 18.5083F}, + {-33.8568F, 18.5082F}, + {-33.8570F, 18.5083F}, + {-33.8569F, 18.5084F}, + {-33.8570F, 18.5084F}, + {-33.8570F, 18.5082F}, + {-33.8569F, 18.5082F} +}; + +static void +measure_position (unsigned int n, float& lat, float& lon) +{ + // Call the instrument to measure the position. + // + lat = test_measurements[n].lat; + lon = test_measurements[n].lon; +} + +// Serializer implementation. +// +void object_simpl:: +pre (const object& obj) +{ + // Cache the object id and determine how many position measuremenets + // we need to take. + // + id_ = obj.id (); + count_ = 8; +} + +unsigned int object_simpl:: +id () +{ + return id_; +} + +bool object_simpl:: +position_next () +{ + return count_ > 0; +} + +const position& object_simpl:: +position () +{ + count_--; + measure_position (count_, cur_pos_.lat (), cur_pos_.lon ()); + return cur_pos_; +} diff --git a/examples/cxx/hybrid/streaming/object-simpl.hxx b/examples/cxx/hybrid/streaming/object-simpl.hxx new file mode 100644 index 0000000..6b20399 --- /dev/null +++ b/examples/cxx/hybrid/streaming/object-simpl.hxx @@ -0,0 +1,32 @@ +// file : examples/cxx/hybrid/streaming/object-simpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef OBJECT_SIMPL_HXX +#define OBJECT_SIMPL_HXX + +// Customized object serializer implementation. +// +class object_simpl: public object_sskel +{ +public: + virtual void + pre (const object&); + + virtual unsigned int + id (); + + virtual bool + position_next (); + + virtual const ::position& + position (); + +private: + unsigned int id_; + + unsigned int count_; + ::position cur_pos_; +}; + +#endif // OBJECT_SIMPL_HXX diff --git a/examples/cxx/hybrid/streaming/position.xml b/examples/cxx/hybrid/streaming/position.xml new file mode 100644 index 0000000..0943bb2 --- /dev/null +++ b/examples/cxx/hybrid/streaming/position.xml @@ -0,0 +1,22 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/streaming/position.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<object id="123"> + + <position lat="-33.8569" lon="18.5083"/> + <position lat="-33.8568" lon="18.5083"/> + <position lat="-33.8568" lon="18.5082"/> + <position lat="-33.8570" lon="18.5083"/> + <position lat="-33.8569" lon="18.5084"/> + <position lat="-33.8570" lon="18.5084"/> + <position lat="-33.8570" lon="18.5082"/> + <position lat="-33.8569" lon="18.5082"/> + +</object> diff --git a/examples/cxx/hybrid/streaming/position.xsd b/examples/cxx/hybrid/streaming/position.xsd new file mode 100644 index 0000000..70b73f2 --- /dev/null +++ b/examples/cxx/hybrid/streaming/position.xsd @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/streaming/position.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + + <xsd:complexType name="position"> + <xsd:attribute name="lat" type="xsd:float" use="required"/> + <xsd:attribute name="lon" type="xsd:float" use="required"/> + </xsd:complexType> + + <xsd:complexType name="object"> + <xsd:sequence> + <xsd:element name="position" type="position" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + + <xsd:element name="object" type="object"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/wildcard/README b/examples/cxx/hybrid/wildcard/README new file mode 100644 index 0000000..d54b081 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/README @@ -0,0 +1,76 @@ +This example shows how to parse, store in the object model, and serialize +XML data matched by XML Schema wildcards (any and anyAttribute) using the +Embedded C++/Hybrid mapping. + +This example uses the object model as well as parser and serializer +customization mechanisms provided by the C++/Hybrid mapping. For more +information, see Section 4.8, "Customizing the Object Model" and Section +6.1, "Customizing Parsers and Serializers" in the Embedded C++/Hybrid +Mapping Getting Started Guide. + +The example consists of the following files: + +email.xsd + XML Schema which describes a simple email format with the + extensible envelope type. + +email.xml + Sample email message. + +email.hxx +email.cxx + +email-pskel.hxx +email-pskel.cxx +email-pimpl.hxx +email-pimpl.cxx + +email-pskel.hxx +email-pskel.cxx +email-pimpl.hxx +email-pimpl.cxx + Object model (the first pair of files), parser skeletons (the + second pair), parser implementations (the third pair), serializer + skeletons (the fourth pair), and serializer implementations (the + fifth pair). These files are generated by the XSD/e compiler from + email.xsd. The --generate-parser, --generate-serializer, and + --generate-aggregate options were used to request the generation of + the parsing and serialization code. The --custom-data option was + used to request addition of custom data to the envelope class in + the object model. The --custom-parser option was used to customize + the envelope_pimpl parser implementation. The --custom-serializer + option was used to customize the envelope_simpl serializer + implementation. + +body.hxx +body.cxx + Implementation of the body class. It is used to store the wildcard + data in the custom data sequence in the envelope class. + +envelope-pimpl.hxx +envelope-pimpl.cxx + Custom envelope parser implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the wildcard + callbacks to parse the wildcard content and store it as custom data + in the envelope object. + +envelope-simpl.hxx +envelope-simpl.cxx + Custom envelope serializer implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the wildcard + callbacks to serialize the wildcard content stored as custom data in + the envelope object. + +driver.cxx + Driver for the example. It first calls the parser that constructs the + email object from the input XML file. It then prints the content of + the email to STDERR. Finally, the driver creates a reply email and + calls the serializer to serialize it to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver email.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <email.xml diff --git a/examples/cxx/hybrid/wildcard/body.cxx b/examples/cxx/hybrid/wildcard/body.cxx new file mode 100644 index 0000000..e6bd164 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/body.cxx @@ -0,0 +1,26 @@ +// file : examples/cxx/hybrid/wildcard/body.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "body.hxx" + +namespace email +{ + void body:: + body_type (body::type t) + { + if (body_type_ == type_binary) + { + delete binary_; + binary_ = 0; + } + + body_type_ = t; + } + + void + destroy_body (void* p, size_t) + { + delete static_cast<body*> (p); + } +} diff --git a/examples/cxx/hybrid/wildcard/body.hxx b/examples/cxx/hybrid/wildcard/body.hxx new file mode 100644 index 0000000..512a107 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/body.hxx @@ -0,0 +1,81 @@ +// file : examples/cxx/hybrid/wildcard/body.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef BODY_HXX +#define BODY_HXX + +#include "email.hxx" + +namespace email +{ + // Custom email body type which can hold text or binary. + // + class body + { + public: + enum type + { + type_none, + type_text, + type_binary + }; + + body () + : body_type_ (type_none), binary_ (0) + { + } + + ~body () + { + body_type (type_none); + } + + type + body_type () const + { + return body_type_; + } + + const std::string& + text () const + { + return text_; + } + + void + text (const std::string& t) + { + body_type (type_text); + text_ = t; + } + + const email::binary& + binary () const + { + return *binary_; + } + + void + binary (email::binary* b) + { + body_type (type_binary); + binary_ = b; + } + + private: + void + body_type (type t); + + type body_type_; + std::string text_; + email::binary* binary_; + }; + + // Custom data destructor for body. + // + void + destroy_body (void*, size_t); +} + +#endif // BODY_HXX diff --git a/examples/cxx/hybrid/wildcard/driver.cxx b/examples/cxx/hybrid/wildcard/driver.cxx new file mode 100644 index 0000000..eea5bc7 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/driver.cxx @@ -0,0 +1,188 @@ +// file : examples/cxx/hybrid/wildcard/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <string> // memcpy +#include <memory> // std::auto_ptr +#include <iostream> + +#include "email.hxx" +#include "body.hxx" + +#include "email-pimpl.hxx" +#include "email-simpl.hxx" + +using namespace std; + +// Extended parser and serializer aggregates for the message +// element. They add parser/serializer aggregates for the +// wildcard elements. +// +namespace email +{ + class message_paggr_ex: public message_paggr + { + public: + message_paggr_ex () + { + envelope_p_.text_parser (text_p_.root_parser ()); + envelope_p_.binary_parser (binary_p_.root_parser ()); + } + + public: + text_paggr text_p_; + binary_paggr binary_p_; + }; + + class message_saggr_ex: public message_saggr + { + public: + message_saggr_ex () + { + envelope_s_.text_serializer (text_s_.root_serializer ()); + envelope_s_.binary_serializer (binary_s_.root_serializer ()); + } + + public: + text_saggr text_s_; + binary_saggr binary_s_; + }; +} + +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 + { + using namespace email; + + // Parse. + // + message_paggr_ex message_p; + + xml_schema::document_pimpl doc_p ( + message_p.root_parser (), + message_p.root_namespace (), + message_p.root_name ()); + + message_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr<envelope> msg (message_p.post ()); + + // Print what we've got. + // + cerr << "To: " << msg->to () << endl + << "From: " << msg->from () << endl + << "Subject: " << msg->subject () << endl; + + envelope::custom_data_sequence& body_seq (msg->custom_data ()); + + for (envelope::custom_data_iterator i = body_seq.begin (); + i != body_seq.end (); + ++i) + { + body* b = static_cast<body*> (*i); + + switch (b->body_type ()) + { + case body::type_text: + { + cerr << b->text () << endl + << endl; + break; + } + case body::type_binary: + { + const binary& bin = b->binary (); + cerr << "binary: " << bin.name () << " " + << "type: " << bin.mime () << endl + << endl; + break; + } + default: + { + cerr << "unexpected body type" << endl; + break; + } + } + } + + // Create a reply message. + // + auto_ptr<envelope> reply (new envelope); + reply->custom_data ().destructor (&destroy_body); + + reply->to (msg->from ()); + reply->from (msg->to ()); + reply->subject ("Re: " + msg->subject ()); + + // Add a text body. + // + auto_ptr<body> b (new body); + b->text ("Hi!\n\n" + "Indeed nice pictures. Check out mine.\n\n" + "Jane"); + reply->custom_data ().push_back (b.release ()); + + // Add a (fake) image. + // + auto_ptr<binary> pic (new binary); + pic->name ("pic.jpg"); + pic->mime ("image/jpeg"); + pic->size (3); + memcpy (pic->data (), "123", 3); + + b = auto_ptr<body> (new body); + b->binary (pic.release ()); + reply->custom_data ().push_back (b.release ()); + + // Serialize. + // + message_saggr_ex message_s; + + xml_schema::document_simpl doc_s ( + message_s.root_serializer (), + message_s.root_namespace (), + message_s.root_name ()); + + doc_s.add_prefix ("lib", "http://www.codesynthesis.com/email"); + doc_s.add_schema ("http://www.codesynthesis.com/email", "email.xsd"); + + message_s.pre (*reply); + doc_s.serialize (cout); + message_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/wildcard/email.xml b/examples/cxx/hybrid/wildcard/email.xml new file mode 100644 index 0000000..75592f4 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/email.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/wildcard/email.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<eml:message xmlns:eml="http://www.codesynthesis.com/email" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.codesynthesis.com/email email.xsd"> + + <to>Jane Doe <jane@doe.com></to> + <from>John Doe <john@doe.com></from> + <subject>Surfing pictures</subject> + + <eml:text> +Hi Jane, + +Here are cool pictures of me surfing. + +Cheers, +John + </eml:text> + + <eml:binary name="pic1.jpg" mime="image/jpeg">YmFzZTY0IGJpbmFyeQ==</eml:binary> + <eml:binary name="pic2.jpg" mime="image/jpeg">YmFzZTY0IGJpbmFyeQ==</eml:binary> + +</eml:message> diff --git a/examples/cxx/hybrid/wildcard/email.xsd b/examples/cxx/hybrid/wildcard/email.xsd new file mode 100644 index 0000000..ca20df3 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/email.xsd @@ -0,0 +1,45 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/wildcard/email.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:eml="http://www.codesynthesis.com/email" + targetNamespace="http://www.codesynthesis.com/email"> + + <!-- Predefined envolop body types. --> + + <xsd:element name="text" type="xsd:string"/> + + <xsd:complexType name="binary"> + <xsd:simpleContent> + <xsd:extension base="xsd:base64Binary"> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="mime" type="xsd:string" use="required"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:element name="binary" type="eml:binary"/> + + <xsd:complexType name="envelope"> + <xsd:sequence> + <xsd:element name="to" type="xsd:string"/> + <xsd:element name="from" type="xsd:string"/> + <xsd:element name="subject" type="xsd:string"/> + + <!-- Extensible envelope body. --> + + <xsd:any namespace="##targetNamespace" processContents="strict" + maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="message" type="eml:envelope"/> + +</xsd:schema> diff --git a/examples/cxx/hybrid/wildcard/envelope-pimpl.cxx b/examples/cxx/hybrid/wildcard/envelope-pimpl.cxx new file mode 100644 index 0000000..16bd2e5 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/envelope-pimpl.cxx @@ -0,0 +1,111 @@ +// file : examples/cxx/hybrid/wildcard/envelope-pimpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr + +#include "body.hxx" + +// Include email-pimpl.hxx (which includes envelope-pimpl.hxx) +// instead of envelope-pimpl.hxx. +// +#include "email-pimpl.hxx" + +namespace email +{ + void envelope_pimpl:: + _pre () + { + // Set the custom data destructor. + // + envelope_base_pimpl_state_.envelope_->custom_data ().destructor ( + &destroy_body); + + envelope_base_pimpl::_pre (); + } + + void envelope_pimpl:: +#ifndef XSDE_POLYMORPHIC + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name) +#else + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char*) +#endif + { + // We use the depth_ counter to filter out nested elements + // and attributes for the content matched by the wildcard + // but which we don't know how to handle. + // + if (depth_++ == 0) + { + // Top-level (relative to this type) element matched by the + // any wildcard. + // + xml_schema::parser_base* p = 0; + + if (ns == "http://www.codesynthesis.com/email") + { + if (name == "text") + p = text_p_; + else if (name == "binary") + p = binary_p_; + + if (p != 0) + { + // If you are not using exceptions then you will need to add + // error propagation code. For more information on how to do + // this see the wildcard example for the C++/Parser mapping + // (examples/parser/ directory). + // + xml_schema::parser_context& ctx = _context (); + p->pre (); + p->_pre_impl (ctx); + } + } + } + } + + void envelope_pimpl:: + _end_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name) + { + if (--depth_ == 0) + { + if (ns == "http://www.codesynthesis.com/email") + { + // Note that we don't call _post_impl() (corresponding to + // _pre_impl()) here. It is called automatically by the + // infrastructure. + // + envelope* env = envelope_base_pimpl_state_.envelope_; + + if (name == "text") + { + std::auto_ptr<body> b (new body); + b->text (text_p_->post_string ()); + env->custom_data ().push_back (b.release ()); + } + else if (name == "binary") + { + std::auto_ptr<body> b (new body); + b->binary (binary_p_->post_binary ()); + env->custom_data ().push_back (b.release ()); + } + } + } + } + + void envelope_pimpl:: + _reset () + { + // Note that we always need to call _reset() from the base. + // + envelope_base_pimpl::_reset (); + + depth_ = 0; + text_p_->_reset (); + binary_p_->_reset (); + } +} diff --git a/examples/cxx/hybrid/wildcard/envelope-pimpl.hxx b/examples/cxx/hybrid/wildcard/envelope-pimpl.hxx new file mode 100644 index 0000000..06eb26c --- /dev/null +++ b/examples/cxx/hybrid/wildcard/envelope-pimpl.hxx @@ -0,0 +1,81 @@ +// file : examples/cxx/hybrid/wildcard/envelope-pimpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef ENVELOPE_PIMPL_HXX +#define ENVELOPE_PIMPL_HXX + +namespace email +{ + // Customized envelope parser implementation. All wildcard events are + // routed to the _start_any_element, _end_any_element, _any_attribute, + // and _any_characters functions. We can dynamically select a parser + // from the _start_any_element after which all inner content will be + // automatically routed to this parser. At the end we will get a call + // to _end_any_element in which we can call post(), and save the data. + // + class envelope_pimpl: public envelope_base_pimpl + { + public: + envelope_pimpl () + : depth_ (0), text_p_ (0), binary_p_ (0) + { + } + + // Additional parsers for the wildcard content. + // + void + text_parser (xml_schema::string_pskel& p) + { + text_p_ = &p; + } + + void + binary_parser (binary_pskel& p) + { + binary_p_ = &p; + } + + public: + virtual void + _pre (); + + // If the XSD runtime library was configured with polymorphism + // support, then _start_any_element has a third argument which + // is a dynamic type id that comes from xsi:type or substitution + // groups. + // +#ifndef XSDE_POLYMORPHIC + virtual void + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name); +#else + virtual void + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char*); +#endif + + virtual void + _end_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name); + + // If we need to be able to reset and reuse the parser after + // an error then we also need to override _reset() and reset + // the parsers that are used to handle wildcards. + // + virtual void + _reset (); + + private: + std::size_t depth_; + + // Parsers for the text and binary elements. + // + private: + xml_schema::string_pskel* text_p_; + binary_pskel* binary_p_; + }; +} + +#endif // ENVELOPE_PIMPL_HXX diff --git a/examples/cxx/hybrid/wildcard/envelope-simpl.cxx b/examples/cxx/hybrid/wildcard/envelope-simpl.cxx new file mode 100644 index 0000000..ae7bd00 --- /dev/null +++ b/examples/cxx/hybrid/wildcard/envelope-simpl.cxx @@ -0,0 +1,137 @@ +// file : examples/cxx/hybrid/wildcard/envelope-simpl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "body.hxx" + +// Include email-simpl.hxx (which includes envelope-simpl.hxx) +// instead of envelope-simpl.hxx. +// +#include "email-simpl.hxx" + +namespace email +{ + void envelope_simpl:: + _pre () + { + // Initialize the body iterator. + // + i_ = envelope_base_simpl_state_.envelope_->custom_data ().begin (); + } + + bool envelope_simpl:: + any_next () + { + envelope::custom_data_const_iterator end ( + envelope_base_simpl_state_.envelope_->custom_data ().end ()); + + // See if there is a body that we know how to serialize. + // + for (; i_ != end; ++i_) + { + body::type t = static_cast<const body*> (*i_)->body_type (); + + if (t == body::type_text || t == body::type_binary) + break; + } + + return i_ != end; + } + + void envelope_simpl:: + any (std::string& ns, std::string& name) + { + ns = "http://www.codesynthesis.com/email"; + + switch (static_cast<const body*> (*i_)->body_type ()) + { + case body::type_text: + { + name = "text"; + break; + } + case body::type_binary: + { + name = "binary"; + break; + } + default: + break; + } + } + + void envelope_simpl:: + serialize_any () + { + xml_schema::serializer_base* s = 0; + const body* b = static_cast<const body*> (*i_++); + + // If you are not using exceptions then you will need to add + // error propagation code. For more information on how to do + // this see the wildcard example for the C++/Parser mapping + // (examples/parser/ directory). + // + switch (b->body_type ()) + { + case body::type_text: + { + text_s_->pre (b->text ()); + s = text_s_; + break; + } + case body::type_binary: + { + binary_s_->pre (b->binary ()); + s = binary_s_; + break; + } + default: + break; + } + + if (s != 0) + { + // If XML Schema validation is enabled then we need to check + // for error conditions. + // + xml_schema::serializer_context& ctx = _context (); + + s->_pre_impl (ctx); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->_serialize_attributes (); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->_serialize_content (); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->_post_impl (); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->post (); + } + } + + void envelope_simpl:: + _reset () + { + text_s_->_reset (); + binary_s_->_reset (); + + // Note that we always need to call _reset() from the base. + // + envelope_base_simpl::_reset (); + } +} diff --git a/examples/cxx/hybrid/wildcard/envelope-simpl.hxx b/examples/cxx/hybrid/wildcard/envelope-simpl.hxx new file mode 100644 index 0000000..1de12bd --- /dev/null +++ b/examples/cxx/hybrid/wildcard/envelope-simpl.hxx @@ -0,0 +1,67 @@ +// file : examples/cxx/hybrid/wildcard/envelope-simpl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef ENVELOPE_SIMPL_HXX +#define ENVELOPE_SIMPL_HXX + +namespace email +{ + // Customized envelope serializer implementation. Here we implement + // the any_next, any, and serialize_any callbacks to serialize the + // wildcard content. + // + class envelope_simpl: public envelope_base_simpl + { + public: + envelope_simpl () + : text_s_ (0), binary_s_ (0) + { + } + + // Additional serializers for the wildcard content. + // + void + text_serializer (xml_schema::string_sskel& s) + { + text_s_ = &s; + } + + void + binary_serializer (binary_sskel& s) + { + binary_s_ = &s; + } + + public: + virtual void + _pre (); + + virtual bool + any_next (); + + virtual void + any (std::string& ns, std::string& name); + + virtual void + serialize_any (); + + // If we need to be able to reset and reuse the serializer + // after an error then we also need to override _reset() and + // reset the serializers that are used to handle wildcards. + // + virtual void + _reset (); + + private: + envelope::custom_data_const_iterator i_; + + // Serializers for the text and binary elements. + // + private: + xml_schema::string_sskel* text_s_; + binary_sskel* binary_s_; + }; +} + +#endif // ENVELOPE_SIMPL_HXX diff --git a/examples/cxx/hybrid/wildcard/makefile b/examples/cxx/hybrid/wildcard/makefile new file mode 100644 index 0000000..94d2fae --- /dev/null +++ b/examples/cxx/hybrid/wildcard/makefile @@ -0,0 +1,80 @@ +# file : examples/cxx/hybrid/wildcard/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := email.xsd +cxx := driver.cxx body.cxx envelope-pimpl.cxx envelope-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 +clean := $(out_base)/.clean + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=.hxx) \ + $(out_base)/$(xsd:.xsd=.cxx) \ + $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) \ + $(out_base)/$(xsd:.xsd=-sskel.hxx) \ + $(out_base)/$(xsd:.xsd=-sskel.cxx) \ + $(out_base)/$(xsd:.xsd=-simpl.hxx) \ + $(out_base)/$(xsd:.xsd=-simpl.cxx) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate --root-element-all --custom-data envelope \ +--custom-parser envelope=envelope_base_pimpl/envelope-pimpl.hxx \ +--custom-serializer envelope=envelope_base_simpl/envelope-simpl.hxx + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) |