diff options
Diffstat (limited to 'examples/cxx/parser')
76 files changed, 5415 insertions, 0 deletions
diff --git a/examples/cxx/parser/README b/examples/cxx/parser/README new file mode 100644 index 0000000..eaf9342 --- /dev/null +++ b/examples/cxx/parser/README @@ -0,0 +1,32 @@ +This directory contains a number of examples that show how to +use the Embedded C++/Parser 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. + +generated + Shows how to use the sample implementation and test driver + generation feature. This example does not have any hand-written + C++ code; everything is generated by the XSD/e compiler. + +library + Shows how to handle more complex data structures and construct + a custom in-memory object model. + +minimal + This example is a minimal parser implementation that is + intended to work without STL, iostream, or C++ exceptions. + +wildcard + Shows how to parse XML data matched by XML Schema wildcards (any + and anyAttribute). + +multiroot + Shows how to handle XML vocabularies with multiple root elements. + +mixed + Shows how to handle raw, "type-less content" such as mixed content + models, anyType/anySimpleType, and any/anyAttribute. diff --git a/examples/cxx/parser/generated/README b/examples/cxx/parser/generated/README new file mode 100644 index 0000000..ab7ab06 --- /dev/null +++ b/examples/cxx/parser/generated/README @@ -0,0 +1,36 @@ +This example shows how to use the sample implementation and test +driver generation feature of the Embedded C++/Parser mapping. This +example does not have any hand-written C++ code; everything is +generated by the XSD/e compiler. + +The example consists of the following files: + +library.xsd + XML Schema which describes a library of books. + +library.xml + Sample XML instance document. + +library-pskel.hxx +library-pskel.cxx + Parser skeletons generated by XSD/e from library.xsd. + +library-pimpl.hxx +library-pimpl.cxx + Sample parser implementations that print the XML data to STDOUT. + These are generated by XSD/e from library.xsd with the + --generate-print-impl option. + +library-pdriver.cxx + Sample driver for the example. It is generated by XSD/e from + library.xsd with the --generate-test-driver option. + + +To run the example on the sample XML instance document simply +execute: + +$ ./library-pdriver library.xml + +The example reads from STDIN if input file is not specified: + +$ ./library-pdriver <library.xml diff --git a/examples/cxx/parser/generated/library.xml b/examples/cxx/parser/generated/library.xml new file mode 100644 index 0000000..2d9069c --- /dev/null +++ b/examples/cxx/parser/generated/library.xml @@ -0,0 +1,53 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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 id="MM" available="false"> + <isbn>0679760806</isbn> + <title>The Master and Margarita</title> + <genre>fiction</genre> + + <author recommends="WP"> + <name>Mikhail Bulgakov</name> + <born>1891-05-15</born> + <died>1940-03-10</died> + </author> + </book> + + + <book id="WP" available="true" > + <isbn>0679600841</isbn> + <title>War and Peace</title> + <genre>history</genre> + + <author recommends="CP"> + <name>Leo Tolstoy</name> + <born>1828-09-09</born> + <died>1910-11-20</died> + </author> + </book> + + + <book id="CP" 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/parser/generated/library.xsd b/examples/cxx/parser/generated/library.xsd new file mode 100644 index 0000000..57654c7 --- /dev/null +++ b/examples/cxx/parser/generated/library.xsd @@ -0,0 +1,79 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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="person"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + <xsd:element name="born" type="xsd:string"/> + <xsd:element name="died" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + + <xsd:complexType name="author"> + <xsd:complexContent> + <xsd:extension base="lib:person"> + <xsd:attribute name="recommends" type="xsd:IDREF"/> <!-- Book --> + </xsd:extension> + </xsd:complexContent> + </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:attribute name="id" type="xsd:ID" 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/parser/generated/makefile b/examples/cxx/parser/generated/makefile new file mode 100644 index 0000000..8bd0b05 --- /dev/null +++ b/examples/cxx/parser/generated/makefile @@ -0,0 +1,71 @@ +# file : examples/cxx/parser/generated/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 + +xsd := library.xsd + +obj := $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.o) $(xsd:.xsd=-pimpl.o) $(xsd:.xsd=-pdriver.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)/$(xsd:.xsd=-pdriver) +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +gen := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.hxx) \ + $(out_base)/$(xsd:.xsd=-pimpl.cxx) \ + $(out_base)/$(xsd:.xsd=-pdriver.cxx) + +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-print-impl --generate-test-driver \ +--force-overwrite +$(gen): $(out_root)/xsde/xsde + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pimpl.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) + +xsd_pimpl_suffix := -pimpl +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/hello/README b/examples/cxx/parser/hello/README new file mode 100644 index 0000000..958ed1e --- /dev/null +++ b/examples/cxx/parser/hello/README @@ -0,0 +1,33 @@ +This is a "Hello, world!" example that shows how to use the +Embedded C++/Parser mapping to parse XML instance documents. + +The example consists of the following files: + +hello.xsd + XML Schema which describes "hello" instance documents. + +hello.xml + Sample XML instance document. + +hello-pskel.hxx +hello-pskel.ixx +hello-pskel.cxx + Parser skeletons generated by XSD/e from hello.xsd. + +driver.cxx + A parser implementation and a driver for the example. The + parser implementation simply prints the results to STDERR. + The driver first constructs a parser instance from the + parser implementation mentioned above and a couple of + predefined parsers for the XML Schema built-in types. + In then invokes this parser instance to parse the input + file. + +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/parser/hello/driver.cxx b/examples/cxx/parser/hello/driver.cxx new file mode 100644 index 0000000..2326445 --- /dev/null +++ b/examples/cxx/parser/hello/driver.cxx @@ -0,0 +1,82 @@ +// file : examples/cxx/parser/hello/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <string> +#include <iostream> + +#include "hello-pskel.hxx" + +using namespace std; + +struct hello_pimpl: hello_pskel +{ + virtual void + greeting (const string& greeting) + { + greeting_ = greeting; + } + + virtual void + name (const string& name) + { + cout << greeting_ << ", " << name << "!" << endl; + } + +private: + string greeting_; +}; + + +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 + { + // Construct the parser. + // + xml_schema::string_pimpl string_p; + hello_pimpl hello_p; + + hello_p.greeting_parser (string_p); + hello_p.name_parser (string_p); + + + // Parse the XML instance document. The second argument to the + // document's constructor is the document's root element name. + // + xml_schema::document_pimpl doc_p (hello_p, "hello"); + + hello_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + hello_p.post_hello (); + } + 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/parser/hello/hello.xml b/examples/cxx/parser/hello/hello.xml new file mode 100644 index 0000000..2e5aaa3 --- /dev/null +++ b/examples/cxx/parser/hello/hello.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/hello/hello.xsd b/examples/cxx/parser/hello/hello.xsd new file mode 100644 index 0000000..f0941b7 --- /dev/null +++ b/examples/cxx/parser/hello/hello.xsd @@ -0,0 +1,22 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/hello/makefile b/examples/cxx/parser/hello/makefile new file mode 100644 index 0000000..9067e04 --- /dev/null +++ b/examples/cxx/parser/hello/makefile @@ -0,0 +1,64 @@ +# file : examples/cxx/parser/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=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): $(out_root)/xsde/xsde + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/library/README b/examples/cxx/parser/library/README new file mode 100644 index 0000000..da0a49b --- /dev/null +++ b/examples/cxx/parser/library/README @@ -0,0 +1,53 @@ +This example shows how to use the Embedded C++/Parser mapping +to construct a custom in-memory object model from XML instance +documents. + +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 + Types that describe a library of books in C++. These are + hand-written. + +library.map + Type map. It maps XML Schema types defined in library.xsd + to C++ types defined in library.hxx. + +library-pskel.hxx +library-pskel.ixx +library-pskel.cxx + Parser skeletons generated by XSD/e from library.xsd and + library.map. + +library-pimpl-mixin.hxx +library-pimpl-mixin.cxx + +library-pimpl-tiein.hxx +library-pimpl-tiein.cxx + Parser implementations (using either mixin or tiein parser + reuse style) that construct the custom in-memory object model + from an XML instance using types from library.hxx. These are + hand-written implementations of the parser skeletons defined + in library-pskel.hxx. + +driver.cxx + Driver for the example. It first constructs a parser + instance from all the individual parsers found in one of + library-pimpl-*.hxx. In then invokes this parser instance + to parse the input file and produce the in-memory object + model. Finally, it prints the content of the object model + to STDERR. + +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/parser/library/driver.cxx b/examples/cxx/parser/library/driver.cxx new file mode 100644 index 0000000..902499a --- /dev/null +++ b/examples/cxx/parser/library/driver.cxx @@ -0,0 +1,131 @@ +// file : examples/cxx/parser/library/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "library.hxx" + +#include "library-pskel.hxx" // Get the configuration macros (XSDE_*). + +#if defined(XSDE_REUSE_STYLE_MIXIN) +# include "library-pimpl-mixin.hxx" +#elif defined(XSDE_REUSE_STYLE_TIEIN) +# include "library-pimpl-tiein.hxx" +#else +# error this example requires mixin or tiein parser reuse support +#endif + +using std::cerr; +using std::endl; + +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; + + + // Construct the parser. + // + xml_schema::id_pimpl id_p; + xml_schema::idref_pimpl idref_p; + xml_schema::string_pimpl string_p; + xml_schema::boolean_pimpl boolean_p; + + isbn_pimpl isbn_p; + + title_pimpl title_p; + title_p.lang_parser (string_p); + + genre_pimpl genre_p; + + author_pimpl author_p; + author_p.parsers (string_p, // name + string_p, // born + string_p, // died + idref_p); // recommends + + book_pimpl book_p; + book_p.parsers (boolean_p, // available + id_p, // id + isbn_p, // isbn + title_p, // title + genre_p, // genre + author_p); // author + + catalog_pimpl catalog_p; + catalog_p.book_parser (book_p); + + + // Parse the XML instance document. + // + xml_schema::document_pimpl doc_p ( + catalog_p, + "http://www.codesynthesis.com/library", // root element namespace + "catalog"); // root element name + + catalog_p.pre (); + + if (argc < 2) + doc_p.parse (std::cin); + else + doc_p.parse (argv[1]); + + catalog c (catalog_p.post_catalog ()); + + + // Let's print what we've got. + // + for (catalog::const_iterator bi (c.begin ()); bi != c.end (); ++bi) + { + cerr << endl + << "ID : " << bi->id () << endl + << "ISBN : " << bi->isbn () << endl + << "Title : " << bi->title () << endl + << "Genre : " << bi->genre () << endl; + + for (book::authors::const_iterator ai (bi->author ().begin ()); + ai != bi->author ().end (); + ++ai) + { + cerr << "Author : " << ai->name () << endl; + cerr << " Born : " << ai->born () << endl; + + if (!ai->died ().empty ()) + cerr << " Died : " << ai->died () << endl; + + if (!ai->recommends ().empty ()) + { + cerr << " Recommends : " << ai->recommends () << endl; + } + } + + cerr << "Available : " << std::boolalpha << bi->available () << endl; + } + } + catch (const xml_schema::parser_exception& e) + { + cerr << input << ":" << e.line () << ":" << e.column () << ": " + << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << input << ": unable to open or read failure" << endl; + return 1; + } + + return 0; +} diff --git a/examples/cxx/parser/library/library-pimpl-mixin.cxx b/examples/cxx/parser/library/library-pimpl-mixin.cxx new file mode 100644 index 0000000..ac525a2 --- /dev/null +++ b/examples/cxx/parser/library/library-pimpl-mixin.cxx @@ -0,0 +1,184 @@ +// file : examples/cxx/parser/library/library-pimpl-mixin.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "library-pimpl-mixin.hxx" + +namespace library +{ + // isbn_pimpl + // + isbn isbn_pimpl:: + post_isbn () + { + return post_unsigned_int (); + } + + // title_pimpl + // + void title_pimpl:: + _pre () + { + title_.lang (""); + } + + void title_pimpl:: + lang (const std::string& lang) + { + title_.lang (lang); + } + + title title_pimpl:: + post_title () + { + title_.assign (post_string ()); + return title_; + } + + // genre_pimpl + // + genre genre_pimpl:: + post_genre () + { + genre r (romance); + std::string v (post_string ()); + + if (v == "romance") r = romance; else + if (v == "fiction") r = fiction; else + if (v == "horror") r = horror; else + if (v == "history") r = history; else + if (v == "philosophy") r = philosophy; + + return r; + } + + // person_pimpl + // + void person_pimpl:: + _pre () + { + person_.died (""); + } + + void person_pimpl:: + name (const std::string& name) + { + person_.name (name); + } + + void person_pimpl:: + born (const std::string& born) + { + person_.born (born); + } + + void person_pimpl:: + died (const std::string& died) + { + person_.died (died); + } + + person person_pimpl:: + post_person () + { + return person_; + } + + // author_pimpl + // + void author_pimpl:: + _pre () + { + author_.recommends (""); + person_pimpl::_pre (); + } + + void author_pimpl:: + recommends (const std::string& recommends) + { + author_.recommends (recommends); + } + + author author_pimpl:: + post_author () + { + person p (post_person ()); + + author_.name (p.name ()); + author_.born (p.born ()); + author_.died (p.died ()); + + return author_; + } + + // book_pimpl + // + void book_pimpl:: + _pre () + { + book_.author ().clear (); + } + + void book_pimpl:: + isbn (library::isbn isbn) + { + book_.isbn (isbn); + } + + void book_pimpl:: + title (const library::title& title) + { + book_.title (title); + } + + void book_pimpl:: + genre (library::genre genre) + { + book_.genre (genre); + } + + void book_pimpl:: + author (const library::author& author) + { + book_.author ().push_back (author); + } + + void book_pimpl:: + available (bool available) + { + book_.available (available); + } + + void book_pimpl:: + id (const std::string& id) + { + book_.id (id); + } + + book book_pimpl:: + post_book () + { + return book_; + } + + // catalog_pimpl + // + void catalog_pimpl:: + _pre () + { + catalog_.clear (); + } + + void catalog_pimpl:: + book (const library::book& book) + { + catalog_.push_back (book); + } + + catalog catalog_pimpl:: + post_catalog () + { + return catalog_; + } +} + diff --git a/examples/cxx/parser/library/library-pimpl-mixin.hxx b/examples/cxx/parser/library/library-pimpl-mixin.hxx new file mode 100644 index 0000000..e57efea --- /dev/null +++ b/examples/cxx/parser/library/library-pimpl-mixin.hxx @@ -0,0 +1,136 @@ +// file : examples/cxx/parser/library/library-pimpl-mixin.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef LIBRARY_PIMPL_HXX +#define LIBRARY_PIMPL_HXX + +#include "library.hxx" +#include "library-pskel.hxx" + +namespace library +{ + // + // + struct isbn_pimpl: virtual isbn_pskel, xml_schema::unsigned_int_pimpl + { + virtual isbn + post_isbn (); + }; + + // + // + struct title_pimpl: virtual title_pskel, xml_schema::string_pimpl + { + virtual void + _pre (); + + virtual void + lang (const std::string&); + + virtual title + post_title (); + + private: + title title_; + }; + + // + // + struct genre_pimpl: virtual genre_pskel, xml_schema::string_pimpl + { + virtual genre + post_genre (); + }; + + // + // + struct person_pimpl: virtual person_pskel + { + virtual void + _pre (); + + virtual void + name (const std::string&); + + virtual void + born (const std::string&); + + virtual void + died (const std::string&); + + virtual person + post_person (); + + private: + person person_; + }; + + // + // + struct author_pimpl: virtual author_pskel, person_pimpl + { + virtual void + _pre (); + + virtual void + recommends (const std::string&); + + virtual author + post_author (); + + private: + author author_; + }; + + // + // + struct book_pimpl: virtual book_pskel + { + virtual void + _pre (); + + virtual void + isbn (library::isbn); + + virtual void + title (const library::title&); + + virtual void + genre (library::genre); + + virtual void + author (const library::author&); + + virtual void + available (bool); + + virtual void + id (const std::string&); + + virtual book + post_book (); + + private: + book book_; + }; + + // + // + struct catalog_pimpl: virtual catalog_pskel + { + virtual void + _pre (); + + virtual void + book (const library::book&); + + virtual catalog + post_catalog (); + + private: + catalog catalog_; + }; +} + +#endif // LIBRARY_PIMPL_HXX diff --git a/examples/cxx/parser/library/library-pimpl-tiein.cxx b/examples/cxx/parser/library/library-pimpl-tiein.cxx new file mode 100644 index 0000000..f4f54a8 --- /dev/null +++ b/examples/cxx/parser/library/library-pimpl-tiein.cxx @@ -0,0 +1,208 @@ +// file : examples/cxx/parser/library/library-pimpl-tiein.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "library-pimpl-tiein.hxx" + +namespace library +{ + // isbn_pimpl + // + isbn_pimpl:: + isbn_pimpl () + : isbn_pskel (&base_impl_) + { + } + + isbn isbn_pimpl:: + post_isbn () + { + return post_unsigned_int (); + } + + // title_pimpl + // + title_pimpl:: + title_pimpl () + : title_pskel (&base_impl_) + { + } + + void title_pimpl:: + _pre () + { + title_.lang (""); + } + + void title_pimpl:: + lang (const std::string& lang) + { + title_.lang (lang); + } + + title title_pimpl:: + post_title () + { + title_.assign (post_string ()); + return title_; + } + + // genre_pimpl + // + genre_pimpl:: + genre_pimpl () + : genre_pskel (&base_impl_) + { + } + + genre genre_pimpl:: + post_genre () + { + genre r (romance); + std::string v (post_string ()); + + if (v == "romance") r = romance; else + if (v == "fiction") r = fiction; else + if (v == "horror") r = horror; else + if (v == "history") r = history; else + if (v == "philosophy") r = philosophy; + + return r; + } + + // person_pimpl + // + void person_pimpl:: + _pre () + { + person_.died (""); + } + + void person_pimpl:: + name (const std::string& name) + { + person_.name (name); + } + + void person_pimpl:: + born (const std::string& born) + { + person_.born (born); + } + + void person_pimpl:: + died (const std::string& died) + { + person_.died (died); + } + + person person_pimpl:: + post_person () + { + return person_; + } + + // author_pimpl + // + author_pimpl:: + author_pimpl () + : author_pskel (&base_impl_) + { + } + + void author_pimpl:: + _pre () + { + author_.recommends (""); + base_impl_._pre (); + } + + void author_pimpl:: + recommends (const std::string& recommends) + { + author_.recommends (recommends); + } + + author author_pimpl:: + post_author () + { + person p (post_person ()); + + author_.name (p.name ()); + author_.born (p.born ()); + author_.died (p.died ()); + + return author_; + } + + // book_pimpl + // + void book_pimpl:: + _pre () + { + book_.author ().clear (); + } + + void book_pimpl:: + isbn (library::isbn isbn) + { + book_.isbn (isbn); + } + + void book_pimpl:: + title (const library::title& title) + { + book_.title (title); + } + + void book_pimpl:: + genre (library::genre genre) + { + book_.genre (genre); + } + + void book_pimpl:: + author (const library::author& author) + { + book_.author ().push_back (author); + } + + void book_pimpl:: + available (bool available) + { + book_.available (available); + } + + void book_pimpl:: + id (const std::string& id) + { + book_.id (id); + } + + book book_pimpl:: + post_book () + { + return book_; + } + + // catalog_pimpl + // + void catalog_pimpl:: + _pre () + { + catalog_.clear (); + } + + void catalog_pimpl:: + book (const library::book& book) + { + catalog_.push_back (book); + } + + catalog catalog_pimpl:: + post_catalog () + { + return catalog_; + } +} + diff --git a/examples/cxx/parser/library/library-pimpl-tiein.hxx b/examples/cxx/parser/library/library-pimpl-tiein.hxx new file mode 100644 index 0000000..423bc91 --- /dev/null +++ b/examples/cxx/parser/library/library-pimpl-tiein.hxx @@ -0,0 +1,152 @@ +// file : examples/cxx/parser/library/library-pimpl-tiein.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef LIBRARY_PIMPL_HXX +#define LIBRARY_PIMPL_HXX + +#include "library.hxx" +#include "library-pskel.hxx" + +namespace library +{ + // + // + struct isbn_pimpl: isbn_pskel + { + isbn_pimpl (); + + virtual isbn + post_isbn (); + + private: + xml_schema::unsigned_int_pimpl base_impl_; + }; + + // + // + struct title_pimpl: title_pskel + { + title_pimpl (); + + virtual void + _pre (); + + virtual void + lang (const std::string&); + + virtual title + post_title (); + + private: + title title_; + xml_schema::string_pimpl base_impl_; + }; + + // + // + struct genre_pimpl: genre_pskel + { + genre_pimpl (); + + virtual genre + post_genre (); + + private: + xml_schema::string_pimpl base_impl_; + }; + + // + // + struct person_pimpl: person_pskel + { + virtual void + _pre (); + + virtual void + name (const std::string&); + + virtual void + born (const std::string&); + + virtual void + died (const std::string&); + + virtual person + post_person (); + + private: + person person_; + }; + + // + // + struct author_pimpl: author_pskel + { + author_pimpl (); + + virtual void + _pre (); + + virtual void + recommends (const std::string&); + + virtual author + post_author (); + + private: + person_pimpl base_impl_; + author author_; + }; + + // + // + struct book_pimpl: book_pskel + { + virtual void + _pre (); + + virtual void + isbn (library::isbn); + + virtual void + title (const library::title&); + + virtual void + genre (library::genre); + + virtual void + author (const library::author&); + + virtual void + available (bool); + + virtual void + id (const std::string&); + + virtual book + post_book (); + + private: + book book_; + }; + + // + // + struct catalog_pimpl: catalog_pskel + { + virtual void + _pre (); + + virtual void + book (const library::book&); + + virtual catalog + post_catalog (); + + private: + catalog catalog_; + }; +} + +#endif // LIBRARY_PIMPL_HXX diff --git a/examples/cxx/parser/library/library.hxx b/examples/cxx/parser/library/library.hxx new file mode 100644 index 0000000..fb6cc1d --- /dev/null +++ b/examples/cxx/parser/library/library.hxx @@ -0,0 +1,242 @@ +// file : examples/cxx/parser/library/library.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef LIBRARY_HXX +#define LIBRARY_HXX + +#include <string> +#include <vector> + +namespace library +{ + // + // + typedef unsigned int isbn; + + + // + // + struct title: std::string + { + // lang + // + const std::string& + lang () const + { + return lang_; + } + + void + lang (const std::string& lang) + { + lang_ = lang; + } + + private: + std::string lang_; + }; + + + // + // + enum genre + { + romance, + fiction, + horror, + history, + philosophy + }; + + + // + // + struct person + { + // name + // + const std::string& + name () const + { + return name_; + } + + void + name (const std::string& name) + { + name_ = name; + } + + // born + // + const std::string& + born () const + { + return born_; + } + + void + born (const std::string& born) + { + born_ = born; + } + + + // died + // + const std::string& + died () const + { + return died_; + } + + void + died (const std::string& died) + { + died_ = died; + } + + private: + std::string name_; + std::string born_; + std::string died_; + }; + + + // + // + struct author: person + { + // recommends + // + const std::string& + recommends () const + { + return recommends_; + } + + void + recommends (const std::string& recommends) + { + recommends_ = recommends; + } + + private: + std::string recommends_; + }; + + + // + // + struct book + { + // isbn + // + library::isbn + isbn () const + { + return isbn_; + } + + void + isbn (const library::isbn& isbn) + { + isbn_ = isbn; + } + + + // title + // + library::title + title () const + { + return title_; + } + + void + title (const library::title& title) + { + title_ = title; + } + + + // genre + // + library::genre + genre () const + { + return genre_; + } + + void + genre (const library::genre& genre) + { + genre_ = genre; + } + + + // author + // + typedef std::vector<library::author> authors; + + const authors& + author () const + { + return author_; + } + + authors& + author () + { + return author_; + } + + + // available + // + bool + available () const + { + return available_; + } + + void + available (bool available) + { + available_ = available; + } + + + // id + // + const std::string& + id () const + { + return id_; + } + + void + id (const std::string& id) + { + id_ = id; + } + + private: + library::isbn isbn_; + library::title title_; + library::genre genre_; + + authors author_; + + bool available_; + std::string id_; + }; + + + // + // + typedef std::vector<book> catalog; +} + +#endif // LIBRARY_HXX diff --git a/examples/cxx/parser/library/library.map b/examples/cxx/parser/library/library.map new file mode 100644 index 0000000..87a1d53 --- /dev/null +++ b/examples/cxx/parser/library/library.map @@ -0,0 +1,16 @@ +# file : examples/cxx/parser/library/library.map +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : not copyrighted - public domain + +namespace http://www.codesynthesis.com/library library +{ + include "library.hxx"; + + isbn isbn isbn; + title title; + genre genre genre; + person person; + author author; + book book; + catalog catalog; +} diff --git a/examples/cxx/parser/library/library.xml b/examples/cxx/parser/library/library.xml new file mode 100644 index 0000000..2d9069c --- /dev/null +++ b/examples/cxx/parser/library/library.xml @@ -0,0 +1,53 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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 id="MM" available="false"> + <isbn>0679760806</isbn> + <title>The Master and Margarita</title> + <genre>fiction</genre> + + <author recommends="WP"> + <name>Mikhail Bulgakov</name> + <born>1891-05-15</born> + <died>1940-03-10</died> + </author> + </book> + + + <book id="WP" available="true" > + <isbn>0679600841</isbn> + <title>War and Peace</title> + <genre>history</genre> + + <author recommends="CP"> + <name>Leo Tolstoy</name> + <born>1828-09-09</born> + <died>1910-11-20</died> + </author> + </book> + + + <book id="CP" 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/parser/library/library.xsd b/examples/cxx/parser/library/library.xsd new file mode 100644 index 0000000..57654c7 --- /dev/null +++ b/examples/cxx/parser/library/library.xsd @@ -0,0 +1,79 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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="person"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + <xsd:element name="born" type="xsd:string"/> + <xsd:element name="died" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + + <xsd:complexType name="author"> + <xsd:complexContent> + <xsd:extension base="lib:person"> + <xsd:attribute name="recommends" type="xsd:IDREF"/> <!-- Book --> + </xsd:extension> + </xsd:complexContent> + </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:attribute name="id" type="xsd:ID" 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/parser/library/makefile b/examples/cxx/parser/library/makefile new file mode 100644 index 0000000..3df256c --- /dev/null +++ b/examples/cxx/parser/library/makefile @@ -0,0 +1,72 @@ +# file : examples/cxx/parser/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 + +ifeq ($(xsde_reuse_style),mixin) +cxx += library-pimpl-mixin.cxx +else +cxx += library-pimpl-tiein.cxx +endif + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): xsde_options += --generate-inline --type-map $(src_base)/library.map + +$(skel): $(out_root)/xsde/xsde $(src_base)/library.map + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/makefile b/examples/cxx/parser/makefile new file mode 100644 index 0000000..5a81a72 --- /dev/null +++ b/examples/cxx/parser/makefile @@ -0,0 +1,53 @@ +# file : examples/cxx/parser/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 := + +ifneq ($(xsde_reuse_style),none) +examples += generated +endif + +ifeq ($(xsde_stl),y) +ifeq ($(xsde_iostream),y) +ifeq ($(xsde_exceptions),y) + +examples += hello + +ifneq ($(xsde_reuse_style),none) +examples += library multiroot + +ifeq ($(xsde_polymorphic),y) +examples += polymorphism polyroot +endif + +endif + +ifeq ($(xsde_reuse_style),tiein) +examples += mixed wildcard +endif + +endif +endif +endif + +ifeq ($(xsde_stl),n) +ifeq ($(xsde_exceptions),n) +ifneq ($(xsde_reuse_style),none) +examples += minimal +endif +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/parser/minimal/README b/examples/cxx/parser/minimal/README new file mode 100644 index 0000000..a525533 --- /dev/null +++ b/examples/cxx/parser/minimal/README @@ -0,0 +1,51 @@ +This example is a minimal parser implementation that is +intended to work without 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. + +gender.hxx + C++ gender enum that corresponds to the gender types + in people.xsd. + +people.map + Type map. It maps XML Schema gender type defined in + people.xsd to C++ gender enum defined in gender.hxx. + +people-pskel.hxx +people-pskel.ixx +people-pskel.cxx + Parser skeletons generated by XSD/e from people.xsd and + people.map. The --no-stl and --no-exceptions options + were used to produce these files. + +people-pimpl-mixin.hxx + +people-pimpl-tiein.hxx + Parser implementations (using either mixin or tiein parser + reuse style) that prints the results to STDERR. These are + hand-written implementations of the parser skeletons defined + in people-pskel.hxx. + +driver.cxx + Driver for the example. It first constructs a parser instance + from the parser implementation mentioned above and a couple of + predefined parsers for the XML Schema built-in types. In then + invokes this parser instance to parse the input file. It also + shows how to handle parsing and validation errors using error + codes. + +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/parser/minimal/driver.cxx b/examples/cxx/parser/minimal/driver.cxx new file mode 100644 index 0000000..e526358 --- /dev/null +++ b/examples/cxx/parser/minimal/driver.cxx @@ -0,0 +1,145 @@ +// file : examples/cxx/parser/minimal/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <stdio.h> + +#include "people-pskel.hxx" // Get the configuration macros (XSDE_*). + +#if defined(XSDE_REUSE_STYLE_MIXIN) +# include "people-pimpl-mixin.hxx" +#elif defined(XSDE_REUSE_STYLE_TIEIN) +# include "people-pimpl-tiein.hxx" +#else +# error this example requires mixin or tiein parser reuse support +#endif + +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]; + + // Construct the parser. + // + xml_schema::unsigned_short_pimpl unsigned_short_p; + xml_schema::string_pimpl string_p; + + gender_pimpl gender_p; + person_pimpl person_p; + people_pimpl people_p; + + person_p.parsers (string_p, string_p, gender_p, unsigned_short_p); + people_p.parsers (person_p); + + // 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. + // + typedef xml_schema::parser_error error; + error e; + bool io_error = false; + + do + { + xml_schema::document_pimpl doc_p (people_p, "people"); + + if (e = doc_p._error ()) + break; + + people_p.pre (); + + if (e = 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); + e = doc_p._error (); + + } while (!e && !feof (f)); + + if (io_error || e) + break; + + people_p.post_people (); + + e = people_p._error (); + + } while (false); + + if (argc > 1) + fclose (f); + + // Handle errors. + // + + if (io_error) + { + fprintf (stderr, "%s: read failure\n", input); + return 1; + } + + if (e) + { + switch (e.type ()) + { + case error::sys: + { + fprintf (stderr, "%s: %s\n", input, e.sys_text ()); + break; + } + case error::xml: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + input, e.line (), e.column (), e.xml_text ()); + break; + } +#ifdef XSDE_PARSER_VALIDATION + case error::schema: + { + fprintf (stderr, "%s:%lu:%lu: %s\n", + input, e.line (), e.column (), e.schema_text ()); + break; + } +#endif + case error::app: + { + fprintf (stderr, "%s:%lu:%lu: application error %d\n", + input, e.line (), e.column (), e.app_code ()); + break; + } + default: + break; + } + + return 1; + } + + return 0; +} diff --git a/examples/cxx/parser/minimal/gender.hxx b/examples/cxx/parser/minimal/gender.hxx new file mode 100644 index 0000000..d348ccd --- /dev/null +++ b/examples/cxx/parser/minimal/gender.hxx @@ -0,0 +1,14 @@ +// file : examples/cxx/parser/minimal/gender.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef GENDER_HXX +#define GENDER_HXX + +enum gender +{ + male, + female +}; + +#endif // GENDER_HXX diff --git a/examples/cxx/parser/minimal/makefile b/examples/cxx/parser/minimal/makefile new file mode 100644 index 0000000..1f0466c --- /dev/null +++ b/examples/cxx/parser/minimal/makefile @@ -0,0 +1,66 @@ +# file : examples/cxx/parser/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=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): xsde_options += --type-map $(src_base)/people.map + +$(skel): $(out_root)/xsde/xsde $(src_base)/people.map + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/minimal/people-pimpl-mixin.hxx b/examples/cxx/parser/minimal/people-pimpl-mixin.hxx new file mode 100644 index 0000000..eb2c331 --- /dev/null +++ b/examples/cxx/parser/minimal/people-pimpl-mixin.hxx @@ -0,0 +1,82 @@ +// file : examples/cxx/parser/people/people-pimpl-mixin.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PEOPLE_PIMPL_HXX +#define PEOPLE_PIMPL_HXX + +#include "gender.hxx" +#include "people-pskel.hxx" + +struct gender_pimpl: virtual gender_pskel, xml_schema::string_pimpl +{ + virtual gender + post_gender () + { + char* s = post_string (); + + if (!_error ()) + { + gender g = strcmp (s, "male") ? female : male; + + delete[] s; + return g; + } + else + return male; // This value will never be used. + } +}; + +struct person_pimpl: virtual person_pskel +{ + virtual void + first_name (char* n) + { + printf ("first: %s\n", n); + delete[] n; + } + + virtual void + last_name (char* n) + { + printf ("last: %s\n", n); + delete[] n; + } + + virtual void + gender (::gender g) + { + switch (g) + { + case male: + { + printf ("gender: male\n"); + break; + } + case female: + { + printf ("gender: female\n"); + break; + } + } + } + + virtual void + age (unsigned short a) + { + printf ("age: %hu\n", a); + } +}; + +struct people_pimpl: virtual people_pskel +{ + virtual void + person () + { + // Add an extra newline after each person record. + // + printf ("\n"); + } +}; + +#endif // PEOPLE_PIMPL_HXX diff --git a/examples/cxx/parser/minimal/people-pimpl-tiein.hxx b/examples/cxx/parser/minimal/people-pimpl-tiein.hxx new file mode 100644 index 0000000..154c861 --- /dev/null +++ b/examples/cxx/parser/minimal/people-pimpl-tiein.hxx @@ -0,0 +1,90 @@ +// file : examples/cxx/parser/people/people-pimpl-tiein.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PEOPLE_PIMPL_HXX +#define PEOPLE_PIMPL_HXX + +#include "gender.hxx" +#include "people-pskel.hxx" + +struct gender_pimpl: gender_pskel +{ + gender_pimpl () + : gender_pskel (&base_impl_) + { + } + + virtual gender + post_gender () + { + char* s = post_string (); + + if (!_error ()) + { + gender g = strcmp (s, "male") ? female : male; + + delete[] s; + return g; + } + else + return male; // This value will never be used. + } + +private: + xml_schema::string_pimpl base_impl_; +}; + +struct person_pimpl: person_pskel +{ + virtual void + first_name (char* n) + { + printf ("first: %s\n", n); + delete[] n; + } + + virtual void + last_name (char* n) + { + printf ("last: %s\n", n); + delete[] n; + } + + virtual void + gender (::gender g) + { + switch (g) + { + case male: + { + printf ("gender: male\n"); + break; + } + case female: + { + printf ("gender: female\n"); + break; + } + } + } + + virtual void + age (unsigned short a) + { + printf ("age: %hu\n", a); + } +}; + +struct people_pimpl: people_pskel +{ + virtual void + person () + { + // Add an extra newline after each person record. + // + printf ("\n"); + } +}; + +#endif // PEOPLE_PIMPL_HXX diff --git a/examples/cxx/parser/minimal/people.map b/examples/cxx/parser/minimal/people.map new file mode 100644 index 0000000..05558a1 --- /dev/null +++ b/examples/cxx/parser/minimal/people.map @@ -0,0 +1,7 @@ +# file : examples/cxx/parser/minimal/people.map +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : not copyrighted - public domain + +include "gender.hxx"; + +gender ::gender ::gender; diff --git a/examples/cxx/parser/minimal/people.xml b/examples/cxx/parser/minimal/people.xml new file mode 100644 index 0000000..fce688c --- /dev/null +++ b/examples/cxx/parser/minimal/people.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/minimal/people.xsd b/examples/cxx/parser/minimal/people.xsd new file mode 100644 index 0000000..d2e8f47 --- /dev/null +++ b/examples/cxx/parser/minimal/people.xsd @@ -0,0 +1,37 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/mixed/README b/examples/cxx/parser/mixed/README new file mode 100644 index 0000000..69d2b07 --- /dev/null +++ b/examples/cxx/parser/mixed/README @@ -0,0 +1,54 @@ +This example shows how to handle "type-less content" such as +mixed content models, xsd:anyType/xsd:anySimpleType, and +xsd:any/xsd:anyAttribute in the Embedded C++/Parser mapping. + +In this example we use mixed content model to describe text +with embedded links, e.g., + + This paragraph talks about <a href="uri">time</a>. + +The example transforms such text into plain text with +references, e.g., + + This paragraph talks about time[0]. + + [0] uri + +The example consists of the following files: + +text.xsd + XML Schema which describes "text with links" instance + documents. + +text.xml + Sample XML instance document. + +anchor.hxx + Anchor type that captures the information about a link. + +text.map + Type map. It maps XML Schema anchor types defined in + text.xsd to C++ anchor class defined in anchor.hxx. + +text-pskel.hxx +text-pskel.ixx +text-pskel.cxx + Parser skeletons generated by XSD/e from text.xsd and + text.map. + +driver.cxx + A parser implementation and a driver for the example. The + parser implementation prints the transformed text to STDOUT. + The driver first constructs a parser instance from the parser + implementation mentioned above and a couple of predefined + parsers for the XML Schema built-in types. In then invokes + this parser instance to parse the input file. + +To run the example on the sample XML instance document simply +execute: + +$ ./driver text.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <text.xml diff --git a/examples/cxx/parser/mixed/anchor.hxx b/examples/cxx/parser/mixed/anchor.hxx new file mode 100644 index 0000000..bc1b54d --- /dev/null +++ b/examples/cxx/parser/mixed/anchor.hxx @@ -0,0 +1,34 @@ +// file : examples/cxx/parser/mixed/anchor.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef ANCHOR_HXX +#define ANCHOR_HXX + +#include <string> + +struct anchor +{ + anchor (const std::string& text, const std::string& uri) + : uri_ (uri), text_ (text) + { + } + + const std::string& + text () const + { + return text_; + } + + const std::string& + uri () const + { + return uri_; + } + +private: + std::string uri_; + std::string text_; +}; + +#endif // ANCHOR_HXX diff --git a/examples/cxx/parser/mixed/driver.cxx b/examples/cxx/parser/mixed/driver.cxx new file mode 100644 index 0000000..13877b0 --- /dev/null +++ b/examples/cxx/parser/mixed/driver.cxx @@ -0,0 +1,123 @@ +// file : examples/cxx/parser/mixed/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <string> +#include <vector> +#include <iostream> + +#include "anchor.hxx" +#include "text-pskel.hxx" + +#ifndef XSDE_REUSE_STYLE_TIEIN +# error this example requires the tiein parser reuse support +#endif + +using namespace std; + +struct anchor_pimpl: anchor_pskel +{ + anchor_pimpl () + : anchor_pskel (&base_impl_) + { + } + + virtual void + href (const std::string& uri) + { + uri_ = uri; + } + + virtual anchor + post_anchor () + { + return anchor (post_string (), uri_); + } + +private: + xml_schema::string_pimpl base_impl_; + std::string uri_; +}; + + +struct text_pimpl: text_pskel +{ + virtual void + a (const anchor& a) + { + cout << a.text () << "[" << anchors_.size () << "]"; + anchors_.push_back (a); + } + + virtual void + _any_characters (const xml_schema::ro_string& s) + { + cout << s; + } + + virtual void + post_text () + { + for (anchors::const_iterator i (anchors_.begin ()); + i != anchors_.end (); + ++i) + { + cout << "[" << i - anchors_.begin () << "] " << i->uri () << endl; + } + } + +private: + typedef vector<anchor> anchors; + anchors anchors_; +}; + + +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 + { + // Construct the parser. + // + xml_schema::string_pimpl string_p; + anchor_pimpl anchor_p; + text_pimpl text_p; + + anchor_p.href_parser (string_p); + text_p.a_parser (anchor_p); + + xml_schema::document_pimpl doc_p (text_p, "text"); + + text_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + text_p.post_text (); + } + 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/parser/mixed/makefile b/examples/cxx/parser/mixed/makefile new file mode 100644 index 0000000..f41fae3 --- /dev/null +++ b/examples/cxx/parser/mixed/makefile @@ -0,0 +1,66 @@ +# file : examples/cxx/parser/mixed/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 := text.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): xsde_options += --type-map $(src_base)/text.map + +$(skel): $(out_root)/xsde/xsde $(src_base)/text.map + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/mixed/text.map b/examples/cxx/parser/mixed/text.map new file mode 100644 index 0000000..206d72e --- /dev/null +++ b/examples/cxx/parser/mixed/text.map @@ -0,0 +1,7 @@ +# file : examples/cxx/parser/mixed/text.map +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : not copyrighted - public domain + +include "anchor.hxx"; + +anchor anchor; diff --git a/examples/cxx/parser/mixed/text.xml b/examples/cxx/parser/mixed/text.xml new file mode 100644 index 0000000..97d4d21 --- /dev/null +++ b/examples/cxx/parser/mixed/text.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/text/text.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<text xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="text.xsd"> + +The first paragraph of this text talks about <a href="http://en.wikipedia.org/wiki/time">time</a>. + +And this paragraph talks about <a href="http://en.wikipedia.org/wiki/space">space</a>. + +</text> diff --git a/examples/cxx/parser/mixed/text.xsd b/examples/cxx/parser/mixed/text.xsd new file mode 100644 index 0000000..4929964 --- /dev/null +++ b/examples/cxx/parser/mixed/text.xsd @@ -0,0 +1,29 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/mixed/text.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="anchor"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="href" type="xsd:string" use="required"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="text" mixed="true"> + <xsd:sequence> + <xsd:element name="a" type="anchor" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="text" type="text"/> + +</xsd:schema> diff --git a/examples/cxx/parser/multiroot/README b/examples/cxx/parser/multiroot/README new file mode 100644 index 0000000..817e522 --- /dev/null +++ b/examples/cxx/parser/multiroot/README @@ -0,0 +1,61 @@ +This example shows how to handle XML vocabularies with multiple +root elements using the Embedded C++/Parser 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 + C++ types that describe the protocol requests. These are + hand-written. + +protocol.map + Type map. It maps XML Schema types defined in protocol.xsd + to the C++ types defined in protocol.hxx. + +protocol-pskel.hxx +protocol-pskel.cxx + Parser skeletons generated by XSD/e from protocol.xsd and + protocol.map. + +protocol-pimpl-mixin.hxx +protocol-pimpl-mixin.cxx + +protocol-pimpl-tiein.hxx +protocol-pimpl-tiein.cxx + Parser implementations (using either mixin or tiein parser + reuse style) that construct the custom object model from an + XML instance using the types from protocol.hxx. These are + hand-written implementations of the parser skeletons defined + in protocol-pskel.hxx. + +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 constructs + a parser instance from all the individual parsers found in one + of protocol-pimpl-*.hxx. In then invokes this parser instance + to parse the input file and produce the in-memory object model. + Finally, it prints the contents 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/parser/multiroot/balance.xml b/examples/cxx/parser/multiroot/balance.xml new file mode 100644 index 0000000..df0a6e9 --- /dev/null +++ b/examples/cxx/parser/multiroot/balance.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/multiroot/deposit.xml b/examples/cxx/parser/multiroot/deposit.xml new file mode 100644 index 0000000..3043c52 --- /dev/null +++ b/examples/cxx/parser/multiroot/deposit.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/multiroot/driver.cxx b/examples/cxx/parser/multiroot/driver.cxx new file mode 100644 index 0000000..32aced2 --- /dev/null +++ b/examples/cxx/parser/multiroot/driver.cxx @@ -0,0 +1,245 @@ +// file : examples/cxx/parser/multiroot/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <iostream> + +#include "protocol.hxx" +#include "protocol-pskel.hxx" // Get the configuration macros (XSDE_*). + +#if defined(XSDE_REUSE_STYLE_MIXIN) +# include "protocol-pimpl-mixin.hxx" +#elif defined(XSDE_REUSE_STYLE_TIEIN) +# include "protocol-pimpl-tiein.hxx" +#else +# error this example requires mixin or tiein parser reuse support +#endif + +using std::cerr; +using std::endl; +using xml_schema::ro_string; + +namespace protocol +{ + // We are going to use our own "type ids" for the request + // types. You could instead use dynamic_cast if your system + // provides RTTI. + // + 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 (balance_pskel& balance_p, withdraw_pskel& withdraw_p) + : result_type_ (unknown_type), + balance_p_ (balance_p), + withdraw_p_ (withdraw_p) + { + } + + request_type + result_type () const + { + return result_type_; + } + + request* + result () + { + return result_.release (); + } + + 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") + { + balance_p_.pre (); + return &balance_p_; + } + else if (name == "withdraw") + { + balance_p_.pre (); + return &withdraw_p_; + } + + cerr << "ignoring unknown request: " << name << endl; + 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. + // +#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_ variable. + // + if (parser == &balance_p_) + { + result_type_ = balance_type; + result_.reset (balance_p_.post_balance ()); + } + else if (parser == &withdraw_p_) + { + result_type_ = withdraw_type; + result_.reset (withdraw_p_.post_withdraw ()); + } + else + { + result_type_ = unknown_type; + result_.reset (0); + } + } + + + 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: + request_type result_type_; + std::auto_ptr<request> result_; + + balance_pskel& balance_p_; + withdraw_pskel& 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; + + // Construct the parser. + // + xml_schema::unsigned_int_pimpl unsigned_int_p; + + balance_pimpl balance_p; + withdraw_pimpl withdraw_p; + + balance_p.parsers (unsigned_int_p); // account + + withdraw_p.parsers (unsigned_int_p, // account + unsigned_int_p); // amount + + // Parse the XML instance document. + // + document_pimpl doc_p (balance_p, withdraw_p); + + // pre() and post() will be called as part of the start_root_element() + // and end_root_element() calls. + // + if (argc < 2) + doc_p.parse (std::cin); + else + doc_p.parse (argv[1]); + + std::auto_ptr<request> r (doc_p.result ()); + request_type t = doc_p.result_type (); + + // Let's print what we've got. + // + switch (t) + { + case balance_type: + { + balance* b = static_cast<balance*> (r.get ()); + cerr << "balance request for acc# " << b->account () << endl; + break; + } + case withdraw_type: + { + withdraw* w = static_cast<withdraw*> (r.get ()); + 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/parser/multiroot/makefile b/examples/cxx/parser/multiroot/makefile new file mode 100644 index 0000000..44e8980 --- /dev/null +++ b/examples/cxx/parser/multiroot/makefile @@ -0,0 +1,71 @@ +# file : examples/cxx/parser/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 + +ifeq ($(xsde_reuse_style),mixin) +cxx += protocol-pimpl-mixin.cxx +else +cxx += protocol-pimpl-tiein.cxx +endif + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): xsde_options += --type-map $(src_base)/protocol.map +$(skel): $(out_root)/xsde/xsde $(src_base)/protocol.map + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/multiroot/protocol-pimpl-mixin.cxx b/examples/cxx/parser/multiroot/protocol-pimpl-mixin.cxx new file mode 100644 index 0000000..3cfd0b0 --- /dev/null +++ b/examples/cxx/parser/multiroot/protocol-pimpl-mixin.cxx @@ -0,0 +1,47 @@ +// file : examples/cxx/parser/multiroot/protocol-pimpl-mixin.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "protocol-pimpl-mixin.hxx" + +namespace protocol +{ + // request_pimpl + // + void request_pimpl:: + account (unsigned int account) + { + account_ = account; + } + + request* request_pimpl:: + post_request () + { + // This parser is never used directly. + // + return 0; + } + + // balance_pimpl + // + balance* balance_pimpl:: + post_balance () + { + return new balance (account_); + } + + // withdraw_pimpl + // + void withdraw_pimpl:: + amount (unsigned int amount) + { + amount_ = amount; + } + + withdraw* withdraw_pimpl:: + post_withdraw () + { + return new withdraw (account_, amount_); + } +} + diff --git a/examples/cxx/parser/multiroot/protocol-pimpl-mixin.hxx b/examples/cxx/parser/multiroot/protocol-pimpl-mixin.hxx new file mode 100644 index 0000000..dc26e9a --- /dev/null +++ b/examples/cxx/parser/multiroot/protocol-pimpl-mixin.hxx @@ -0,0 +1,49 @@ +// file : examples/cxx/parser/multiroot/protocol-pimpl-mixin.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PROTOCOL_PIMPL_HXX +#define PROTOCOL_PIMPL_HXX + +#include "protocol.hxx" +#include "protocol-pskel.hxx" + +namespace protocol +{ + class request_pimpl: public virtual request_pskel + { + public: + virtual void + account (unsigned int); + + virtual request* + post_request (); + + protected: + unsigned int account_; + }; + + class balance_pimpl: public virtual balance_pskel, + public request_pimpl + { + public: + virtual balance* + post_balance (); + }; + + class withdraw_pimpl: public virtual withdraw_pskel, + public request_pimpl + { + public: + virtual void + amount (unsigned int); + + virtual withdraw* + post_withdraw (); + + private: + unsigned int amount_; + }; +} + +#endif // PROTOCOL_PIMPL_HXX diff --git a/examples/cxx/parser/multiroot/protocol-pimpl-tiein.cxx b/examples/cxx/parser/multiroot/protocol-pimpl-tiein.cxx new file mode 100644 index 0000000..def6f98 --- /dev/null +++ b/examples/cxx/parser/multiroot/protocol-pimpl-tiein.cxx @@ -0,0 +1,59 @@ +// file : examples/cxx/parser/multiroot/protocol-pimpl-tiein.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include "protocol-pimpl-tiein.hxx" + +namespace protocol +{ + // request_pimpl + // + void request_pimpl:: + account (unsigned int account) + { + account_ = account; + } + + request* request_pimpl:: + post_request () + { + // This parser is never used directly. + // + return 0; + } + + // balance_pimpl + // + balance_pimpl:: + balance_pimpl () + : balance_pskel (&base_impl_) + { + } + + balance* balance_pimpl:: + post_balance () + { + return new balance (base_impl_.account_); + } + + // withdraw_pimpl + // + withdraw_pimpl:: + withdraw_pimpl () + : withdraw_pskel (&base_impl_) + { + } + + void withdraw_pimpl:: + amount (unsigned int amount) + { + amount_ = amount; + } + + withdraw* withdraw_pimpl:: + post_withdraw () + { + return new withdraw (base_impl_.account_, amount_); + } +} + diff --git a/examples/cxx/parser/multiroot/protocol-pimpl-tiein.hxx b/examples/cxx/parser/multiroot/protocol-pimpl-tiein.hxx new file mode 100644 index 0000000..3a18da0 --- /dev/null +++ b/examples/cxx/parser/multiroot/protocol-pimpl-tiein.hxx @@ -0,0 +1,55 @@ +// file : examples/cxx/parser/multiroot/protocol-pimpl-tiein.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PROTOCOL_PIMPL_HXX +#define PROTOCOL_PIMPL_HXX + +#include "protocol.hxx" +#include "protocol-pskel.hxx" + +namespace protocol +{ + class request_pimpl: public request_pskel + { + public: + virtual void + account (unsigned int); + + virtual request* + post_request (); + + public: + unsigned int account_; + }; + + class balance_pimpl: public balance_pskel + { + public: + balance_pimpl (); + + virtual balance* + post_balance (); + + private: + request_pimpl base_impl_; + }; + + class withdraw_pimpl: public withdraw_pskel + { + public: + withdraw_pimpl (); + + virtual void + amount (unsigned int); + + virtual withdraw* + post_withdraw (); + + private: + request_pimpl base_impl_; + unsigned int amount_; + }; +} + +#endif // PROTOCOL_PIMPL_HXX diff --git a/examples/cxx/parser/multiroot/protocol.hxx b/examples/cxx/parser/multiroot/protocol.hxx new file mode 100644 index 0000000..f076140 --- /dev/null +++ b/examples/cxx/parser/multiroot/protocol.hxx @@ -0,0 +1,62 @@ +// file : examples/cxx/parser/multiroot/protocol.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PROTOCOL_HXX +#define PROTOCOL_HXX + +namespace protocol +{ + class request + { + public: + virtual + ~request () + { + } + + unsigned int + account () const + { + return account_; + } + + protected: + request (unsigned int account) + : account_ (account) + { + } + + private: + unsigned int account_; + }; + + class balance: public request + { + public: + balance (unsigned int account) + : request (account) + { + } + }; + + class withdraw: public request + { + public: + withdraw (unsigned int account, unsigned int amount) + : request (account), amount_ (amount) + { + } + + unsigned int + amount () const + { + return amount_; + } + + private: + unsigned int amount_; + }; +} + +#endif // PROTOCOL_HXX diff --git a/examples/cxx/parser/multiroot/protocol.map b/examples/cxx/parser/multiroot/protocol.map new file mode 100644 index 0000000..43c0f21 --- /dev/null +++ b/examples/cxx/parser/multiroot/protocol.map @@ -0,0 +1,12 @@ +# file : examples/cxx/parser/multiroot/protocol.map +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : not copyrighted - public domain + +namespace http://www.codesynthesis.com/protocol protocol +{ + include "protocol.hxx"; + + request request*; + balance balance*; + withdraw withdraw*; +} diff --git a/examples/cxx/parser/multiroot/protocol.xsd b/examples/cxx/parser/multiroot/protocol.xsd new file mode 100644 index 0000000..4b29926 --- /dev/null +++ b/examples/cxx/parser/multiroot/protocol.xsd @@ -0,0 +1,51 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/multiroot/withdraw.xml b/examples/cxx/parser/multiroot/withdraw.xml new file mode 100644 index 0000000..7a80aa7 --- /dev/null +++ b/examples/cxx/parser/multiroot/withdraw.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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/parser/polymorphism/README b/examples/cxx/parser/polymorphism/README new file mode 100644 index 0000000..0b3d749 --- /dev/null +++ b/examples/cxx/parser/polymorphism/README @@ -0,0 +1,38 @@ +This example shows how to handle XML Schema polymorphism features such +as xsi:type attributes and substitution groups in the Embedded C++/Parser +mapping. The case when xsi:type or substitution groups are used on root +elements is covered in the polyroot examples. + +The example consists of the following files: + +supermen.xsd + XML Schema which describes supermen instance documents. + +supermen.xml + Sample XML instance document. + +supermen-pskel.hxx +supermen-pskel.cxx + Parser skeletons generated by the XSD/e compiler from supermen.xsd. + Note the use of the --generate-polymorphic command line option. + +supermen-pimpl-mixin.hxx +supermen-pimpl-mixin.cxx + +supermen-pimpl-tiein.hxx +supermen-pimpl-tiein.cxx + Parser implementations (using either mixin or tiein parser reuse + style) that print the XML data to STDOUT. + +driver.cxx + Driver for the example. It first constructs a parser instance from + all the individual parsers found in one of supermen-pimpl-*.hxx. It + then invokes this parser instance to parse the input file. + +To run the example on the sample XML instance document simply execute: + +$ ./driver supermen.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <supermen.xml diff --git a/examples/cxx/parser/polymorphism/driver.cxx b/examples/cxx/parser/polymorphism/driver.cxx new file mode 100644 index 0000000..907be5d --- /dev/null +++ b/examples/cxx/parser/polymorphism/driver.cxx @@ -0,0 +1,115 @@ +// file : examples/cxx/parser/polymorphism/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "supermen-pskel.hxx" // Get the configuration macros (XSDE_*). + +#if defined(XSDE_REUSE_STYLE_MIXIN) +# include "supermen-pimpl-mixin.hxx" +#elif defined(XSDE_REUSE_STYLE_TIEIN) +# include "supermen-pimpl-tiein.hxx" +#else +# error this example requires mixin or tiein parser reuse support +#endif + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ + // Check that the load in substitution and inheritance hashmaps + // is not too high. + // +#ifndef NDEBUG + float load = (float) xml_schema::parser_smap_elements (); + load /= xml_schema::parser_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_SMAP_BUCKETS" << endl; + } + +#ifdef XSDE_PARSER_VALIDATION + load = (float) xml_schema::parser_imap_elements (); + load /= xml_schema::parser_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_IMAP_BUCKETS" << endl; + } +#endif +#endif + + const char* input; + + if (argc < 2) + { + input = "STDIN"; + cerr << "XML file not specified, reading from STDIN" << endl; + } + else + input = argv[1]; + + try + { + // Construct the parser. + // + xml_schema::string_pimpl string_p; + xml_schema::boolean_pimpl boolean_p; + xml_schema::unsigned_int_pimpl unsigned_int_p; + + person_pimpl person_p; + superman_pimpl superman_p; + batman_pimpl batman_p; + + xml_schema::parser_map_impl person_map (5); // 5 hashtable buckets + supermen_pimpl supermen_p; + + + person_p.parsers (string_p); + superman_p.parsers (string_p, boolean_p); + batman_p.parsers (string_p, boolean_p, unsigned_int_p); + + // Here we are specifying several parsers that can be + // used to parse the person element. + // + person_map.insert (person_p); + person_map.insert (superman_p); + person_map.insert (batman_p); + + supermen_p.person_parser (person_map); + + // Parse the XML document. The last argument to the document's + // constructor indicates that we are parsing polymorphic XML + // documents. + // + xml_schema::document_pimpl doc_p (supermen_p, "supermen", true); + + supermen_p.pre (); + + if (argc < 2) + doc_p.parse (std::cin); + else + doc_p.parse (argv[1]); + + supermen_p.post_supermen (); + } + 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/parser/polymorphism/makefile b/examples/cxx/parser/polymorphism/makefile new file mode 100644 index 0000000..c096e5a --- /dev/null +++ b/examples/cxx/parser/polymorphism/makefile @@ -0,0 +1,71 @@ +# file : examples/cxx/parser/polymorphism/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := supermen.xsd +cxx := driver.cxx + +ifeq ($(xsde_reuse_style),mixin) +cxx += supermen-pimpl-mixin.cxx +else +cxx += supermen-pimpl-tiein.cxx +endif + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): xsde_options += --generate-polymorphic +$(skel): $(out_root)/xsde/xsde + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/polymorphism/supermen-pimpl-mixin.cxx b/examples/cxx/parser/polymorphism/supermen-pimpl-mixin.cxx new file mode 100644 index 0000000..e8fa8e4 --- /dev/null +++ b/examples/cxx/parser/polymorphism/supermen-pimpl-mixin.cxx @@ -0,0 +1,86 @@ +// file : examples/cxx/parser/polymorphism/supermen-pimpl-mixin.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain +// + +#include <iostream> + +#include "supermen-pimpl-mixin.hxx" + +using std::cout; +using std::endl; + +// person_pimpl +// +void person_pimpl:: +pre () +{ + cout << "starting to parse person" << endl; +} + +void person_pimpl:: +name (const std::string& v) +{ + cout << "name: " << v << endl; +} + +void person_pimpl:: +post_person () +{ + cout << "finished parsing person" << endl + << endl; +} + +// superman_pimpl +// +void superman_pimpl:: +pre () +{ + cout << "strarting to parse superman" << endl; +} + +void superman_pimpl:: +can_fly (bool v) +{ + cout << "can-fly: " << v << endl; +} + +void superman_pimpl:: +post_person () +{ + post_superman (); +} + +void superman_pimpl:: +post_superman () +{ + cout << "finished parsing superman" << endl + << endl; +} + +// batman_pimpl +// +void batman_pimpl:: +pre () +{ + cout << "starting to parse batman" << endl; +} + +void batman_pimpl:: +wing_span (unsigned int v) +{ + cout << "wing-span: " << v << endl; +} + +void batman_pimpl:: +post_superman () +{ + post_batman (); +} + +void batman_pimpl:: +post_batman () +{ + cout << "finished parsing batman" << endl + << endl; +} diff --git a/examples/cxx/parser/polymorphism/supermen-pimpl-mixin.hxx b/examples/cxx/parser/polymorphism/supermen-pimpl-mixin.hxx new file mode 100644 index 0000000..d07215e --- /dev/null +++ b/examples/cxx/parser/polymorphism/supermen-pimpl-mixin.hxx @@ -0,0 +1,69 @@ +// file : examples/cxx/parser/polymorphism/supermen-pimpl-mixin.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SUPERMEN_PIMPL_HXX +#define SUPERMEN_PIMPL_HXX + +#include "supermen-pskel.hxx" + +class person_pimpl: public virtual person_pskel +{ +public: + virtual void + pre (); + + virtual void + name (const std::string&); + + virtual void + post_person (); +}; + +class superman_pimpl: public virtual superman_pskel, + public person_pimpl +{ +public: + virtual void + pre (); + + virtual void + can_fly (bool); + + // By default, post_superman() calls post_person(). In case of + // polymorphic parsing we want the opposite: post_person() calls + // post_superman(). + // + virtual void + post_person (); + + virtual void + post_superman (); +}; + +class batman_pimpl: public virtual batman_pskel, + public superman_pimpl +{ +public: + virtual void + pre (); + + virtual void + wing_span (unsigned int); + + // By default, post_batman() calls post_superman(). In case of + // polymorphic parsing we want the opposite: post_superman() + // calls post_batman(). + // + virtual void + post_superman (); + + virtual void + post_batman (); +}; + +class supermen_pimpl: public virtual supermen_pskel +{ +}; + +#endif // SUPERMEN_PIMPL_HXX diff --git a/examples/cxx/parser/polymorphism/supermen-pimpl-tiein.cxx b/examples/cxx/parser/polymorphism/supermen-pimpl-tiein.cxx new file mode 100644 index 0000000..cb9ece3 --- /dev/null +++ b/examples/cxx/parser/polymorphism/supermen-pimpl-tiein.cxx @@ -0,0 +1,104 @@ +// file : examples/cxx/parser/polymorphism/supermen-pimpl-tiein.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain +// + +#include <iostream> + +#include "supermen-pimpl-tiein.hxx" + +using std::cout; +using std::endl; + +// person_pimpl +// +void person_pimpl:: +pre () +{ + cout << "starting to parse person" << endl; +} + +void person_pimpl:: +name (const std::string& v) +{ + cout << "name: " << v << endl; +} + +void person_pimpl:: +post_person () +{ + cout << "finished parsing person" << endl + << endl; +} + +// superman_pimpl +// +superman_pimpl:: +superman_pimpl () + : superman_pskel (&base_impl_) +{ +} + +void superman_pimpl:: +pre () +{ + cout << "starting to parse superman" << endl; +} + +void superman_pimpl:: +can_fly (bool v) +{ + cout << "can-fly: " << v << endl; +} + +void superman_pimpl:: +post_person () +{ + post_superman (); +} + +void superman_pimpl:: +post_superman () +{ + cout << "finished parsing superman" << endl + << endl; +} + +// batman_pimpl +// +batman_pimpl:: +batman_pimpl () + : batman_pskel (&base_impl_) +{ +} + +void batman_pimpl:: +pre () +{ + cout << "starting to parse batman" << endl; +} + +void batman_pimpl:: +wing_span (unsigned int v) +{ + cout << "wing-span: " << v << endl; +} + +void batman_pimpl:: +post_person () +{ + post_superman (); +} + +void batman_pimpl:: +post_superman () +{ + post_batman (); +} + +void batman_pimpl:: +post_batman () +{ + cout << "finished parsing batman" << endl + << endl; +} diff --git a/examples/cxx/parser/polymorphism/supermen-pimpl-tiein.hxx b/examples/cxx/parser/polymorphism/supermen-pimpl-tiein.hxx new file mode 100644 index 0000000..b8acd74 --- /dev/null +++ b/examples/cxx/parser/polymorphism/supermen-pimpl-tiein.hxx @@ -0,0 +1,81 @@ +// file : examples/cxx/parser/polymorphism/supermen-pimpl-tiein.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SUPERMEN_PIMPL_HXX +#define SUPERMEN_PIMPL_HXX + +#include "supermen-pskel.hxx" + +class person_pimpl: public person_pskel +{ +public: + virtual void + pre (); + + virtual void + name (const std::string&); + + virtual void + post_person (); +}; + +class superman_pimpl: public superman_pskel +{ +public: + superman_pimpl (); + + virtual void + pre (); + + virtual void + can_fly (bool); + + // By default, post_superman() calls post_person(). In case of + // polymorphic parsing we want the opposite: post_person() calls + // post_superman(). + // + virtual void + post_person (); + + virtual void + post_superman (); + +private: + person_pimpl base_impl_; +}; + +class batman_pimpl: public batman_pskel +{ +public: + batman_pimpl (); + + virtual void + pre (); + + virtual void + wing_span (unsigned int); + + // By default, post_batman() calls post_superman() which calls + // post_person(). In case of polymorphic parsing we want the + // opposite: post_person() calls post_superman() which calls + // post_batman(). + // + virtual void + post_person (); + + virtual void + post_superman (); + + virtual void + post_batman (); + +private: + superman_pimpl base_impl_; +}; + +class supermen_pimpl: public virtual supermen_pskel +{ +}; + +#endif // SUPERMEN_PIMPL_HXX diff --git a/examples/cxx/parser/polymorphism/supermen.xml b/examples/cxx/parser/polymorphism/supermen.xml new file mode 100644 index 0000000..2d73c44 --- /dev/null +++ b/examples/cxx/parser/polymorphism/supermen.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/polymorphism/supermen.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd"> + + <person> + <name>John Doe</name> + </person> + + <superman can-fly="false"> + <name>James "007" Bond</name> + </superman> + + <superman can-fly="true" wing-span="10" xsi:type="batman"> + <name>Bruce Wayne</name> + </superman> + +</supermen> diff --git a/examples/cxx/parser/polymorphism/supermen.xsd b/examples/cxx/parser/polymorphism/supermen.xsd new file mode 100644 index 0000000..83a7aac --- /dev/null +++ b/examples/cxx/parser/polymorphism/supermen.xsd @@ -0,0 +1,49 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/polymorphism/supermen.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:complexType name="person"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + + <!-- substitution group root --> + <xsd:element name="person" type="person"/> + + + <xsd:complexType name="superman"> + <xsd:complexContent> + <xsd:extension base="person"> + <xsd:attribute name="can-fly" type="xsd:boolean" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="superman" type="superman" substitutionGroup="person"/> + + <xsd:complexType name="batman"> + <xsd:complexContent> + <xsd:extension base="superman"> + <xsd:attribute name="wing-span" type="xsd:unsignedInt" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="supermen"> + <xsd:sequence> + <xsd:element ref="person" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="supermen" type="supermen"/> + +</xsd:schema> diff --git a/examples/cxx/parser/polyroot/README b/examples/cxx/parser/polyroot/README new file mode 100644 index 0000000..4b01b56 --- /dev/null +++ b/examples/cxx/parser/polyroot/README @@ -0,0 +1,47 @@ +This example shows how to handle the xsi:type attributes and substitution +groups when they are used on root elements. For general coverage of XML +Schema polymorphism handling in the Embedded C++/Parser mapping see the +polymorphism example. + +The example consists of the following files: + +supermen.xsd + XML Schema which describes supermen instance documents. + +person.xml +superman.xml +batman.xml + Sample XML instance documents. + +supermen-pskel.hxx +supermen-pskel.cxx + Parser skeletons generated by the XSD/e compiler from supermen.xsd. + Note the use of the --generate-polymorphic command line option. + +supermen-pimpl-mixin.hxx +supermen-pimpl-mixin.cxx + +supermen-pimpl-tiein.hxx +supermen-pimpl-tiein.cxx + Parser implementations (using either mixin or tiein parser reuse + style) that print the XML data to STDOUT. + +driver.cxx + Driver for the example. It implements a custom document parser + that determines which XML Schema type is being parsed and uses + the corresponding parser implementation. The driver first + constructs a parser instance from all the individual parsers + found in one of supermen-pimpl-*.hxx. In then invokes this parser + instance to parse the input file. + +To run the example on the sample XML instance documents simply execute: + +$ ./driver person.xml +$ ./driver superman.xml +$ ./driver batman.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver <person.xml +$ ./driver <superman.xml +$ ./driver <batman.xml diff --git a/examples/cxx/parser/polyroot/batman.xml b/examples/cxx/parser/polyroot/batman.xml new file mode 100644 index 0000000..70abdf7 --- /dev/null +++ b/examples/cxx/parser/polyroot/batman.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/polyroot/batman.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd" + xsi:type="batman" can-fly="true" wing-span="10"> + + <name>Bruce Wayne</name> + +</person> diff --git a/examples/cxx/parser/polyroot/driver.cxx b/examples/cxx/parser/polyroot/driver.cxx new file mode 100644 index 0000000..592ccfd --- /dev/null +++ b/examples/cxx/parser/polyroot/driver.cxx @@ -0,0 +1,216 @@ +// file : examples/cxx/parser/polyroot/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "supermen-pskel.hxx" // Get the configuration macros (XSDE_*). + +#if defined(XSDE_REUSE_STYLE_MIXIN) +# include "supermen-pimpl-mixin.hxx" +#elif defined(XSDE_REUSE_STYLE_TIEIN) +# include "supermen-pimpl-tiein.hxx" +#else +# error this example requires mixin or tiein parser reuse support +#endif + +using std::cerr; +using std::endl; +using xml_schema::ro_string; + +// Customize the xml_schema::document object to handle polymorphic +// root element. For more information see the multiroot example. +// +class document_pimpl: public xml_schema::document_pimpl +{ +public: + // Passing the root element name to xml_schema::document_pimpl + // constructor indicates that we are doing polymorphic parsing. + // The root element name is used to automatically translate + // substitutions to type information. + // + document_pimpl (xml_schema::parser_map& parser_map) + : xml_schema::document_pimpl ("person"), + parser_map_ (parser_map), + parser_used_ (0) + { + } + +protected: + // This function is called to obtain the root element type parser. + // If the returned pointer is 0 then the whole document content + // is ignored. The type argument contains the XML Schema type + // if xsi:type attribute or an element that substitutes the root + // was specified and 0 otherwise. + // + virtual xml_schema::parser_base* + start_root_element (const ro_string& ns, + const ro_string& name, + const char* type) + { + if (name != "person" || !ns.empty ()) + { + // If the runtime and the generated code are built with + // validation enabled then we can also set an XML Schema + // error. + // +#ifdef XSDE_PARSER_VALIDATION + context_.schema_error ( + xml_schema::parser_schema_error::unexpected_element); +#endif + return 0; + } + + // Search the parser map. If type is 0 then there is no xsi:type and + // static type should be used. + // + xml_schema::parser_base* p = parser_map_.find ( + type ? type : person_pskel::_static_type ()); + + if (p != 0) + { + // The map returns a generic parser_base which we will cast to + // person_pskel in order to call the pre() and post_person() + // callbacks. If the runtime and the generated code are built + // with the mixin parser reuse style then we have to use + // dynamic_cast because of the virtual inheritance. + // +#ifdef XSDE_REUSE_STYLE_MIXIN + parser_used_ = dynamic_cast<person_pskel*> (p); +#else + parser_used_ = static_cast<person_pskel*> (p); +#endif + parser_used_->pre (); + } + else + { + // No parser for this type. We could also make this an error + // by calling the schema_error() function as above. + // + parser_used_ = 0; + } + + return p; + } + + // This function is called to indicate the completion of document + // parsing. The parser argument contains the pointer returned by + // start_root_element. + // + virtual void + end_root_element (const ro_string& /* ns */, + const ro_string& /* name */, + xml_schema::parser_base* /* parser */) + { + // Instead of caching the current parser in parser_used_, we + // could also cast the parser argument to the person_pskel + // type. + // + if (parser_used_) + parser_used_->post_person (); + } + +public: + // If we need to be able to reset and reuse the parser after + // an error then we also need to override reset() and reset + // the parser that was used last. Note that you always need + // to call _reset() from the base. + // + virtual void + reset () + { + xml_schema::document_pimpl::reset (); + + if (parser_used_) + parser_used_->_reset (); + } + +private: + xml_schema::parser_map& parser_map_; + person_pskel* parser_used_; +}; + +int +main (int argc, char* argv[]) +{ + // Check that the load in substitution and inheritance hashmaps + // is not too high. + // +#ifndef NDEBUG + float load = (float) xml_schema::parser_smap_elements (); + load /= xml_schema::parser_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_SMAP_BUCKETS" << endl; + } + +#ifdef XSDE_PARSER_VALIDATION + load = (float) xml_schema::parser_imap_elements (); + load /= xml_schema::parser_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_IMAP_BUCKETS" << endl; + } +#endif +#endif + + const char* input; + + if (argc < 2) + { + input = "STDIN"; + cerr << "XML file not specified, reading from STDIN" << endl; + } + else + input = argv[1]; + + try + { + // Construct the parser. + // + xml_schema::string_pimpl string_p; + xml_schema::boolean_pimpl boolean_p; + xml_schema::unsigned_int_pimpl unsigned_int_p; + + person_pimpl person_p; + superman_pimpl superman_p; + batman_pimpl batman_p; + + person_p.parsers (string_p); + superman_p.parsers (string_p, boolean_p); + batman_p.parsers (string_p, boolean_p, unsigned_int_p); + + // Parse the XML document. + // + xml_schema::parser_map_impl person_map (5); // 5 hashtable buckets + + person_map.insert (person_p); + person_map.insert (superman_p); + person_map.insert (batman_p); + + document_pimpl doc_p (person_map); + + // pre() and post() will be called as part of the start_root_element() + // and end_root_element() calls. + // + if (argc < 2) + doc_p.parse (std::cin); + else + doc_p.parse (argv[1]); + } + catch (const xml_schema::parser_exception& e) + { + cerr << input << ":" << e.line () << ":" << e.column () << ": " + << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << input << ": unable to open or read failure" << endl; + return 1; + } +} diff --git a/examples/cxx/parser/polyroot/makefile b/examples/cxx/parser/polyroot/makefile new file mode 100644 index 0000000..0f4d6eb --- /dev/null +++ b/examples/cxx/parser/polyroot/makefile @@ -0,0 +1,71 @@ +# file : examples/cxx/parser/polyroot/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := supermen.xsd +cxx := driver.cxx + +ifeq ($(xsde_reuse_style),mixin) +cxx += supermen-pimpl-mixin.cxx +else +cxx += supermen-pimpl-tiein.cxx +endif + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): xsde_options += --generate-polymorphic +$(skel): $(out_root)/xsde/xsde + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/examples/cxx/parser/polyroot/person.xml b/examples/cxx/parser/polyroot/person.xml new file mode 100644 index 0000000..157a5af --- /dev/null +++ b/examples/cxx/parser/polyroot/person.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/polyroot/person.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd"> + + <name>John Doe</name> + +</person> diff --git a/examples/cxx/parser/polyroot/superman.xml b/examples/cxx/parser/polyroot/superman.xml new file mode 100644 index 0000000..0f4b89c --- /dev/null +++ b/examples/cxx/parser/polyroot/superman.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/polyroot/superman.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<superman xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd" + can-fly="false"> + + <name>James "007" Bond</name> + +</superman> diff --git a/examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx new file mode 100644 index 0000000..fb339ac --- /dev/null +++ b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx @@ -0,0 +1,83 @@ +// file : examples/cxx/parser/polyroot/supermen-pimpl-mixin.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain +// + +#include <iostream> + +#include "supermen-pimpl-mixin.hxx" + +using std::cout; +using std::endl; + +// person_pimpl +// +void person_pimpl:: +pre () +{ + cout << "starting to parse person" << endl; +} + +void person_pimpl:: +name (const std::string& v) +{ + cout << "name: " << v << endl; +} + +void person_pimpl:: +post_person () +{ + cout << "finished parsing person" << endl; +} + +// superman_pimpl +// +void superman_pimpl:: +pre () +{ + cout << "starting to parse superman" << endl; +} + +void superman_pimpl:: +can_fly (bool v) +{ + cout << "can-fly: " << v << endl; +} + +void superman_pimpl:: +post_person () +{ + post_superman (); +} + +void superman_pimpl:: +post_superman () +{ + cout << "finished parsing superman" << endl; +} + +// batman_pimpl +// +void batman_pimpl:: +pre () +{ + cout << "starting to parse batman" << endl; +} + +void batman_pimpl:: +wing_span (unsigned int v) +{ + cout << "wing-span: " << v << endl; +} + +void batman_pimpl:: +post_superman () +{ + post_batman (); +} + +void batman_pimpl:: +post_batman () +{ + cout << "finished parsing batman" << endl; +} diff --git a/examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx new file mode 100644 index 0000000..1f66062 --- /dev/null +++ b/examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx @@ -0,0 +1,65 @@ +// file : examples/cxx/parser/polyroot/supermen-pimpl-mixin.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SUPERMEN_PIMPL_HXX +#define SUPERMEN_PIMPL_HXX + +#include "supermen-pskel.hxx" + +class person_pimpl: public virtual person_pskel +{ +public: + virtual void + pre (); + + virtual void + name (const std::string&); + + virtual void + post_person (); +}; + +class superman_pimpl: public virtual superman_pskel, + public person_pimpl +{ +public: + virtual void + pre (); + + virtual void + can_fly (bool); + + // By default, post_superman() calls post_person(). In case of + // polymorphic parsing we want the opposite: post_person() calls + // post_superman(). + // + virtual void + post_person (); + + virtual void + post_superman (); +}; + +class batman_pimpl: public virtual batman_pskel, + public superman_pimpl +{ +public: + virtual void + pre (); + + virtual void + wing_span (unsigned int); + + // By default, post_batman() calls post_superman(). In case of + // polymorphic parsing we want the opposite: post_superman() + // calls post_batman(). + // + virtual void + post_superman (); + + virtual void + post_batman (); +}; + +#endif // SUPERMEN_PIMPL_HXX diff --git a/examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx new file mode 100644 index 0000000..b02eeef --- /dev/null +++ b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx @@ -0,0 +1,101 @@ +// file : examples/cxx/parser/polyroot/supermen-pimpl-tiein.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain +// + +#include <iostream> + +#include "supermen-pimpl-tiein.hxx" + +using std::cout; +using std::endl; + +// person_pimpl +// +void person_pimpl:: +pre () +{ + cout << "starting to parse person" << endl; +} + +void person_pimpl:: +name (const std::string& v) +{ + cout << "name: " << v << endl; +} + +void person_pimpl:: +post_person () +{ + cout << "finished parsing person" << endl; +} + +// superman_pimpl +// +superman_pimpl:: +superman_pimpl () + : superman_pskel (&base_impl_) +{ +} + +void superman_pimpl:: +pre () +{ + cout << "starting to parse superman" << endl; +} + +void superman_pimpl:: +can_fly (bool v) +{ + cout << "can-fly: " << v << endl; +} + +void superman_pimpl:: +post_person () +{ + post_superman (); +} + +void superman_pimpl:: +post_superman () +{ + cout << "finished parsing superman" << endl; +} + +// batman_pimpl +// +batman_pimpl:: +batman_pimpl () + : batman_pskel (&base_impl_) +{ +} + +void batman_pimpl:: +pre () +{ + cout << "starting to parse batman" << endl; +} + +void batman_pimpl:: +wing_span (unsigned int v) +{ + cout << "wing-span: " << v << endl; +} + +void batman_pimpl:: +post_person () +{ + post_superman (); +} + +void batman_pimpl:: +post_superman () +{ + post_batman (); +} + +void batman_pimpl:: +post_batman () +{ + cout << "finished parsing batman" << endl; +} diff --git a/examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx new file mode 100644 index 0000000..41dfe84 --- /dev/null +++ b/examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx @@ -0,0 +1,77 @@ +// file : examples/cxx/parser/polyroot/supermen-pimpl-tiein.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SUPERMEN_PIMPL_HXX +#define SUPERMEN_PIMPL_HXX + +#include "supermen-pskel.hxx" + +class person_pimpl: public person_pskel +{ +public: + virtual void + pre (); + + virtual void + name (const std::string&); + + virtual void + post_person (); +}; + +class superman_pimpl: public superman_pskel +{ +public: + superman_pimpl (); + + virtual void + pre (); + + virtual void + can_fly (bool); + + // By default, post_superman() calls post_person(). In case of + // polymorphic parsing we want the opposite: post_person() calls + // post_superman(). + // + virtual void + post_person (); + + virtual void + post_superman (); + +private: + person_pimpl base_impl_; +}; + +class batman_pimpl: public batman_pskel +{ +public: + batman_pimpl (); + + virtual void + pre (); + + virtual void + wing_span (unsigned int); + + // By default, post_batman() calls post_superman() which calls + // post_person(). In case of polymorphic parsing we want the + // opposite: post_person() calls post_superman() which calls + // post_batman(). + // + virtual void + post_person (); + + virtual void + post_superman (); + + virtual void + post_batman (); + +private: + superman_pimpl base_impl_; +}; + +#endif // SUPERMEN_PIMPL_HXX diff --git a/examples/cxx/parser/polyroot/supermen.xsd b/examples/cxx/parser/polyroot/supermen.xsd new file mode 100644 index 0000000..722d59b --- /dev/null +++ b/examples/cxx/parser/polyroot/supermen.xsd @@ -0,0 +1,40 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/polyroot/supermen.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:complexType name="person"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + + <!-- substitution group root --> + <xsd:element name="person" type="person"/> + + <xsd:complexType name="superman"> + <xsd:complexContent> + <xsd:extension base="person"> + <xsd:attribute name="can-fly" type="xsd:boolean" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="superman" type="superman" substitutionGroup="person"/> + + <xsd:complexType name="batman"> + <xsd:complexContent> + <xsd:extension base="superman"> + <xsd:attribute name="wing-span" type="xsd:unsignedInt" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + +</xsd:schema> diff --git a/examples/cxx/parser/wildcard/README b/examples/cxx/parser/wildcard/README new file mode 100644 index 0000000..d978ddc --- /dev/null +++ b/examples/cxx/parser/wildcard/README @@ -0,0 +1,33 @@ +This example shows how to parse XML data matched by XML Schema +wildcards (any and anyAttribute) using the Embedded C++/Parser +mapping. + +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-pskel.hxx +email-pskel.cxx + Parser skeletons generated by XSD/e from email.xsd. + +driver.cxx + Parser implementations and a driver for the example. The + parser implementations simply print the data to STDERR. + The driver first constructs parser instances from the + parser implementations mentioned above and a couple of + predefined parsers for the XML Schema built-in types. + In then invokes the parser instances to parse the input + file. + +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/parser/wildcard/driver.cxx b/examples/cxx/parser/wildcard/driver.cxx new file mode 100644 index 0000000..aed2560 --- /dev/null +++ b/examples/cxx/parser/wildcard/driver.cxx @@ -0,0 +1,359 @@ +// file : examples/cxx/parser/wildcard/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <string> +#include <memory> +#include <iostream> + +#include "email-pskel.hxx" + +#ifndef XSDE_REUSE_STYLE_TIEIN +# error this example requires the tiein parser reuse support +#endif + +using namespace std; +using xml_schema::ro_string; + +namespace email +{ + class binary_pimpl: public binary_pskel + { + public: + binary_pimpl () + : binary_pskel (&base_impl_) + { + } + + virtual void + name (const string& n) + { + cerr << "binary: " << n << endl; + } + + virtual void + mime (const string& t) + { + cerr << "type: " << t << endl; + } + + virtual void + post_binary () + { + std::auto_ptr<xml_schema::buffer> buf (post_base64_binary ()); + + cerr << "size: " << buf->size () << endl + << endl; + } + + private: + xml_schema::base64_binary_pimpl base_impl_; + }; + + class envelope_pimpl: public envelope_pskel + { + public: + envelope_pimpl (xml_schema::unsigned_int_pskel& uint_p, + xml_schema::string_pskel& string_p, + binary_pskel& binary_p) + : depth_ (0), + uint_p_ (uint_p), string_p_ (string_p), binary_p_ (binary_p) + { + } + + virtual void + to (const string& addr) + { + cerr << "To: " << addr << endl; + } + + virtual void + from (const string& addr) + { + cerr << "From: " << addr << endl; + } + + virtual void + subject (const string& s) + { + cerr << "Subject: " << s << endl; + } + + // Wildcard handling. 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(), clean up, etc. + // + // If we are not using exceptions or XML Schema validation + // is enabled then we need to check for the error condition + // and, if the (user) error was set in pre() or post(), + // also copy the error code to the context. The _error_type() + // function returns non-0 value if there an error pending. + // The _copy_error() functions copies the error state to + // the context. + // + // Finally, 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. + // + virtual void +#ifndef XSDE_POLYMORPHIC + _start_any_element (const ro_string& ns, const ro_string& name) +#else + _start_any_element (const ro_string& ns, + const 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 = &string_p_; + } + else if (name == "binary") + { + p = &binary_p_; + } + + if (p != 0) + { + xml_schema::parser_context& ctx = _context (); + + p->pre (); + +#ifndef XSDE_EXCEPTIONS + if (p->_error_type ()) + { + // Propagate the error. + // + p->_copy_error (ctx); + return; + } +#endif + p->_pre_impl (ctx); + } + } + + if (p == 0) + { + cerr << "Unknown wildcard content: " << ns << "#" << name << endl; + } + } + } + + virtual void + _end_any_element (const ro_string& ns, const ro_string& name) + { + if (--depth_ == 0) + { + if (ns == "http://www.codesynthesis.com/email") + { + if (name == "text") + { + // Note that we don't call _post_impl() (corresponding to + // _pre_impl()) here. It is called automatically by the + // infrastructure. + // + + string text (string_p_.post_string ()); + +#ifndef XSDE_EXCEPTIONS + if (string_p_._error_type ()) + { + // Propagate the error. + // + string_p_._copy_error (_context ()); + return; + } +#endif + cerr << text << endl + << endl; + } + else if (name == "binary") + { + // Note that we don't call _post_impl() (corresponding to + // _pre_impl()) here. It is called automatically by the + // infrastructure. + // + + binary_p_.post_binary (); + +#ifndef XSDE_EXCEPTIONS + if (binary_p_._error_type ()) + { + // Propagate the error. + // + binary_p_._copy_error (_context ()); + return; + } +#endif + } + } + } + } + + virtual void + _any_attribute (const ro_string& ns, + const ro_string& name, + const ro_string& value) + { + if (depth_ == 0) + { + // Top-level (relative to this type) attribute matched by the + // anyAttribute wildcard. + // + if (ns == "http://www.codesynthesis.com/email" && name == "thread-id") + { + xml_schema::parser_context& ctx = _context (); + + uint_p_.pre (); + +#ifndef XSDE_EXCEPTIONS + if (uint_p_._error_type ()) + { + uint_p_._copy_error (ctx); + return; + } +#endif + + uint_p_._pre_impl (ctx); + +#if defined(XSDE_PARSER_VALIDATION) || !defined(XSDE_EXCEPTIONS) + if (ctx.error_type ()) + return; +#endif + + uint_p_._characters (value); + +#if defined(XSDE_PARSER_VALIDATION) || !defined(XSDE_EXCEPTIONS) + if (ctx.error_type ()) + return; +#endif + + uint_p_._post_impl (); + +#if defined(XSDE_PARSER_VALIDATION) || !defined(XSDE_EXCEPTIONS) + if (ctx.error_type ()) + return; +#endif + + unsigned int tid = uint_p_.post_unsigned_int (); + +#ifndef XSDE_EXCEPTIONS + if (uint_p_._error_type ()) + { + uint_p_._copy_error (ctx); + return; + } +#endif + + cerr << "Thread-id: " << tid << endl; + } + } + } + + // 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. Note that + // you always need to call _reset() from the base. + // + virtual void + _reset () + { + envelope_pskel::_reset (); + + depth_ = 0; + uint_p_._reset (); + string_p_._reset (); + binary_p_._reset (); + } + + private: + std::size_t depth_; + + // Parsers for the unsigned int, string and binary types. + // + private: + xml_schema::unsigned_int_pskel& uint_p_; + xml_schema::string_pskel& string_p_; + binary_pskel& binary_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 + { + // Construct the parser. + // + xml_schema::unsigned_int_pimpl unsigned_int_p; + xml_schema::string_pimpl string_p; + email::binary_pimpl binary_p; + email::envelope_pimpl envelope_p (unsigned_int_p, string_p, binary_p); + + binary_p.parsers (string_p, // name + string_p); // mime + + envelope_p.parsers (string_p, // to + string_p, // from + string_p); // subject + + // Parse the XML instance document. + // + xml_schema::document_pimpl doc_p ( + envelope_p, + "http://www.codesynthesis.com/email", + "message"); + + envelope_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + envelope_p.post_envelope (); + } + 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/parser/wildcard/email.xml b/examples/cxx/parser/wildcard/email.xml new file mode 100644 index 0000000..55f1e4b --- /dev/null +++ b/examples/cxx/parser/wildcard/email.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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" + eml:thread-id="123456789"> + + <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/parser/wildcard/email.xsd b/examples/cxx/parser/wildcard/email.xsd new file mode 100644 index 0000000..2e1f660 --- /dev/null +++ b/examples/cxx/parser/wildcard/email.xsd @@ -0,0 +1,51 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/parser/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"/> + + <!-- Predefined envelop attributes. --> + + <xsd:attribute name="thread-id" type="xsd:unsignedInt"/> + + + <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:anyAttribute namespace="##targetNamespace" processContents="strict"/> + </xsd:complexType> + + <xsd:element name="message" type="eml:envelope"/> + +</xsd:schema> diff --git a/examples/cxx/parser/wildcard/makefile b/examples/cxx/parser/wildcard/makefile new file mode 100644 index 0000000..8613847 --- /dev/null +++ b/examples/cxx/parser/wildcard/makefile @@ -0,0 +1,64 @@ +# file : examples/cxx/parser/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 + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): cpp_options := -I$(out_base) +$(obj) $(dep): $(xsde.l.cpp-options) + +skel := $(out_base)/$(xsd:.xsd=-pskel.hxx) \ + $(out_base)/$(xsd:.xsd=-pskel.ixx) \ + $(out_base)/$(xsd:.xsd=-pskel.cxx) + +$(skel): xsde := $(out_root)/xsde/xsde +$(skel): $(out_root)/xsde/xsde + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) |