diff options
Diffstat (limited to 'xsd/examples')
257 files changed, 19044 insertions, 0 deletions
diff --git a/xsd/examples/cxx/parser/README b/xsd/examples/cxx/parser/README new file mode 100644 index 0000000..01906c7 --- /dev/null +++ b/xsd/examples/cxx/parser/README @@ -0,0 +1,45 @@ +This directory contains a number of examples that show how to use +the 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 compiler. + +library +  Shows how to handle more complex data structures and construct +  a custom in-memory object model. + +mixin +  Shows how to reuse implementations of base parsers in derived +  parsers using the mixin C++ idiom. + +wildcard +  Shows how to parse the XML data matched by XML Schema wildcards +  (any and anyAttribute). + +multiroot +  Shows how to handle XML vocabularies with multiple root elements. + +polymorphism +  Shows how to use XML Schema polymorphism features such as the +  xsi:type attribute and substitution groups. + +polyroot +  Shows how to handle the xsi:type attribute when it is used on root +  elements. + +performance +  Measures the performance of XML parsing. This example also shows how +  to structure your code to achieve the maximum performance for this +  operation. + +mixed +  Shows how to handle raw, "type-less content" such as mixed content +  models, anyType/anySimpleType, and any/anyAttribute.
\ No newline at end of file diff --git a/xsd/examples/cxx/parser/generated/README b/xsd/examples/cxx/parser/generated/README new file mode 100644 index 0000000..ca56974 --- /dev/null +++ b/xsd/examples/cxx/parser/generated/README @@ -0,0 +1,32 @@ +This example shows how to use the sample implementation and test +driver generation feature of the C++/Parser mapping. This example +does not have any hand-written C++ code; everything is generated +by the XSD 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 from library.xsd. + +library-pimpl.hxx +library-pimpl.cxx +  Sample parser implementations that print the XML data to STDOUT. +  These are generated by XSD from library.xsd with the +  --generate-print-impl option. + +library-driver.cxx +  Sample driver for the example. It is generated by XSD from +  library.xsd with the --generate-test-driver option. + + +To run the example on the sample XML instance document simply +execute: + +$ ./library-driver library.xml diff --git a/xsd/examples/cxx/parser/generated/library.xml b/xsd/examples/cxx/parser/generated/library.xml new file mode 100644 index 0000000..b1ac98c --- /dev/null +++ b/xsd/examples/cxx/parser/generated/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/library/library.xml +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/xsd/examples/cxx/parser/generated/library.xsd b/xsd/examples/cxx/parser/generated/library.xsd new file mode 100644 index 0000000..71e4005 --- /dev/null +++ b/xsd/examples/cxx/parser/generated/library.xsd @@ -0,0 +1,78 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/library/library.xsd +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/xsd/examples/cxx/parser/generated/makefile b/xsd/examples/cxx/parser/generated/makefile new file mode 100644 index 0000000..78a60fe --- /dev/null +++ b/xsd/examples/cxx/parser/generated/makefile @@ -0,0 +1,110 @@ +# file      : examples/cxx/parser/generated/makefile +# copyright : Copyright (c) 2006-2014 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=-driver.o)) +dep := $(obj:.o=.o.d) + + +driver   := $(out_base)/$(xsd:.xsd=-driver) +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx)  \ +        $(xsd:.xsd=-pskel.ixx)  \ +        $(xsd:.xsd=-pskel.cxx)  \ +        $(xsd:.xsd=-pimpl.hxx)  \ +	$(xsd:.xsd=-pimpl.cxx)  \ +	$(xsd:.xsd=-driver.cxx) + +gen  := $(addprefix $(out_base)/,$(genf)) + + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-print-impl --generate-test-driver \ +--force-overwrite +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) + +$(dist-common): +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# 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)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := $(xsd:.xsd=-driver) $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) + +xsd_parser_impl_suffix := -pimpl +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/hello/README b/xsd/examples/cxx/parser/hello/README new file mode 100644 index 0000000..97449de --- /dev/null +++ b/xsd/examples/cxx/parser/hello/README @@ -0,0 +1,28 @@ +This is a "Hello, world!" example that shows how to use the +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.cxx +  Parser skeletons generated by XSD from hello.xsd. + +driver.cxx +  A parser implementation and a driver for the example. The +  parser implementation simply prints the data 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 diff --git a/xsd/examples/cxx/parser/hello/driver.cxx b/xsd/examples/cxx/parser/hello/driver.cxx new file mode 100644 index 0000000..e261e10 --- /dev/null +++ b/xsd/examples/cxx/parser/hello/driver.cxx @@ -0,0 +1,67 @@ +// file      : examples/cxx/parser/hello/driver.cxx +// 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[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " hello.xml" << endl; +    return 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 doc_p (hello_p, "hello"); + +    hello_p.pre (); +    doc_p.parse (argv[1]); +    hello_p.post_hello (); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/hello/hello.xml b/xsd/examples/cxx/parser/hello/hello.xml new file mode 100644 index 0000000..dd0c13d --- /dev/null +++ b/xsd/examples/cxx/parser/hello/hello.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/hello/hello.xml +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/xsd/examples/cxx/parser/hello/hello.xsd b/xsd/examples/cxx/parser/hello/hello.xsd new file mode 100644 index 0000000..be69957 --- /dev/null +++ b/xsd/examples/cxx/parser/hello/hello.xsd @@ -0,0 +1,21 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/hello/hello.xsd +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/xsd/examples/cxx/parser/hello/makefile b/xsd/examples/cxx/parser/hello/makefile new file mode 100644 index 0000000..ccf0257 --- /dev/null +++ b/xsd/examples/cxx/parser/hello/makefile @@ -0,0 +1,101 @@ +# file      : examples/cxx/parser/hello/makefile +# copyright : Copyright (c) 2005-2014 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) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/hello.xsd,$(install_doc_dir)/xsd/$(path)/hello.xsd) +	$(call install-data,$(src_base)/hello.xml,$(install_doc_dir)/xsd/$(path)/hello.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/hello.xsd,$(dist_prefix)/$(path)/hello.xsd) +	$(call install-data,$(src_base)/hello.xml,$(dist_prefix)/$(path)/hello.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/library/README b/xsd/examples/cxx/parser/library/README new file mode 100644 index 0000000..3f515f6 --- /dev/null +++ b/xsd/examples/cxx/parser/library/README @@ -0,0 +1,44 @@ +This example shows how to use the 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 the C++ types defined in library.hxx. + +library-pskel.hxx +library-pskel.ixx +library-pskel.cxx +  Parser skeletons generated by XSD from library.xsd and +  library.map. + +library-pimpl.hxx +library-pimpl.cxx +  Parser implementations that construct the custom in-memory +  object model from an XML instance using the 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 +  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 contents of the +  in-memory object model to STDERR. + +To run the example on the sample XML instance document simply +execute: + +$ ./driver library.xml diff --git a/xsd/examples/cxx/parser/library/driver.cxx b/xsd/examples/cxx/parser/library/driver.cxx new file mode 100644 index 0000000..3b63801 --- /dev/null +++ b/xsd/examples/cxx/parser/library/driver.cxx @@ -0,0 +1,109 @@ +// file      : examples/cxx/parser/library/driver.cxx +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "library.hxx" +#include "library-pimpl.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml" << endl; +    return 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 (isbn_p,    // isbn +                    title_p,   // title +                    genre_p,   // genre +                    author_p,  // author +                    boolean_p, // available +                    id_p);     // id + +    catalog_pimpl catalog_p; +    catalog_p.book_parser (book_p); + + +    // Parse the XML instance document. +    // +    xml_schema::document doc_p ( +      catalog_p, +      "http://www.codesynthesis.com/library", // root element namespace +      "catalog");                             // root element name + +    catalog_p.pre (); +    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::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/library/library-pimpl.cxx b/xsd/examples/cxx/parser/library/library-pimpl.cxx new file mode 100644 index 0000000..7a1e484 --- /dev/null +++ b/xsd/examples/cxx/parser/library/library-pimpl.cxx @@ -0,0 +1,183 @@ +// file      : examples/cxx/parser/library/library-pimpl.cxx +// copyright : not copyrighted - public domain + +#include "library-pimpl.hxx" + +namespace library +{ +  // isbn_impl +  // +  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 () +  { +    person_pimpl::_pre (); +    author_.recommends (""); +  } + +  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/xsd/examples/cxx/parser/library/library-pimpl.hxx b/xsd/examples/cxx/parser/library/library-pimpl.hxx new file mode 100644 index 0000000..5d0dcc1 --- /dev/null +++ b/xsd/examples/cxx/parser/library/library-pimpl.hxx @@ -0,0 +1,135 @@ +// file      : examples/cxx/parser/library/library-pimpl.hxx +// 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, xml_schema::unsigned_int_pimpl +  { +    virtual isbn +    post_isbn (); +  }; + +  // +  // +  struct title_pimpl: 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: 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: author_pskel, person_pimpl +  { +    virtual void +    _pre (); + +    virtual void +    recommends (const std::string&); + +    virtual author +    post_author (); + +  private: +    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/xsd/examples/cxx/parser/library/library.hxx b/xsd/examples/cxx/parser/library/library.hxx new file mode 100644 index 0000000..552e7a5 --- /dev/null +++ b/xsd/examples/cxx/parser/library/library.hxx @@ -0,0 +1,241 @@ +// file      : examples/cxx/parser/library/library.hxx +// 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/xsd/examples/cxx/parser/library/library.map b/xsd/examples/cxx/parser/library/library.map new file mode 100644 index 0000000..3a49b49 --- /dev/null +++ b/xsd/examples/cxx/parser/library/library.map @@ -0,0 +1,15 @@ +# file      : examples/cxx/parser/library/library.map +# 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/xsd/examples/cxx/parser/library/library.xml b/xsd/examples/cxx/parser/library/library.xml new file mode 100644 index 0000000..b1ac98c --- /dev/null +++ b/xsd/examples/cxx/parser/library/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/library/library.xml +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/xsd/examples/cxx/parser/library/library.xsd b/xsd/examples/cxx/parser/library/library.xsd new file mode 100644 index 0000000..71e4005 --- /dev/null +++ b/xsd/examples/cxx/parser/library/library.xsd @@ -0,0 +1,78 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/library/library.xsd +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/xsd/examples/cxx/parser/library/makefile b/xsd/examples/cxx/parser/library/makefile new file mode 100644 index 0000000..6410cf3 --- /dev/null +++ b/xsd/examples/cxx/parser/library/makefile @@ -0,0 +1,110 @@ +# file      : examples/cxx/parser/library/makefile +# copyright : Copyright (c) 2005-2014 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 library-pimpl.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-inline --type-map $(src_base)/library.map +$(gen): $(out_root)/xsd/xsd $(src_base)/library.map + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) +	$(call install-data,$(src_base)/library.map,$(install_doc_dir)/xsd/$(path)/library.map) +	$(call install-data,$(src_base)/library.hxx,$(install_doc_dir)/xsd/$(path)/library.hxx) +	$(call install-data,$(src_base)/library-pimpl.hxx,$(install_doc_dir)/xsd/$(path)/library-pimpl.hxx) +	$(call install-data,$(src_base)/library-pimpl.cxx,$(install_doc_dir)/xsd/$(path)/library-pimpl.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) +	$(call install-data,$(src_base)/library.map,$(dist_prefix)/$(path)/library.map) +	$(call install-data,$(src_base)/library.hxx,$(dist_prefix)/$(path)/library.hxx) +	$(call install-data,$(src_base)/library-pimpl.hxx,$(dist_prefix)/$(path)/library-pimpl.hxx) +	$(call install-data,$(src_base)/library-pimpl.cxx,$(dist_prefix)/$(path)/library-pimpl.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/makefile b/xsd/examples/cxx/parser/makefile new file mode 100644 index 0000000..4744b29 --- /dev/null +++ b/xsd/examples/cxx/parser/makefile @@ -0,0 +1,56 @@ +# file      : examples/cxx/parser/makefile +# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make + +examples := generated hello library mixin mixed multiroot performance \ +polymorphism polyroot wildcard + +default  := $(out_base)/ +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Build +# +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(examples))) + + +# Install & Dist. +# +$(install) $(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base)) + +$(install): $(addprefix $(out_base)/,$(addsuffix /.install,$(examples))) +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) + +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): export dirs := $(examples) +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,parser-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,parser-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,parser-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,parser-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,parser-vc12.sln) +	$(call meta-vctest,parser-vc8.sln,$(src_root)/dist/examples/test.bat,test.bat) + +# Clean +# +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(examples))) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) +$(call include,$(bld_root)/meta/vctest.make) + + +$(foreach e,$(examples),$(call import,$(src_base)/$e/makefile)) diff --git a/xsd/examples/cxx/parser/mixed/README b/xsd/examples/cxx/parser/mixed/README new file mode 100644 index 0000000..23ace6f --- /dev/null +++ b/xsd/examples/cxx/parser/mixed/README @@ -0,0 +1,49 @@ +This example shows how to handle raw, "type-less content" such as +mixed content models, anyType/anySimpleType, and any/anyAttribute +in the 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.cxx +  Parser skeletons generated by XSD 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 diff --git a/xsd/examples/cxx/parser/mixed/anchor.hxx b/xsd/examples/cxx/parser/mixed/anchor.hxx new file mode 100644 index 0000000..3adc90b --- /dev/null +++ b/xsd/examples/cxx/parser/mixed/anchor.hxx @@ -0,0 +1,33 @@ +// file      : examples/cxx/parser/mixed/anchor.hxx +// 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/xsd/examples/cxx/parser/mixed/driver.cxx b/xsd/examples/cxx/parser/mixed/driver.cxx new file mode 100644 index 0000000..3f3cc65 --- /dev/null +++ b/xsd/examples/cxx/parser/mixed/driver.cxx @@ -0,0 +1,100 @@ +// file      : examples/cxx/parser/mixed/driver.cxx +// copyright : not copyrighted - public domain + +#include <string> +#include <vector> +#include <iostream> + +#include "anchor.hxx" +#include "text-pskel.hxx" + +using namespace std; + +struct anchor_pimpl: anchor_pskel, xml_schema::string_pimpl +{ +  virtual void +  href (const std::string& uri) +  { +    uri_ = uri; +  } + +  virtual anchor +  post_anchor () +  { +    return anchor (post_string (), uri_); +  } + +private: +  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[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " text.xml" << endl; +    return 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 doc_p (text_p, "text"); + +    text_p.pre (); +    doc_p.parse (argv[1]); +    text_p.post_text (); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/mixed/makefile b/xsd/examples/cxx/parser/mixed/makefile new file mode 100644 index 0000000..acf8aed --- /dev/null +++ b/xsd/examples/cxx/parser/mixed/makefile @@ -0,0 +1,107 @@ +# file      : examples/cxx/parser/mixed/makefile +# copyright : Copyright (c) 2005-2014 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) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --type-map $(src_base)/text.map +$(gen): $(out_root)/xsd/xsd $(src_base)/text.map + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/text.xsd,$(install_doc_dir)/xsd/$(path)/text.xsd) +	$(call install-data,$(src_base)/text.xml,$(install_doc_dir)/xsd/$(path)/text.xml) +	$(call install-data,$(src_base)/text.map,$(install_doc_dir)/xsd/$(path)/text.map) +	$(call install-data,$(src_base)/anchor.hxx,$(install_doc_dir)/xsd/$(path)/anchor.hxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/text.xsd,$(dist_prefix)/$(path)/text.xsd) +	$(call install-data,$(src_base)/text.xml,$(dist_prefix)/$(path)/text.xml) +	$(call install-data,$(src_base)/text.map,$(dist_prefix)/$(path)/text.map) +	$(call install-data,$(src_base)/anchor.hxx,$(dist_prefix)/$(path)/anchor.hxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/mixed/text.map b/xsd/examples/cxx/parser/mixed/text.map new file mode 100644 index 0000000..85971c4 --- /dev/null +++ b/xsd/examples/cxx/parser/mixed/text.map @@ -0,0 +1,6 @@ +# file      : examples/cxx/parser/mixed/text.map +# copyright : not copyrighted - public domain + +include "anchor.hxx"; + +anchor ::anchor; diff --git a/xsd/examples/cxx/parser/mixed/text.xml b/xsd/examples/cxx/parser/mixed/text.xml new file mode 100644 index 0000000..bfdc881 --- /dev/null +++ b/xsd/examples/cxx/parser/mixed/text.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/text/text.xml +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/xsd/examples/cxx/parser/mixed/text.xsd b/xsd/examples/cxx/parser/mixed/text.xsd new file mode 100644 index 0000000..92e300c --- /dev/null +++ b/xsd/examples/cxx/parser/mixed/text.xsd @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/mixed/text.xsd +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/xsd/examples/cxx/parser/mixin/README b/xsd/examples/cxx/parser/mixin/README new file mode 100644 index 0000000..343e379 --- /dev/null +++ b/xsd/examples/cxx/parser/mixin/README @@ -0,0 +1,34 @@ +This example shows how to reuse implementations of base parsers +in derived parsers using the mixin C++ idiom. + +The example consists of the following files: + +schema.xsd +  XML Schema which defined two data types: base and +  derived. + +instance.xml +  Sample XML instance document. + +types.hxx +  C++ classes that correspond to the base and derived +  types in schema.xsd. + +schema.map +  Type map. It maps XML Schema types defined in schema.xsd +  to C++ types defined in types.hxx. + +schema-pskel.hxx +schema-pskel.cxx +  Parser skeletons generated by XSD from schema.xsd and +  schema.map. + +driver.cxx +  Parser implementations and a driver for the example. It +  shows how to mix the implementation of the base parser +  into the derived parser. + +To run the example on the sample XML instance document simply +execute: + +$ ./driver instance.xml diff --git a/xsd/examples/cxx/parser/mixin/driver.cxx b/xsd/examples/cxx/parser/mixin/driver.cxx new file mode 100644 index 0000000..04466a1 --- /dev/null +++ b/xsd/examples/cxx/parser/mixin/driver.cxx @@ -0,0 +1,103 @@ +// file      : examples/cxx/parser/mixin/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory> +#include <iostream> + +#include "types.hxx" +#include "schema-pskel.hxx" + +using namespace std; + +struct base_pimpl: virtual base_pskel +{ +  virtual void +  pre () +  { +    base_.reset (new ::base); +  } + +  virtual void +  a (bool v) +  { +    base_->a (v); +  } + +  virtual base* +  post_base () +  { +    return base_.release (); +  } + +protected: +  auto_ptr<base> base_; +}; + +// Implement derived parser by mixing-in base's implementation. +// +struct derived_pimpl: derived_pskel, base_pimpl +{ +  virtual void +  pre () +  { +    // Override base's pre() with the new implementation that +    // instantiates derived instead of base. +    // +    base_.reset (new ::derived); +  } + +  virtual void +  b (int v) +  { +    // We could also store a pointer to derived in derived_impl to +    // avoid casting. +    // +    static_cast< ::derived* > (base_.get ())->b (v); +  } + +  virtual derived* +  post_derived () +  { +    return static_cast<derived*> (base_.release ()); +  } +}; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " instance.xml" << endl; +    return 1; +  } + +  try +  { +    // Construct the parser. +    // +    xml_schema::boolean_pimpl bool_p; +    xml_schema::int_pimpl int_p; +    derived_pimpl derived_p; + +    derived_p.parsers (bool_p, int_p); + +    xml_schema::document doc_p (derived_p, "root"); + +    derived_p.pre (); +    doc_p.parse (argv[1]); +    auto_ptr<derived> d (derived_p.post_derived ()); + +    cerr << "a: " << boolalpha << d->a () << endl; +    cerr << "b: " << d->b () << endl; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/mixin/instance.xml b/xsd/examples/cxx/parser/mixin/instance.xml new file mode 100644 index 0000000..253f348 --- /dev/null +++ b/xsd/examples/cxx/parser/mixin/instance.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/mixin/instance.xml +copyright : not copyrighted - public domain + +--> + +<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +      xsi:noNamespaceSchemaLocation="schema.xsd"> + +  <a>true</a> +  <b>1</b> + +</root> diff --git a/xsd/examples/cxx/parser/mixin/makefile b/xsd/examples/cxx/parser/mixin/makefile new file mode 100644 index 0000000..7ef8084 --- /dev/null +++ b/xsd/examples/cxx/parser/mixin/makefile @@ -0,0 +1,107 @@ +# file      : examples/cxx/parser/mixin/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := schema.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --type-map $(src_base)/schema.map +$(gen): $(out_root)/xsd/xsd $(src_base)/schema.map + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/schema.xsd,$(install_doc_dir)/xsd/$(path)/schema.xsd) +	$(call install-data,$(src_base)/instance.xml,$(install_doc_dir)/xsd/$(path)/instance.xml) +	$(call install-data,$(src_base)/schema.map,$(install_doc_dir)/xsd/$(path)/schema.map) +	$(call install-data,$(src_base)/types.hxx,$(install_doc_dir)/xsd/$(path)/types.hxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/schema.xsd,$(dist_prefix)/$(path)/schema.xsd) +	$(call install-data,$(src_base)/instance.xml,$(dist_prefix)/$(path)/instance.xml) +	$(call install-data,$(src_base)/schema.map,$(dist_prefix)/$(path)/schema.map) +	$(call install-data,$(src_base)/types.hxx,$(dist_prefix)/$(path)/types.hxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/mixin/schema.map b/xsd/examples/cxx/parser/mixin/schema.map new file mode 100644 index 0000000..a93c881 --- /dev/null +++ b/xsd/examples/cxx/parser/mixin/schema.map @@ -0,0 +1,7 @@ +# file      : examples/cxx/parser/mixin/schema.map +# copyright : not copyrighted - public domain + +include "types.hxx"; + +base ::base*; +derived ::derived*; diff --git a/xsd/examples/cxx/parser/mixin/schema.xsd b/xsd/examples/cxx/parser/mixin/schema.xsd new file mode 100644 index 0000000..d2d195d --- /dev/null +++ b/xsd/examples/cxx/parser/mixin/schema.xsd @@ -0,0 +1,30 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/mixin/schema.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + +  <xsd:complexType name="base"> +    <xsd:sequence> +      <xsd:element name="a" type="xsd:boolean"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="derived"> +    <xsd:complexContent> +      <xsd:extension base="base"> +        <xsd:sequence> +          <xsd:element name="b" type="xsd:int"/> +        </xsd:sequence> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:element name="root" type="derived"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/parser/mixin/types.hxx b/xsd/examples/cxx/parser/mixin/types.hxx new file mode 100644 index 0000000..930033d --- /dev/null +++ b/xsd/examples/cxx/parser/mixin/types.hxx @@ -0,0 +1,43 @@ +// file      : examples/cxx/parser/mixin/types.hxx +// copyright : not copyrighted - public domain + +#ifndef TYPES_HXX +#define TYPES_HXX + +struct base +{ +  bool +  a () const +  { +    return a_; +  } + +  void +  a (bool v) +  { +    a_ = v; +  } + +private: +  bool a_; +}; + +struct derived: base +{ +  int +  b () const +  { +    return b_; +  } + +  void +  b (int v) +  { +    b_ = v; +  } + +private: +  int b_; +}; + +#endif // TYPES_HXX diff --git a/xsd/examples/cxx/parser/multiroot/README b/xsd/examples/cxx/parser/multiroot/README new file mode 100644 index 0000000..041dfec --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/README @@ -0,0 +1,51 @@ +This example shows how to handle XML vocabularies with multiple +root elements using the 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 from protocol.xsd and +  protocol.map. + +protocol-pimpl.hxx +protocol-pimpl.cxx +  Parser implementations 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 +  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 diff --git a/xsd/examples/cxx/parser/multiroot/balance.xml b/xsd/examples/cxx/parser/multiroot/balance.xml new file mode 100644 index 0000000..71ed493 --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/balance.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/multiroot/balance.xml +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/xsd/examples/cxx/parser/multiroot/deposit.xml b/xsd/examples/cxx/parser/multiroot/deposit.xml new file mode 100644 index 0000000..70f0c77 --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/deposit.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/multiroot/deposit.xml +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/xsd/examples/cxx/parser/multiroot/driver.cxx b/xsd/examples/cxx/parser/multiroot/driver.cxx new file mode 100644 index 0000000..3b32898 --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/driver.cxx @@ -0,0 +1,161 @@ +// file      : examples/cxx/parser/multiroot/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "protocol.hxx" +#include "protocol-pimpl.hxx" + +using std::cerr; +using std::endl; +using xml_schema::ro_string; + +namespace protocol +{ +  // Customize the xml_schema::document object to handle our protocol +  // vocabulary with multiple root elements. +  // +  class document: public xml_schema::document +  { +  public: +    document (balance_pskel& balance_p, withdraw_pskel& withdraw_p) +        : balance_p_ (balance_p), withdraw_p_ (withdraw_p) +    { +    } + +    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. The type argument is used to handle polymorphic +    // XML documents and is not used in this example (see the polyroot +    // example for more information on this argument). +    // +    virtual xml_schema::parser_base* +    start_root_element (const ro_string& ns, +                        const ro_string& name, +                        const ro_string* /* type */) +    { +      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: " << ns << "#" << name << endl; + +      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_.reset (balance_p_.post_balance ()); +      } +      else if (parser == &withdraw_p_) +      { +        result_.reset (withdraw_p_.post_withdraw ()); +      } +      else +        result_.reset (0); +    } + + +  private: +    std::auto_ptr<request> result_; + +    balance_pskel& balance_p_; +    withdraw_pskel& withdraw_p_; +  }; +} + + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " request.xml" << endl; +    return 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 doc_p (balance_p, withdraw_p); + +    // pre() and post() will be called as part of the start_root_element() +    // and end_root_element() calls. +    // +    doc_p.parse (argv[1]); +    std::auto_ptr<request> r (doc_p.result ()); + +    // Let's print what we've got. +    // +    if (balance* b = dynamic_cast<balance*> (r.get ())) +    { +      cerr << "balance request for acc# " << b->account () << endl; +    } +    else if (withdraw* w = dynamic_cast<withdraw*> (r.get ())) +    { +      cerr << "withdrawal request for acc# " << w->account () << ", " +           << "amount: " << w->amount () << endl; +    } +    else +    { +      cerr << "unknown request" << endl; +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/multiroot/makefile b/xsd/examples/cxx/parser/multiroot/makefile new file mode 100644 index 0000000..60c6bac --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/makefile @@ -0,0 +1,113 @@ +# file      : examples/cxx/parser/multiroot/makefile +# copyright : Copyright (c) 2005-2014 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 protocol-pimpl.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --type-map $(src_base)/protocol.map +$(gen): $(out_root)/xsd/xsd $(src_base)/protocol.map + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/protocol.xsd,$(install_doc_dir)/xsd/$(path)/protocol.xsd) +	$(call install-data,$(src_base)/balance.xml,$(install_doc_dir)/xsd/$(path)/balance.xml) +	$(call install-data,$(src_base)/deposit.xml,$(install_doc_dir)/xsd/$(path)/deposit.xml) +	$(call install-data,$(src_base)/withdraw.xml,$(install_doc_dir)/xsd/$(path)/withdraw.xml) +	$(call install-data,$(src_base)/protocol.map,$(install_doc_dir)/xsd/$(path)/protocol.map) +	$(call install-data,$(src_base)/protocol.hxx,$(install_doc_dir)/xsd/$(path)/protocol.hxx) +	$(call install-data,$(src_base)/protocol-pimpl.hxx,$(install_doc_dir)/xsd/$(path)/protocol-pimpl.hxx) +	$(call install-data,$(src_base)/protocol-pimpl.cxx,$(install_doc_dir)/xsd/$(path)/protocol-pimpl.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/protocol.xsd,$(dist_prefix)/$(path)/protocol.xsd) +	$(call install-data,$(src_base)/balance.xml,$(dist_prefix)/$(path)/balance.xml) +	$(call install-data,$(src_base)/deposit.xml,$(dist_prefix)/$(path)/deposit.xml) +	$(call install-data,$(src_base)/withdraw.xml,$(dist_prefix)/$(path)/withdraw.xml) +	$(call install-data,$(src_base)/protocol.map,$(dist_prefix)/$(path)/protocol.map) +	$(call install-data,$(src_base)/protocol.hxx,$(dist_prefix)/$(path)/protocol.hxx) +	$(call install-data,$(src_base)/protocol-pimpl.hxx,$(dist_prefix)/$(path)/protocol-pimpl.hxx) +	$(call install-data,$(src_base)/protocol-pimpl.cxx,$(dist_prefix)/$(path)/protocol-pimpl.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/multiroot/protocol-pimpl.cxx b/xsd/examples/cxx/parser/multiroot/protocol-pimpl.cxx new file mode 100644 index 0000000..b5ec1b2 --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/protocol-pimpl.cxx @@ -0,0 +1,46 @@ +// file      : examples/cxx/parser/multiroot/protocol-pimpl.cxx +// copyright : not copyrighted - public domain + +#include "protocol-pimpl.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/xsd/examples/cxx/parser/multiroot/protocol-pimpl.hxx b/xsd/examples/cxx/parser/multiroot/protocol-pimpl.hxx new file mode 100644 index 0000000..c0693cb --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/protocol-pimpl.hxx @@ -0,0 +1,48 @@ +// file      : examples/cxx/parser/multiroot/protocol-pimpl.hxx +// 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/xsd/examples/cxx/parser/multiroot/protocol.hxx b/xsd/examples/cxx/parser/multiroot/protocol.hxx new file mode 100644 index 0000000..bbf5b56 --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/protocol.hxx @@ -0,0 +1,61 @@ +// file      : examples/cxx/parser/multiroot/protocol.hxx +// 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/xsd/examples/cxx/parser/multiroot/protocol.map b/xsd/examples/cxx/parser/multiroot/protocol.map new file mode 100644 index 0000000..8d8ac9f --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/protocol.map @@ -0,0 +1,11 @@ +# file      : examples/cxx/parser/multiroot/protocol.map +# copyright : not copyrighted - public domain + +namespace http://www.codesynthesis.com/protocol ::protocol +{ +  include "protocol.hxx"; + +  request request*; +  balance balance*; +  withdraw withdraw*; +} diff --git a/xsd/examples/cxx/parser/multiroot/protocol.xsd b/xsd/examples/cxx/parser/multiroot/protocol.xsd new file mode 100644 index 0000000..e0ecc29 --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/protocol.xsd @@ -0,0 +1,50 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/multiroot/protocol.xsd +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/xsd/examples/cxx/parser/multiroot/withdraw.xml b/xsd/examples/cxx/parser/multiroot/withdraw.xml new file mode 100644 index 0000000..6d5cb39 --- /dev/null +++ b/xsd/examples/cxx/parser/multiroot/withdraw.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/multiroot/withdraw.xml +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/xsd/examples/cxx/parser/performance/README b/xsd/examples/cxx/parser/performance/README new file mode 100644 index 0000000..39aecca --- /dev/null +++ b/xsd/examples/cxx/parser/performance/README @@ -0,0 +1,42 @@ +This example measures the performance of XML parsing in the C++/Parser +mapping. It also shows how to structure your code to achieve the maximum +performance for this operation. + +The example consists of the following files: + +test.xsd +  XML Schema which describes the test vocabulary. + +test-50k.xml +  Test XML document. + +gen.cxx +  Program to generate a test document of desired size. + +time.hxx +time.cxx +  Class definition that represents time. + +test-pskel.hxx +test-pskel.ixx +test-pskel.cxx +  Parser skeletons generated by the XSD compiler from test.xsd. + +driver.cxx +  Driver for the example. It first parses the command line arguments +  and reads the entire document into a memory buffer. It then creates +  a SAX parser and pre-parses and caches the schema if validation is +  enabled (Xerces-C++ only). Finally, it runs the performance +  measurement loop which on each iteration parses the XML document +  from the in-memory buffer. + +To run the example on a test XML document simply execute: + +$ ./driver test-50k.xml + +The -v option can be used to turn on validation in the underlying XML +parser (only makes sense for Xerces-C++, off by default). The -i option +can be used to specify the number of parsing iterations (1000 by default). +For example: + +$ ./driver -v -i 100 test-50k.xml diff --git a/xsd/examples/cxx/parser/performance/driver.cxx b/xsd/examples/cxx/parser/performance/driver.cxx new file mode 100644 index 0000000..302464e --- /dev/null +++ b/xsd/examples/cxx/parser/performance/driver.cxx @@ -0,0 +1,341 @@ +// file      : examples/cxx/parser/performance/driver.cxx +// copyright : not copyrighted - public domain + +#include <string> +#include <memory>  // std::auto_ptr +#include <cstddef> // std::size_t +#include <fstream> +#include <sstream> +#include <iostream> + +#include "time.hxx" +#include "test-pskel.hxx" + +#ifdef _XERCES_VERSION +#  include <xercesc/sax2/SAX2XMLReader.hpp> +#  include <xercesc/sax2/XMLReaderFactory.hpp> +#  include <xercesc/framework/MemBufInputSource.hpp> +#  include <xercesc/validators/common/Grammar.hpp> +#  include <xercesc/util/PlatformUtils.hpp> +#  include <xercesc/util/XMLUni.hpp> + +#  include <xsd/cxx/xml/sax/bits/error-handler-proxy.hxx> +#  include <xsd/cxx/parser/error-handler.hxx> +#endif + +// No-op parser implementation. +// +namespace test +{ +  struct enum_pimpl: enum_pskel, xml_schema::string_pimpl +  { +    virtual void +    post_enum () +    { +    } +  }; + +  struct record_pimpl: record_pskel +  { +    virtual void +    int_ (unsigned int) +    { +    } + +    virtual void +    double_ (double) +    { +    } + +    virtual void +    name (const std::string&) +    { +    } + +    virtual void +    string (const std::string&) +    { +    } + +    virtual void +    choice1 (const std::string&) +    { +    } + +    virtual void +    choice2 (const std::string&) +    { +    } + +    virtual void +    choice3 (const std::string&) +    { +    } + +    virtual void +    choice4 (const std::string&) +    { +    } + +    virtual void +    apple (bool) +    { +    } + +    virtual void +    orange (unsigned long long) +    { +    } +  }; + +  struct root_pimpl: root_pskel +  { +  }; +} + +using namespace std; + +int +main (int argc, char* argv[]) +{ +  if (argc < 2) +  { +    cerr << "usage: " << argv[0] << " [-v] [-i <count>] test.xml" << endl +         << "\t -v turn on validation (default is off)" << endl +         << "\t -i number of iterations to perform (default is 1000)" << endl; +    return 1; +  } + +  bool validate (false); +  unsigned long iter (1000); +  const char* file (0); + +  // Parse command line arguments. +  // +  for (int i (1); i < argc; ++i) +  { +    string arg (argv[i]); + +    if (arg == "-v") +    { +      validate = true; +    } +    else if (arg == "-i") +    { +      if (++i == argc) +      { +        cerr << "argument expected for the -i option" << endl; +        return 1; +      } + +      iter = 0; +      istringstream is (argv[i]); +      is >> iter; + +      if (iter == 0) +      { +        cerr << "invalid argument for the -i option" << endl; +        return 1; +      } +    } +    else +    { +      file = argv[i]; +      break; +    } +  } + +  if (file == 0) +  { +    cerr << "no input file specified" << endl; +    return 1; +  } + +  try +  { +    // Instantiate and connect parsers. +    // +    xml_schema::unsigned_int_pimpl unsigned_int_p; +    xml_schema::double_pimpl double_p; +    xml_schema::ncname_pimpl ncname_p; +    xml_schema::string_pimpl string_p; +    xml_schema::boolean_pimpl boolean_p; +    xml_schema::unsigned_long_pimpl unsigned_long_p; + +    test::enum_pimpl enum_p; +    test::record_pimpl record_p; +    test::root_pimpl root_p; + +    record_p.parsers (unsigned_int_p, +                      double_p, +                      ncname_p, +                      string_p, +                      string_p, +                      string_p, +                      string_p, +                      string_p, +                      enum_p, +                      boolean_p, +                      unsigned_long_p); + +    root_p.parsers (record_p); + +    // Read the fine into in-memory buffer. +    // +    ifstream ifs; +    ifs.exceptions (ios_base::failbit); +    ifs.open (file, ios::in | ios::ate); + +    size_t size (ifs.tellg ()); +    ifs.seekg (0, ios::beg); + +    char* buf = new char[size]; +    ifs.read (buf, size); +    ifs.close (); + +    cerr << "document size:  " << size << " bytes" << endl +         << "iterations:     " << iter << endl; + +    os::time time (0); +    xml_schema::document doc (root_p, "test", "root"); + +#ifdef _XERCES_VERSION + +    // Xerces-C++ as the underlying XML parser. +    // +    using namespace xercesc; + +    namespace xml = xsd::cxx::xml; +    namespace parser = xsd::cxx::parser; + +    XMLPlatformUtils::Initialize (); + +    { +      MemBufInputSource is ( +        reinterpret_cast<XMLByte*> (buf), size, file, false); +      is.setCopyBufToStream (false); + +      auto_ptr<SAX2XMLReader> parser (XMLReaderFactory::createXMLReader ()); + +      parser->setFeature (XMLUni::fgSAX2CoreNameSpaces, true); +      parser->setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes, true); +      parser->setFeature (XMLUni::fgXercesValidationErrorAsFatal, true); + +      if (validate) +      { +        parser->setFeature (XMLUni::fgSAX2CoreValidation, true); +        parser->setFeature (XMLUni::fgXercesSchema, true); +        parser->setFeature (XMLUni::fgXercesSchemaFullChecking, false); + +        // Xerces-C++ 3.1.0 is the first version with working multi import +        // support. +        // +#if _XERCES_VERSION >= 30100 +        parser->setFeature (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +        // Initialize the schema cache. To detect schema errors we will +        // need an error handler. +        // +        parser::error_handler<char> eh; +        xml::sax::bits::error_handler_proxy<char> ehp (eh); +        parser->setErrorHandler (&ehp); + +        if (!parser->loadGrammar ("test.xsd", Grammar::SchemaGrammarType, true)) +        { +          // In Xerces-C++ grammar loading failure results in just a warning. +          // Make it a fatal error. +          // +          eh.handle ("test.xsd", 0, 0, +                     parser::error_handler<char>::severity::fatal, +                     "unable to load schema"); +        } + +        eh.throw_if_failed (); +        parser->setFeature (XMLUni::fgXercesUseCachedGrammarInParse, true); + +#if _XERCES_VERSION >= 30100 +        parser->setFeature (XMLUni::fgXercesLoadSchema, false); +#endif +      } +      else +      { +        parser->setFeature (XMLUni::fgSAX2CoreValidation, false); +        parser->setFeature (XMLUni::fgXercesSchema, false); +        parser->setFeature (XMLUni::fgXercesSchemaFullChecking, false); +      } + +      os::time start; + +      for (unsigned long i (0); i < iter; ++i) +      { +        root_p.pre (); +        doc.parse (is, *parser); +        root_p.post_root (); +      } + +      os::time end; +      time = end - start; +    } + +    XMLPlatformUtils::Terminate (); + +#else + +    // Expat as the underlying XML parser. +    // +    XML_Parser xml_parser (XML_ParserCreateNS (0, ' ')); +    string public_id (file); + +    os::time start; + +    for (unsigned long i (0); i < iter; ++i) +    { +      // Using the low-level Expat-specific API to parse the memory +      // buffer. +      // +      root_p.pre (); +      doc.parse_begin (xml_parser, public_id); + +      XML_Parse (xml_parser, buf, size, 1); + +      doc.parse_end (); +      root_p.post_root (); + +      XML_ParserReset (xml_parser, 0); +    } + +    os::time end; +    time = end - start; + +    XML_ParserFree (xml_parser); + +#endif + +    delete[] buf; + +    cerr << "time:           " << time << " sec" << endl; + +    double ms (time.sec () * 1000000ULL + time.nsec () / 1000ULL); + +    // Calculate throughput in documents/sec. +    // +    double tpd ((iter / ms) * 1000000); +    cerr << "throughput:     " << tpd << " documents/sec" << endl; + +    // Calculate throughput in MBytes/sec. +    // +    double tpb (((size * iter) / ms) * 1000000/(1024*1024)); +    cerr << "throughput:     " << tpb << " MBytes/sec" << endl; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (std::ios_base::failure const&) +  { +    cerr << "io failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/performance/gen.cxx b/xsd/examples/cxx/parser/performance/gen.cxx new file mode 100644 index 0000000..b6392c0 --- /dev/null +++ b/xsd/examples/cxx/parser/performance/gen.cxx @@ -0,0 +1,76 @@ +#include <fstream> +#include <sstream> +#include <iostream> + +using namespace std; + +static const char* enums[] = +{ +  "romance", +  "fiction", +  "horror", +  "history", +  "philosophy" +}; + +int +main (int argc, char* argv[]) +{ +  if (argc != 3) +  { +    cerr << "usage: " << argv[0] << " <count> <output-file>" << endl; +    return 1; +  } + +  unsigned long n (0); +  istringstream is (argv[1]); +  is >> n; + +  if (n == 0) +  { +    cerr << "record count argument should be a positive number" << endl; +    return 1; +  } + +  ofstream ofs (argv[2]); + +  if (!ofs.is_open ()) +  { +    cerr << "unable to open '" << argv[2] << "' in write mode" << endl; +    return 1; +  } + +  ofs << "<t:root xmlns:t='test' " << +    "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " << +    "xsi:schemaLocation='test test.xsd'>"; + +  unsigned short ch (1), en (0); + +  for (unsigned long i (0); i < n; ++i) +  { +    ofs << "<record orange=\"" << i << "\""; + +    if (i % 2 == 0) +      ofs << " apple=\"true\""; + +    ofs << ">" +        << "<int>42</int>" +        << "<double>42345.4232</double>" +        << "<name>name123_45</name>"; + +    if (i % 2 == 1) +      ofs << "<string>one two three</string>"; + +    ofs << "<choice" << ch << ">" << ch << " choice</choice" << ch << ">" +        << "<enum>" << enums[en] << "</enum>" +        << "</record>"; + +    if (++ch > 4) +      ch = 1; + +    if (++en > 4) +      en = 0; +  } + +  ofs << "</t:root>"; +} diff --git a/xsd/examples/cxx/parser/performance/makefile b/xsd/examples/cxx/parser/performance/makefile new file mode 100644 index 0000000..69d3239 --- /dev/null +++ b/xsd/examples/cxx/parser/performance/makefile @@ -0,0 +1,109 @@ +# file      : examples/cxx/parser/performance/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := test.xsd +cxx := driver.cxx time.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-inline +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/test.xsd,$(install_doc_dir)/xsd/$(path)/test.xsd) +	$(call install-data,$(src_base)/test-50k.xml,$(install_doc_dir)/xsd/$(path)/test-50k.xml) +	$(call install-data,$(src_base)/time.hxx,$(install_doc_dir)/xsd/$(path)/time.hxx) +	$(call install-data,$(src_base)/time.cxx,$(install_doc_dir)/xsd/$(path)/time.cxx) +	$(call install-data,$(src_base)/gen.cxx,$(install_doc_dir)/xsd/$(path)/gen.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/test.xsd,$(dist_prefix)/$(path)/test.xsd) +	$(call install-data,$(src_base)/test-50k.xml,$(dist_prefix)/$(path)/test-50k.xml) +	$(call install-data,$(src_base)/time.hxx,$(dist_prefix)/$(path)/time.hxx) +	$(call install-data,$(src_base)/time.cxx,$(dist_prefix)/$(path)/time.cxx) +	$(call install-data,$(src_base)/gen.cxx,$(dist_prefix)/$(path)/gen.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/performance/test-50k.xml b/xsd/examples/cxx/parser/performance/test-50k.xml new file mode 100644 index 0000000..42e22f3 --- /dev/null +++ b/xsd/examples/cxx/parser/performance/test-50k.xml @@ -0,0 +1 @@ +<t:root xmlns:t='test' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='test test.xsd'><record orange="0" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="1"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="2" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="3"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="4" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="5"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="6" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="7"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="8" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="9"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="10" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="11"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="12" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="13"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="14" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="15"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="16" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="17"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="18" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="19"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="20" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="21"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="22" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="23"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="24" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="25"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="26" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="27"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="28" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="29"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="30" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="31"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="32" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="33"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="34" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="35"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="36" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="37"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="38" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="39"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="40" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="41"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="42" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="43"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="44" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="45"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="46" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="47"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="48" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="49"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="50" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="51"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="52" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="53"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="54" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="55"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="56" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="57"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="58" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="59"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="60" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="61"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="62" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="63"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="64" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="65"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="66" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="67"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="68" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="69"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="70" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="71"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="72" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="73"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="74" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="75"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="76" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="77"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="78" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="79"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="80" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="81"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="82" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="83"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="84" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="85"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="86" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="87"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="88" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="89"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="90" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="91"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="92" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="93"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="94" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="95"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="96" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="97"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="98" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="99"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="100" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="101"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="102" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="103"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="104" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="105"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="106" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="107"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="108" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="109"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="110" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="111"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="112" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="113"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="114" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="115"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="116" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="117"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="118" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="119"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="120" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="121"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="122" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="123"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="124" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="125"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="126" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="127"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="128" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="129"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="130" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="131"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="132" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="133"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="134" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="135"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="136" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="137"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="138" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="139"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="140" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="141"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="142" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="143"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="144" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="145"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="146" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="147"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="148" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="149"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="150" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="151"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="152" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="153"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="154" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="155"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="156" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="157"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="158" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="159"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="160" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="161"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="162" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="163"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="164" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="165"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="166" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="167"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="168" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="169"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="170" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="171"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="172" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="173"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="174" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="175"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="176" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="177"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="178" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="179"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="180" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="181"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="182" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="183"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="184" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="185"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="186" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="187"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="188" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="189"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="190" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="191"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="192" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="193"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="194" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="195"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="196" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="197"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="198" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="199"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="200" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="201"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="202" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="203"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="204" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="205"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="206" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="207"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="208" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="209"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="210" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="211"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="212" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="213"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="214" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="215"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="216" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="217"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="218" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="219"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="220" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="221"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="222" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="223"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="224" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="225"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="226" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="227"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="228" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="229"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="230" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="231"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="232" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="233"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="234" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="235"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="236" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="237"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="238" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="239"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="240" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="241"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="242" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="243"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="244" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="245"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="246" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="247"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="248" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="249"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="250" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="251"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="252" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="253"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="254" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="255"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="256" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="257"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="258" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="259"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="260" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="261"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="262" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="263"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="264" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="265"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="266" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="267"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="268" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="269"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="270" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="271"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="272" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="273"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="274" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="275"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="276" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="277"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="278" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="279"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="280" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="281"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="282" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="283"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="284" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="285"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="286" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="287"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="288" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="289"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="290" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="291"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="292" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="293"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="294" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="295"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="296" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="297"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="298" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="299"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="300" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="301"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="302" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="303"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="304" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="305"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="306" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="307"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="308" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="309"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="310" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="311"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="312" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="313"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="314" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="315"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="316" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record></t:root>
\ No newline at end of file diff --git a/xsd/examples/cxx/parser/performance/test.xsd b/xsd/examples/cxx/parser/performance/test.xsd new file mode 100644 index 0000000..bb59c2a --- /dev/null +++ b/xsd/examples/cxx/parser/performance/test.xsd @@ -0,0 +1,49 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/performance/test.xsd +copyright : not copyrighted - public domain + +--> + +<schema targetNamespace="test" xmlns:t="test" +        xmlns="http://www.w3.org/2001/XMLSchema"> + +  <simpleType name="enum"> +    <restriction base="string"> +      <enumeration value="romance"/> +      <enumeration value="fiction"/> +      <enumeration value="horror"/> +      <enumeration value="history"/> +      <enumeration value="philosophy"/> +    </restriction> +  </simpleType> + +  <complexType name="record"> +    <sequence> +      <element name="int" type="unsignedInt"/> +      <element name="double" type="double"/> +      <element name="name" type="NCName"/> +      <element name="string" type="string" minOccurs="0" maxOccurs="1"/> +      <choice> +        <element name="choice1" type="string"/> +        <element name="choice2" type="string"/> +        <element name="choice3" type="string"/> +        <element name="choice4" type="string"/> +      </choice> +      <element name="enum" type="t:enum"/> +    </sequence> +    <attribute name="apple" type="boolean"/> +    <attribute name="orange" type="unsignedLong" use="required"/> +  </complexType> + +  <complexType name="root"> +    <sequence> +      <element name="record" type="t:record" maxOccurs="unbounded"/> +    </sequence> +  </complexType> + +  <element name="root" type="t:root"/> + +</schema> diff --git a/xsd/examples/cxx/parser/performance/time.cxx b/xsd/examples/cxx/parser/performance/time.cxx new file mode 100644 index 0000000..aca5c74 --- /dev/null +++ b/xsd/examples/cxx/parser/performance/time.cxx @@ -0,0 +1,46 @@ +// file      : examples/cxx/parser/performance/time.cxx +// copyright : not copyrighted - public domain + +#include "time.hxx" + +#if defined (WIN32) || defined (__WIN32__) +#  define WIN32_LEAN_AND_MEAN +#  include <windows.h>  // GetSystemTimeAsFileTime +#else +#  include <time.h>     // gettimeofday +#  include <sys/time.h> // timeval +#endif + +#include <ostream> // std::ostream +#include <iomanip> // std::setfill, std::setw + +namespace os +{ +  time:: +  time () +  { +#if defined (WIN32) || defined (__WIN32__) +    FILETIME ft; +    GetSystemTimeAsFileTime (&ft); +    unsigned long long v ( +      ((unsigned long long) (ft.dwHighDateTime) << 32) + ft.dwLowDateTime); + +    sec_  = static_cast<unsigned long> (v / 10000000ULL); +    nsec_ = static_cast<unsigned long> ((v % 10000000ULL) * 100); +#else +    timeval tv; +    if (gettimeofday(&tv, 0) != 0) +      throw failed (); + +    sec_  = static_cast<unsigned long> (tv.tv_sec); +    nsec_ = static_cast<unsigned long> (tv.tv_usec * 1000); +#endif +  } + +  std::ostream& +  operator<< (std::ostream& o, time const& t) +  { +    return o << t.sec () << '.' +             << std::setfill ('0') << std::setw (9) << t.nsec (); +  } +} diff --git a/xsd/examples/cxx/parser/performance/time.hxx b/xsd/examples/cxx/parser/performance/time.hxx new file mode 100644 index 0000000..3b2f040 --- /dev/null +++ b/xsd/examples/cxx/parser/performance/time.hxx @@ -0,0 +1,110 @@ +// file      : examples/cxx/parser/performance/time.hxx +// copyright : not copyrighted - public domain + +#ifndef TIME_HXX +#define TIME_HXX + +#include <iosfwd> // std::ostream& + +namespace os +{ +  class time +  { +  public: +    class failed {}; + +    // Create a time object representing the current time. +    // +    time (); + +    time (unsigned long long nsec) +    { +      sec_  = static_cast<unsigned long> (nsec / 1000000000ULL); +      nsec_ = static_cast<unsigned long> (nsec % 1000000000ULL); +    } + +    time (unsigned long sec, unsigned long nsec) +    { +      sec_  = sec; +      nsec_ = nsec; +    } + +  public: +    unsigned long +    sec () const +    { +      return sec_; +    } + +    unsigned long +    nsec () const +    { +      return nsec_; +    } + +  public: +    class overflow {}; +    class underflow {}; + +    time +    operator+= (time const& b) +    { +      unsigned long long tmp = 0ULL + nsec_ + b.nsec_; + +      sec_ += static_cast<unsigned long> (b.sec_ + tmp / 1000000000ULL); +      nsec_ = static_cast<unsigned long> (tmp % 1000000000ULL); + +      return *this; +    } + +    time +    operator-= (time const& b) +    { +      if (*this < b) +        throw underflow (); + +      sec_ -= b.sec_; + +      if (nsec_ < b.nsec_) +      { +        --sec_; +        nsec_ += 1000000000ULL - b.nsec_; +      } +      else +        nsec_ -= b.nsec_; + +      return *this; +    } + +    friend time +    operator+ (time const& a, time const& b) +    { +      time r (a); +      r += b; +      return r; +    } + +    friend time +    operator- (time const& a, time const& b) +    { +      time r (a); +      r -= b; +      return r; +    } + +    friend bool +    operator < (time const& a, time const& b) +    { +      return (a.sec_ < b.sec_) || (a.sec_ == b.sec_ && a.nsec_ < b.nsec_); +    } + +  private: +    unsigned long sec_; +    unsigned long nsec_; +  }; + +  std::ostream& +  operator<< (std::ostream&, time const&); +} + +#endif // TIME_HXX diff --git a/xsd/examples/cxx/parser/polymorphism/README b/xsd/examples/cxx/parser/polymorphism/README new file mode 100644 index 0000000..60a97e9 --- /dev/null +++ b/xsd/examples/cxx/parser/polymorphism/README @@ -0,0 +1,30 @@ +This example shows how to handle XML Schema polymorphism features such +as xsi:type attributes and substitution groups in the C++/Parser mapping. +The case when xsi:type is used on root elements is covered in the +polyroot examples. + +The example consists of the following files: + +supermen.xsd +  XML Schema which describes the "supermen" instance documents. + +supermen.xml +  Sample XML instance document. + +supermen-pskel.hxx +supermen-pskel.cxx +  Parser skeletons generated by the XSD compiler from supermen.xsd. +  Note the use of the --generate-polymorphic command line option. + +supermen-pimpl.hxx +supermen-pimpl.cxx +  Parser implementations 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 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 diff --git a/xsd/examples/cxx/parser/polymorphism/driver.cxx b/xsd/examples/cxx/parser/polymorphism/driver.cxx new file mode 100644 index 0000000..ffbe48b --- /dev/null +++ b/xsd/examples/cxx/parser/polymorphism/driver.cxx @@ -0,0 +1,70 @@ +// file      : examples/cxx/parser/polymorphism/driver.cxx +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "supermen-pimpl.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " supermen.xml" << endl; +    return 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; + +    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 a parser map which containes 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 doc_p (supermen_p, "supermen", true); + +    supermen_p.pre (); +    doc_p.parse (argv[1]); +    supermen_p.post_supermen (); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/polymorphism/makefile b/xsd/examples/cxx/parser/polymorphism/makefile new file mode 100644 index 0000000..8a89ab8 --- /dev/null +++ b/xsd/examples/cxx/parser/polymorphism/makefile @@ -0,0 +1,106 @@ +# file      : examples/cxx/parser/polymorphism/makefile +# copyright : Copyright (c) 2005-2014 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 supermen-pimpl.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-polymorphic +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/supermen.xsd,$(install_doc_dir)/xsd/$(path)/supermen.xsd) +	$(call install-data,$(src_base)/supermen.xml,$(install_doc_dir)/xsd/$(path)/supermen.xml) +	$(call install-data,$(src_base)/supermen-pimpl.hxx,$(install_doc_dir)/xsd/$(path)/supermen-pimpl.hxx) +	$(call install-data,$(src_base)/supermen-pimpl.cxx,$(install_doc_dir)/xsd/$(path)/supermen-pimpl.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/supermen.xsd,$(dist_prefix)/$(path)/supermen.xsd) +	$(call install-data,$(src_base)/supermen.xml,$(dist_prefix)/$(path)/supermen.xml) +	$(call install-data,$(src_base)/supermen-pimpl.hxx,$(dist_prefix)/$(path)/supermen-pimpl.hxx) +	$(call install-data,$(src_base)/supermen-pimpl.cxx,$(dist_prefix)/$(path)/supermen-pimpl.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/polymorphism/supermen-pimpl.cxx b/xsd/examples/cxx/parser/polymorphism/supermen-pimpl.cxx new file mode 100644 index 0000000..f4b3bc6 --- /dev/null +++ b/xsd/examples/cxx/parser/polymorphism/supermen-pimpl.cxx @@ -0,0 +1,85 @@ +// file      : examples/cxx/parser/polymorphism/supermen-pimpl.cxx +// copyright : not copyrighted - public domain +// + +#include <iostream> + +#include "supermen-pimpl.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 << "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 +// +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/xsd/examples/cxx/parser/polymorphism/supermen-pimpl.hxx b/xsd/examples/cxx/parser/polymorphism/supermen-pimpl.hxx new file mode 100644 index 0000000..eaf81e5 --- /dev/null +++ b/xsd/examples/cxx/parser/polymorphism/supermen-pimpl.hxx @@ -0,0 +1,68 @@ +// file      : examples/cxx/parser/polymorphism/supermen-pimpl.hxx +// 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 supermen_pskel +{ +}; + +#endif // SUPERMEN_PIMPL_HXX diff --git a/xsd/examples/cxx/parser/polymorphism/supermen.xml b/xsd/examples/cxx/parser/polymorphism/supermen.xml new file mode 100644 index 0000000..15054fa --- /dev/null +++ b/xsd/examples/cxx/parser/polymorphism/supermen.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/polymorphism/supermen.xml +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/xsd/examples/cxx/parser/polymorphism/supermen.xsd b/xsd/examples/cxx/parser/polymorphism/supermen.xsd new file mode 100644 index 0000000..c9029da --- /dev/null +++ b/xsd/examples/cxx/parser/polymorphism/supermen.xsd @@ -0,0 +1,48 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/polymorphism/supermen.xsd +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/xsd/examples/cxx/parser/polyroot/README b/xsd/examples/cxx/parser/polyroot/README new file mode 100644 index 0000000..f41b91c --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/README @@ -0,0 +1,36 @@ +This example shows how to handle the xsi:type attributes when it is used +on root elements. For general coverage of XML Schema polymorphism handling +in the C++/Parser mapping see the polymorphism example. + +The example consists of the following files: + +supermen.xsd +  XML Schema which describes the "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 compiler from supermen.xsd. +  Note the use of the --generate-polymorphic command line option. + +supermen-pimpl.hxx +supermen-pimpl.cxx +  Parser implementations 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 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 diff --git a/xsd/examples/cxx/parser/polyroot/batman.xml b/xsd/examples/cxx/parser/polyroot/batman.xml new file mode 100644 index 0000000..fad0b71 --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/batman.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/polyroot/batman.xml +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/xsd/examples/cxx/parser/polyroot/driver.cxx b/xsd/examples/cxx/parser/polyroot/driver.cxx new file mode 100644 index 0000000..1c9c778 --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/driver.cxx @@ -0,0 +1,138 @@ +// file      : examples/cxx/parser/polyroot/driver.cxx +// copyright : not copyrighted - public domain + +#include <map> +#include <string> +#include <iostream> + +#include "supermen-pimpl.hxx" + +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: public xml_schema::document +{ +public: +  document (const xml_schema::parser_map& parser_map) +      : xml_schema::document (true), // Indicate polymorphic parsing. +        parser_map_ (parser_map) +  { +  } + +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 was specified for this element and 0 +  // otherwise. +  // +  virtual xml_schema::parser_base* +  start_root_element (const ro_string& ns, +                      const ro_string& name, +                      const ro_string* type) +  { +    if (name != "person" || !ns.empty ()) +      return 0; + +    xml_schema::parser_base* base; + +    // Search the parser map. +    // +    if (type == 0) +    { +      // No xsi:type. Static type should be used. +      // +      ro_string st (person_pskel::_static_type ()); +      base = parser_map_.find (st); +    } +    else +    { +      base = parser_map_.find (*type); +    } + +    if (base != 0) +    { +      parser_used_ = dynamic_cast<person_pskel*> (base); +      parser_used_->pre (); +    } +    else +      parser_used_ = 0; // No parser for this type. + +    return parser_used_; +  } + +  // 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 dynamic_cast the parser argument to the person_pskel +    // type. +    // +    if (parser_used_) +      parser_used_->post_person (); +  } + + +private: +  const xml_schema::parser_map& parser_map_; +  person_pskel* parser_used_; +}; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " instance.xml" << endl; +    return 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; + +    person_map.insert (person_p); +    person_map.insert (superman_p); +    person_map.insert (batman_p); + +    document doc_p (person_map); + +    doc_p.parse (argv[1]); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/polyroot/makefile b/xsd/examples/cxx/parser/polyroot/makefile new file mode 100644 index 0000000..a5a9088 --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/makefile @@ -0,0 +1,110 @@ +# file      : examples/cxx/parser/polyroot/makefile +# copyright : Copyright (c) 2005-2014 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 supermen-pimpl.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=-pskel.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-polymorphic +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/supermen.xsd,$(install_doc_dir)/xsd/$(path)/supermen.xsd) +	$(call install-data,$(src_base)/batman.xml,$(install_doc_dir)/xsd/$(path)/batman.xml) +	$(call install-data,$(src_base)/person.xml,$(install_doc_dir)/xsd/$(path)/person.xml) +	$(call install-data,$(src_base)/superman.xml,$(install_doc_dir)/xsd/$(path)/superman.xml) +	$(call install-data,$(src_base)/supermen-pimpl.hxx,$(install_doc_dir)/xsd/$(path)/supermen-pimpl.hxx) +	$(call install-data,$(src_base)/supermen-pimpl.cxx,$(install_doc_dir)/xsd/$(path)/supermen-pimpl.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/supermen.xsd,$(dist_prefix)/$(path)/supermen.xsd) +	$(call install-data,$(src_base)/batman.xml,$(dist_prefix)/$(path)/batman.xml) +	$(call install-data,$(src_base)/person.xml,$(dist_prefix)/$(path)/person.xml) +	$(call install-data,$(src_base)/superman.xml,$(dist_prefix)/$(path)/superman.xml) +	$(call install-data,$(src_base)/supermen-pimpl.hxx,$(dist_prefix)/$(path)/supermen-pimpl.hxx) +	$(call install-data,$(src_base)/supermen-pimpl.cxx,$(dist_prefix)/$(path)/supermen-pimpl.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/parser/polyroot/person.xml b/xsd/examples/cxx/parser/polyroot/person.xml new file mode 100644 index 0000000..f463bea --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/person.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/polyroot/person.xml +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/xsd/examples/cxx/parser/polyroot/superman.xml b/xsd/examples/cxx/parser/polyroot/superman.xml new file mode 100644 index 0000000..c831f6c --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/superman.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/polyroot/superman.xml +copyright : not copyrighted - public domain + +--> + +<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +        xsi:noNamespaceSchemaLocation="supermen.xsd" +	xsi:type="superman" can-fly="false"> +	 +  <name>James "007" Bond</name>    +     +</person> diff --git a/xsd/examples/cxx/parser/polyroot/supermen-pimpl.cxx b/xsd/examples/cxx/parser/polyroot/supermen-pimpl.cxx new file mode 100644 index 0000000..62289e9 --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/supermen-pimpl.cxx @@ -0,0 +1,85 @@ +// file      : examples/cxx/parser/polyroot/supermen-pimpl.cxx +// copyright : not copyrighted - public domain +// + +#include <iostream> + +#include "supermen-pimpl.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 << "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 +// +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/xsd/examples/cxx/parser/polyroot/supermen-pimpl.hxx b/xsd/examples/cxx/parser/polyroot/supermen-pimpl.hxx new file mode 100644 index 0000000..49e8c74 --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/supermen-pimpl.hxx @@ -0,0 +1,64 @@ +// file      : examples/cxx/parser/polyroot/supermen-pimpl.hxx +// 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/xsd/examples/cxx/parser/polyroot/supermen.xsd b/xsd/examples/cxx/parser/polyroot/supermen.xsd new file mode 100644 index 0000000..dc5d439 --- /dev/null +++ b/xsd/examples/cxx/parser/polyroot/supermen.xsd @@ -0,0 +1,36 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/polyroot/supermen.xsd +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> + +  <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: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/xsd/examples/cxx/parser/wildcard/README b/xsd/examples/cxx/parser/wildcard/README new file mode 100644 index 0000000..89f9aa9 --- /dev/null +++ b/xsd/examples/cxx/parser/wildcard/README @@ -0,0 +1,27 @@ +This example shows how to parse the XML data matched by XML Schema +wildcards (any and anyAttribute) in the 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 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 diff --git a/xsd/examples/cxx/parser/wildcard/driver.cxx b/xsd/examples/cxx/parser/wildcard/driver.cxx new file mode 100644 index 0000000..fa82ec0 --- /dev/null +++ b/xsd/examples/cxx/parser/wildcard/driver.cxx @@ -0,0 +1,239 @@ +// file      : examples/cxx/parser/wildcard/driver.cxx +// copyright : not copyrighted - public domain + +#include <string> +#include <memory> +#include <iostream> + +#include "email-pskel.hxx" + +using namespace std; +using xml_schema::ro_string; + +class binary_pimpl: public email::binary_pskel, +                    public xml_schema::base64_binary_pimpl +{ +public: +  virtual void +  name (const string& n) +  { +    cerr << "binary: " << n << endl; +  } + +  virtual void +  mime (const string& t) +  { +    cerr << "type:   " << t << endl +         << endl; +  } + +  virtual void +  post_binary () +  { +    auto_ptr<xml_schema::buffer> buf (post_base64_binary ()); + +    cerr << "size:   " << buf->size () << endl +         << endl; +  } +}; + +class envelope_pimpl: public email::envelope_pskel +{ +public: +  envelope_pimpl (xml_schema::unsigned_int_pskel& uint_p, +                  xml_schema::string_pskel& string_p, +                  email::binary_pskel& binary_p) +      : depth_ (0), cur_ (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 these +  // four functions. It is our job to dispatch them to the right +  // parsers. +  // +  virtual void +  _start_any_element (const ro_string& ns, +                      const ro_string& name, +                      const ro_string* type) +  { +    if (depth_++ > 0) +    { +      // Nested wildcard element. +      // +      if (cur_) +        cur_->_start_element (ns, name, type); +    } +    else +    { +      // Top-level element matched by the any wildcard. +      // +      if (ns == "http://www.codesynthesis.com/email") +      { +        if (name == "text") +        { +          cur_ = &string_p_; +          string_p_.pre (); +          string_p_._pre_impl (); +        } +        else if (name == "binary") +        { +          cur_ = &binary_p_; +          binary_p_.pre (); +          binary_p_._pre_impl (); +        } +      } + +      if (cur_ == 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 (cur_) +        cur_->_end_element (ns, name); +    } +    else +    { +      if (ns == "http://www.codesynthesis.com/email") +      { +        if (name == "text") +        { +          string_p_._post_impl (); +          string text (string_p_.post_string ()); + +          cerr << text << endl +               << endl; +        } +        else if (name == "binary") +        { +          binary_p_._post_impl (); +          binary_p_.post_binary (); +        } +      } + +      cur_ = 0; +    } +  } + +  virtual void +  _any_attribute (const ro_string& ns, +                  const ro_string& name, +                  const ro_string& value) +  { +    if (depth_ > 0) +    { +      // Nested wildcard attribute. +      // +      if (cur_) +        cur_->_attribute (ns, name, value); +    } +    else +    { +      // Top-level attribute matched by the anyAttribute wildcard. +      // +      if (ns == "http://www.codesynthesis.com/email" && name == "thread-id") +      { +        uint_p_.pre (); +        uint_p_._pre_impl (); +        uint_p_._characters (value); +        uint_p_._post_impl (); +        unsigned int tid (uint_p_.post_unsigned_int ()); + +        cerr << "Thread-id: " << tid << endl; +      } +    } +  } + +  virtual void +  _any_characters (const ro_string& s) +  { +    if (depth_ > 0) +    { +      if (cur_) +        cur_->_characters (s); +    } +  } + +private: +  size_t depth_; +  xml_schema::parser_base* cur_; + +  // Parsers for the unsigned int, string and binary types. +  // +private: +  xml_schema::unsigned_int_pskel& uint_p_; +  xml_schema::string_pskel& string_p_; +  email::binary_pskel& binary_p_; +}; + + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " email.xml" << endl; +    return 1; +  } + +  try +  { +    // Construct the parser. +    // +    xml_schema::unsigned_int_pimpl unsigned_int_p; +    xml_schema::string_pimpl string_p; +    binary_pimpl binary_p; +    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 doc_p (envelope_p, +                                "http://www.codesynthesis.com/email", +                                "message"); +    envelope_p.pre (); +    doc_p.parse (argv[1]); +    envelope_p.post_envelope (); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/parser/wildcard/email.xml b/xsd/examples/cxx/parser/wildcard/email.xml new file mode 100644 index 0000000..f5d0359 --- /dev/null +++ b/xsd/examples/cxx/parser/wildcard/email.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/wildcard/email.xml +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/xsd/examples/cxx/parser/wildcard/email.xsd b/xsd/examples/cxx/parser/wildcard/email.xsd new file mode 100644 index 0000000..087fc7e --- /dev/null +++ b/xsd/examples/cxx/parser/wildcard/email.xsd @@ -0,0 +1,50 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/parser/wildcard/email.xsd +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/xsd/examples/cxx/parser/wildcard/makefile b/xsd/examples/cxx/parser/wildcard/makefile new file mode 100644 index 0000000..524f8da --- /dev/null +++ b/xsd/examples/cxx/parser/wildcard/makefile @@ -0,0 +1,102 @@ +# file      : examples/cxx/parser/wildcard/makefile +# copyright : Copyright (c) 2005-2014 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) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.ixx) $(xsd:.xsd=-pskel.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/email.xsd,$(install_doc_dir)/xsd/$(path)/email.xsd) +	$(call install-data,$(src_base)/email.xml,$(install_doc_dir)/xsd/$(path)/email.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/email.xsd,$(dist_prefix)/$(path)/email.xsd) +	$(call install-data,$(src_base)/email.xml,$(dist_prefix)/$(path)/email.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                                 \ +  $(addsuffix .cxx.clean,$(obj))                            \ +  $(addsuffix .cxx.clean,$(dep))                            \ +  $(addprefix $(out_base)/,$(xsd:.xsd=-pskel.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/parser/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/README b/xsd/examples/cxx/tree/README new file mode 100644 index 0000000..569bf11 --- /dev/null +++ b/xsd/examples/cxx/tree/README @@ -0,0 +1,80 @@ +This directory contains a number of examples that show how to use +the C++/Tree mapping. The following list gives an overview of +each example. See the README files in example directories for +more information on each example. + +hello +  A simple "Hello, world!" example that shows how to parse XML +  documents. + +library +  Shows hot to handle more complex data structures, use the +  ID/IDREF cross-referencing mechanism, use the xsd:enumeration +  to C++ enum mapping, modify the object model, and serialize +  the modified object model back to XML. + +polymorphism +  Shows how to use XML Schema polymorphism features such as the +  xsi:type attribute and substitution groups. + +order/ +  A collection of examples that show how to use ordered types to +  capture and maintain content order. + +xpath +  Shows how to use the C++/Tree mapping together with XPath. + +wildcard +  Shows how to use the optional wildcard mapping to parse, access, +  modify, and serialize the XML data matched by XML Schema wildcards +  (any and anyAttribute). + +mixed +  Shows how to access the underlying DOM nodes to handle raw, "type- +  less content" such as mixed content models, anyType/anySimpleType, +  and any/anyAttribute. + +multiroot +  Shows how to handle XML vocabularies with multiple root elements. +  See also the messaging example. + +messaging +  Shows how to handle XML vocabularies with multiple root elements +  using the element type and element map features of the C++/Tree +  mapping. + +caching +  Shows how to parse several XML documents while reusing the +  underlying XML parser and caching the schemas used for validation. + +embedded +  Shows how to embed the binary representation of the schema grammar +  into an application and then use it with the C++/Tree mapping to +  parse and validate XML documents. + +performance +  Measures the performance of parsing and serialization. This example +  also shows how to structure your code to achieve the maximum +  performance for these two operations. + +custom/ +  A collection of examples that show how to customize the C++/Tree +  mapping by using custom C++ classes instead of or in addition to +  the generated ones. See the accompanying README file for an +  overview of each example in this directory. + +streaming +  Shows how to perform stream-oriented, partially in-memory XML +  processing using the C++/Tree mapping. With the partially in-memory +  parsing and serialization only a part of the object model is in +  memory at any given time. With this approach we can process parts +  of the document as they become available as well as handle documents +  that are too large to fit into memory. + +compression +  Shows how to compress an XML document during serialization and decompress +  it during parsing using the zlib library. + +binary/ +  A collection of examples that show how to serialize the object model +  into a number of predefined and custom binary formats. diff --git a/xsd/examples/cxx/tree/binary/README b/xsd/examples/cxx/tree/binary/README new file mode 100644 index 0000000..365551e --- /dev/null +++ b/xsd/examples/cxx/tree/binary/README @@ -0,0 +1,16 @@ +This directory contains a number of examples that show how to serialize +the object model into a number of predefined and custom binary formats. +The following list gives an overview of each example: + +boost +  Shows how to save/load the object model to/from a custom format +  using the Boost serialization library as an example. + +cdr +  Shows how to save/load the object model to/from CDR (Common Data +  Representation) binary format using ACE CDR streams. + +xdr +  Shows how to save/load the object model to/from XDR (eXternal Data +  Representation) binary format using the XDR API provided as part of +  Sun RPC. diff --git a/xsd/examples/cxx/tree/binary/boost/README b/xsd/examples/cxx/tree/binary/boost/README new file mode 100644 index 0000000..6cdd2dd --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/README @@ -0,0 +1,49 @@ +This example shows how to save/load the object model to/from a custom +format using the Boost serialization library as an example. You will +need the Boost serialization library[1] installed in order to build +and run this example. + +[1] http://www.boost.org + +The example consists of the following files: + +library.xsd +  XML Schema which describes a library of books. + +library.xml +  Sample XML instance document. + +boost-archive-extraction.hxx +boost-archive-insertion.hxx +  Boost archive insertion and extraction operators for fundamental +  types. You will need to provide a similar set of operators for +  your own stream types. + +library-prologue.hxx +  Contains a number of #include directives that are inserted into +  the generated code by the XSD compiler. The included files are: +  boost/archive/text_oarchive.hpp, boost/archive/text_oarchive.hpp, +  boost-archive-insertion.hxx, and boost-archive-insertion.hxx. + +library.hxx +library.cxx +  C++ types that represent the given vocabulary as well as Boost +  archive insertion and extraction operations. These are generated +  by the XSD compiler from library.xsd. The --hxx-prologue-file +  option is used to insert the contents of the library-prologue.hxx +  file into the generated header file. The --generate-insertion and +  --generate-extraction options are used to generate the insertion +  and extraction operations for text_oarchive and text_iarchive +  types. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input XML file. It then +  saves the object model to text_oarchive and loads it back from +  text_iarchive. Additionally, it prints the resulting text +  representation as well as the content of the object model before +  saving it to text_oarchive and after loading it from text_iarchive. + +To run the example on the sample XML instance document simply execute: + +$ ./driver library.xml diff --git a/xsd/examples/cxx/tree/binary/boost/boost-archive-extraction.hxx b/xsd/examples/cxx/tree/binary/boost/boost-archive-extraction.hxx new file mode 100644 index 0000000..8a1c1ef --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/boost-archive-extraction.hxx @@ -0,0 +1,188 @@ +// file      : examples/cxx/tree/binary/boost/boost-archive-insertion.cxx +// copyright : not copyrighted - public domain + +#ifndef BOOST_ARCHIVE_EXTRACTION_HXX +#define BOOST_ARCHIVE_EXTRACTION_HXX + +#include <cstddef> // std::size_t +#include <string> + +#include <xsd/cxx/tree/buffer.hxx> +#include <xsd/cxx/tree/istream.hxx> + +#include <boost/cstdint.hpp> + +namespace xsd +{ +  namespace cxx +  { +    namespace tree +    { +      // as_size +      // +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_size<T>& x) +      { +        std::size_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + +      // 8-bit +      // +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_int8<T>& x) +      { +        boost::int8_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_uint8<T>& x) +      { +        boost::uint8_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + + +      // 16-bit +      // +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_int16<T>& x) +      { +        boost::int16_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_uint16<T>& x) +      { +        boost::uint16_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + + +      // 32-bit +      // +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_int32<T>& x) +      { +        boost::int32_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_uint32<T>& x) +      { +        boost::uint32_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + + +      // 64-bit +      // +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_int64<T>& x) +      { +        boost::int64_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_uint64<T>& x) +      { +        boost::uint64_t r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + + +      // Boolean +      // +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_bool<T>& x) +      { +        bool r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + + +      // Floating-point +      // +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_float32<T>& x) +      { +        float r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + +      template <typename Archive, typename T> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, istream_common::as_float64<T>& x) +      { +        double r; +        s.impl () >> r; +        x.x_ = static_cast<T> (r); +        return s; +      } + +      // Extraction of std::basic_string. +      // + +      template <typename Archive, typename C> +      inline istream<Archive>& +      operator>> (istream<Archive>& s, std::basic_string<C>& x) +      { +        s.impl () >> x; +        return s; +      } + + +      // Extraction of a binary buffer. +      // +      template <typename Archive, typename C> +      istream<Archive>& +      operator>> (istream<Archive>& s, buffer<C>& x) +      { +        std::size_t size; +        s.impl () >> size; +        x.size (size); +        s.impl ().load_binary (x.data (), size); +        return s; +      } +    } +  } +} + +#endif // BOOST_ARCHIVE_EXTRACTION_HXX diff --git a/xsd/examples/cxx/tree/binary/boost/boost-archive-insertion.hxx b/xsd/examples/cxx/tree/binary/boost/boost-archive-insertion.hxx new file mode 100644 index 0000000..4c89104 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/boost-archive-insertion.hxx @@ -0,0 +1,177 @@ +// file      : examples/cxx/tree/binary/boost/boost-archive-insertion.cxx +// copyright : not copyrighted - public domain + +#ifndef BOOST_ARCHIVE_INSERTION_HXX +#define BOOST_ARCHIVE_INSERTION_HXX + +#include <cstddef> // std::size_t +#include <string> + +#include <xsd/cxx/tree/buffer.hxx> +#include <xsd/cxx/tree/ostream.hxx> + +#include <boost/cstdint.hpp> + +namespace xsd +{ +  namespace cxx +  { +    namespace tree +    { +      // as_size +      // +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_size<T> x) +      { +        std::size_t v (static_cast<std::size_t> (x.x_)); +        s.impl () << v; +        return s; +      } + +      // 8-bit +      // +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_int8<T> x) +      { +        boost::int8_t v (static_cast<boost::int8_t> (x.x_)); +        s.impl () << v; +        return s; +      } + +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_uint8<T> x) +      { +        boost::uint8_t v (static_cast<boost::uint8_t> (x.x_)); +        s.impl () << v; +        return s; +      } + + +      // 16-bit +      // +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_int16<T> x) +      { +        boost::int16_t v (static_cast<boost::int16_t> (x.x_)); +        s.impl () << v; +        return s; +      } + +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_uint16<T> x) +      { +        boost::uint16_t v (static_cast<boost::uint16_t> (x.x_)); +        s.impl () << v; +        return s; +      } + + +      // 32-bit +      // +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_int32<T> x) +      { +        boost::int32_t v (static_cast<boost::int32_t> (x.x_)); +        s.impl () << v; +        return s; +      } + +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_uint32<T> x) +      { +        boost::uint32_t v (static_cast<boost::uint32_t> (x.x_)); +        s.impl () << v; +        return s; +      } + + +      // 64-bit +      // +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_int64<T> x) +      { +        boost::int64_t v (static_cast<boost::int64_t> (x.x_)); +        s.impl () << v; +        return s; +      } + +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_uint64<T> x) +      { +        boost::uint64_t v (static_cast<boost::uint64_t> (x.x_)); +        s.impl () << v; +        return s; +      } + + +      // Boolean +      // +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_bool<T> x) +      { +        bool v (static_cast<bool> (x.x_)); +        s.impl () << v; +        return s; +      } + + +      // Floating-point +      // +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_float32<T> x) +      { +        float v (static_cast<float> (x.x_)); +        s.impl () << v; +        return s; +      } + +      template <typename Archive, typename T> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, ostream_common::as_float64<T> x) +      { +        double v (static_cast<double> (x.x_)); +        s.impl () << v; +        return s; +      } + + +      // Insertion of std::basic_string. +      // +      template <typename Archive, typename C> +      inline ostream<Archive>& +      operator<< (ostream<Archive>& s, const std::basic_string<C>& x) +      { +        s.impl () << x; +        return s; +      } + + +      // Insertion of a binary buffer. +      // +      template <typename Archive, typename C> +      ostream<Archive>& +      operator<< (ostream<Archive>& s, const buffer<C>& x) +      { +        // Boost.Serialization needs an lvalue. +        // +        std::size_t size (x.size()); +        s.impl () << size; +        s.impl ().save_binary (x.data (), x.size ()); +        return s; +      } +    } +  } +} + +#endif // BOOST_ARCHIVE_INSERTION_HXX diff --git a/xsd/examples/cxx/tree/binary/boost/driver.cxx b/xsd/examples/cxx/tree/binary/boost/driver.cxx new file mode 100644 index 0000000..df053b6 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/driver.cxx @@ -0,0 +1,72 @@ +// file      : examples/cxx/tree/binary/boost/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <cstring>  // std::memcpy +#include <sstream> +#include <iostream> + +// You can generate insertion/extraction code for other archive +// types (for example, binary, XML, etc). +// +#include <boost/archive/text_oarchive.hpp> +#include <boost/archive/text_iarchive.hpp> + +#include "library.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace library; +    using boost::archive::text_oarchive; +    using boost::archive::text_iarchive; + +    // Read in the file. +    // +    std::auto_ptr<catalog> c (catalog_ (argv[1])); + +    cerr << *c << endl; + +    // Save into a text archive. +    // +    std::ostringstream ostr; +    text_oarchive oa (ostr); +    xml_schema::ostream<text_oarchive> os (oa); + +    os << *c; + +    // Print the text representation. +    // +    std::string str (ostr.str ()); + +    cerr << endl +         << "text representation: " << endl +         << str << endl; + +    // Load from a text archive. +    // +    std::istringstream istr (str); +    text_iarchive ia (istr); +    xml_schema::istream<text_iarchive> is (ia); + +    std::auto_ptr<catalog> copy (new catalog (is)); + +    cerr << *copy << endl; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/binary/boost/library-prologue.hxx b/xsd/examples/cxx/tree/binary/boost/library-prologue.hxx new file mode 100644 index 0000000..ba0d35f --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/library-prologue.hxx @@ -0,0 +1,9 @@ +// Include declarations for the archive types. +// +#include <boost/archive/text_oarchive.hpp> +#include <boost/archive/text_iarchive.hpp> + +// Include insertion/extraction operators for fundamental types. +// +#include "boost-archive-insertion.hxx" +#include "boost-archive-extraction.hxx" diff --git a/xsd/examples/cxx/tree/binary/boost/library.xml b/xsd/examples/cxx/tree/binary/boost/library.xml new file mode 100644 index 0000000..ceb4443 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/binary/boost/library.xml +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"> +    <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/xsd/examples/cxx/tree/binary/boost/library.xsd b/xsd/examples/cxx/tree/binary/boost/library.xsd new file mode 100644 index 0000000..4bfdd1e --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/library.xsd @@ -0,0 +1,75 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/binary/boost/library.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:xse="http://www.codesynthesis.com/xmlns/xml-schema-extension" +            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:language"/> +      </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:date"/> +      <xsd:element name="died" type="xsd:date" minOccurs="0"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="author"> +    <xsd:complexContent> +      <xsd:extension base="lib:person"> +	<xsd:attribute name="recommends" type="xsd:IDREF" xse:refType="lib: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" default="true"/> +    <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/xsd/examples/cxx/tree/binary/boost/makefile b/xsd/examples/cxx/tree/binary/boost/makefile new file mode 100644 index 0000000..1ed7e41 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/boost/makefile @@ -0,0 +1,132 @@ +# file      : examples/cxx/tree/binary/boost/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := library.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +ifeq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(call import,\ +  $(scf_root)/import/libboost/serialization/stub.make,\ +  l: boost_serialization.l,cpp-options: boost_serialization.l.cpp-options) +endif + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) $(boost_serialization.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) $(boost_serialization.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd + +$(gen): xsd_options += --generate-ostream \ +--hxx-prologue-file $(src_base)/library-prologue.hxx \ +--generate-insertion boost::archive::text_oarchive \ +--generate-extraction boost::archive::text_iarchive + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) +	$(call install-data,$(src_base)/library-prologue.hxx,$(install_doc_dir)/xsd/$(path)/library-prologue.hxx) +	$(call install-data,$(src_base)/boost-archive-extraction.hxx,$(install_doc_dir)/xsd/$(path)/boost-archive-extraction.hxx) +	$(call install-data,$(src_base)/boost-archive-insertion.hxx,$(install_doc_dir)/xsd/$(path)/boost-archive-insertion.hxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) +	$(call install-data,$(src_base)/library-prologue.hxx,$(dist_prefix)/$(path)/library-prologue.hxx) +	$(call install-data,$(src_base)/boost-archive-extraction.hxx,$(dist_prefix)/$(path)/boost-archive-extraction.hxx) +	$(call install-data,$(src_base)/boost-archive-insertion.hxx,$(dist_prefix)/$(path)/boost-archive-insertion.hxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,boost-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,boost-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,boost-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,boost-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,boost-vc12.sln) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/binary/cdr/README b/xsd/examples/cxx/tree/binary/cdr/README new file mode 100644 index 0000000..914d27c --- /dev/null +++ b/xsd/examples/cxx/tree/binary/cdr/README @@ -0,0 +1,36 @@ +This example shows how to save/load the object model to/from CDR +(Common Data Representation) binary format using ACE CDR streams. +Support for other data representation streams can be easily added. You +will need the ACE library[1] installed in order to build and run this +example. + +[1] http://www.cs.wustl.edu/~schmidt/ACE.html + +The example consists of the following files: + +library.xsd +  XML Schema which describes a library of books. + +library.xml +  Sample XML instance document. + +library.hxx +library.cxx +  C++ types that represent the given vocabulary as well as data +  representation stream insertion and extraction operations. These +  are generated by XSD from library.xsd. Note that the +  --generate-insertion and --generate-extraction options are used +  to generate the insertion and extraction operations for ACE CDR +  stream. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input XML file. It then +  saves the object model to ACE_OuputCDR and loads it back from +  ACE_InputCDR. Additionally, it prints the resulting binary +  representation as well as the content of the object model before +  saving it to the CDR stream and after loading it from the CDR stream. + +To run the example on the sample XML instance document simply execute: + +$ ./driver library.xml diff --git a/xsd/examples/cxx/tree/binary/cdr/driver.cxx b/xsd/examples/cxx/tree/binary/cdr/driver.cxx new file mode 100644 index 0000000..ec1ff32 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/cdr/driver.cxx @@ -0,0 +1,87 @@ +// file      : examples/cxx/tree/binary/cdr/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <cstring>  // std::memcpy +#include <iostream> + +#include <ace/Log_Msg.h>   // ACE_HEX_DUMP +#include <ace/CDR_Stream.h> + +// The following two headers define XSD-specific insertion/extraction +// operations for ACE CDR streams. You can use the content of these +// headers as a guide to implementing insertion/extraction to/from +// your own data representation streams: +// +// xsd/cxx/tree/ace-cdr-stream-insertion.hxx +// xsd/cxx/tree/ace-cdr-stream-extraction.hxx + +#include "library.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace library; + +    // Read in the file. +    // +    std::auto_ptr<catalog> c (catalog_ (argv[1])); + +    cerr << *c << endl; + +    // Save to a CDR stream. +    // +    ACE_OutputCDR ace_ocdr; +    xml_schema::ostream<ACE_OutputCDR> ocdr (ace_ocdr); + +    ocdr << *c; + +    // Print the binary representation and at the same time save +    // it into a continuous buffer. +    // +    cerr << endl +         << "binary representation size: " << ace_ocdr.total_length () << endl; + +    xml_schema::buffer buf (ace_ocdr.total_length ()); +    char* data (buf.data ()); + +    for (const ACE_Message_Block* mb = ace_ocdr.begin (); +         mb != 0; +         mb = mb->cont ()) +    { +      std::memcpy (data, mb->rd_ptr (), mb->length ()); +      data += mb->length (); + +      ACE_HEX_DUMP ((LM_DEBUG, mb->rd_ptr (), mb->length ())); +    } + +    // Load from a CDR stream. Note that ACE_InputCDR expects the +    // buffer to be properly aligned. Since our buffer is dynamically +    // allocated, its alignment should be good enough. +    // +    ACE_InputCDR ace_icdr (buf.data (), buf.size ()); +    xml_schema::istream<ACE_InputCDR> icdr (ace_icdr); + +    std::auto_ptr<catalog> copy (new catalog (icdr)); + +    cerr << *copy << endl; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } + +  return 0; // ACE makes our main() an ordinary function. +} diff --git a/xsd/examples/cxx/tree/binary/cdr/library.xml b/xsd/examples/cxx/tree/binary/cdr/library.xml new file mode 100644 index 0000000..941c03f --- /dev/null +++ b/xsd/examples/cxx/tree/binary/cdr/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/binary/cdr/library.xml +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"> +    <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/xsd/examples/cxx/tree/binary/cdr/library.xsd b/xsd/examples/cxx/tree/binary/cdr/library.xsd new file mode 100644 index 0000000..5659e1b --- /dev/null +++ b/xsd/examples/cxx/tree/binary/cdr/library.xsd @@ -0,0 +1,75 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/binary/cdr/library.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:xse="http://www.codesynthesis.com/xmlns/xml-schema-extension" +            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:language"/> +      </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:date"/> +      <xsd:element name="died" type="xsd:date" minOccurs="0"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="author"> +    <xsd:complexContent> +      <xsd:extension base="lib:person"> +	<xsd:attribute name="recommends" type="xsd:IDREF" xse:refType="lib: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" default="true"/> +    <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/xsd/examples/cxx/tree/binary/cdr/makefile b/xsd/examples/cxx/tree/binary/cdr/makefile new file mode 100644 index 0000000..b349ba2 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/cdr/makefile @@ -0,0 +1,120 @@ +# file      : examples/cxx/tree/binary/cdr/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := library.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +ifeq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(call import,\ +  $(scf_root)/import/libace/stub.make,\ +  l: ace.l,cpp-options: ace.l.cpp-options) +endif + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) $(ace.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) $(ace.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-ostream \ +--generate-insertion ACE_OutputCDR --generate-extraction ACE_InputCDR +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,cdr-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,cdr-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,cdr-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,cdr-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,cdr-vc12.sln) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/binary/makefile b/xsd/examples/cxx/tree/binary/makefile new file mode 100644 index 0000000..eb4b312 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/makefile @@ -0,0 +1,56 @@ +# file      : examples/cxx/tree/binary/makefile +# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +all_examples   := boost cdr xdr +build_examples := + +ifeq ($(xsd_with_boost_serialization),y) +build_examples += boost +endif + +ifeq ($(xsd_with_ace),y) +build_examples += cdr +endif + +ifeq ($(xsd_with_xdr),y) +build_examples += xdr +endif + +default  := $(out_base)/ +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Build. +# +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples))) + +# Install & Dist. +# +$(install) $(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base)) + +$(install): $(addprefix $(out_base)/,$(addsuffix /.install,$(all_examples))) +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) + +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples))) + +$(call include,$(bld_root)/install.make) + +ifneq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile)) +else +$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile)) +endif diff --git a/xsd/examples/cxx/tree/binary/xdr/README b/xsd/examples/cxx/tree/binary/xdr/README new file mode 100644 index 0000000..22d5693 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/xdr/README @@ -0,0 +1,34 @@ +This example shows how to save/load the object model to/from XDR +(eXternal Data Representation) binary format using XDR streams. +The XDR API is available out of the box on most UNIX and GNU/Linux +systems as part of Sun RPC. On Windows you may need to install a +third-party library which provides the XDR API. + +The example consists of the following files: + +library.xsd +  XML Schema which describes a library of books. + +library.xml +  Sample XML instance document. + +library.hxx +library.cxx +  C++ types that represent the given vocabulary as well as data +  representation stream insertion and extraction operations. These +  are generated by XSD from library.xsd. Note that the +  --generate-insertion and --generate-extraction options are used +  to generate the insertion and extraction operations for XDR +  stream. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input XML file. It then +  saves the object model to the XDR representation and loads it back. +  Additionally, it prints the content of the object model before saving +  it to the XDR representation and after loading it from the XDR +  representation. + +To run the example on the sample XML instance document simply execute: + +$ ./driver library.xml diff --git a/xsd/examples/cxx/tree/binary/xdr/driver.cxx b/xsd/examples/cxx/tree/binary/xdr/driver.cxx new file mode 100644 index 0000000..d109322 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/xdr/driver.cxx @@ -0,0 +1,148 @@ +// file      : examples/cxx/tree/binary/xdr/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <cstring>  // std::memcpy +#include <cstddef>  // std::size_t +#include <iostream> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +#include "library.hxx" + +using std::cerr; +using std::endl; +using std::size_t; + +// XDR output functions. Their implementations are provided after main(). +// +struct underflow_info +{ +  xml_schema::buffer* buf; +  size_t pos; +}; + +extern "C" int +overflow (void* user_data, char* buf, int n); + +extern "C" int +underflow (void* user_data, char* buf, int n); + +// The xdrrec_create function (used below) has slightly different +// prototypes on different platforms. To make this example portable +// we will need to cast the actual function to the following common +// prototype. +// +extern "C" +typedef  void (*xdrrec_create_p) ( +  XDR*, +  unsigned int write_size, +  unsigned int read_size, +  void* user_data, +  int (*read) (void* user_data, char* buf, int n), +  int (*write) (void* user_data, char* buf, int n)); + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace library; + +    xdrrec_create_p xdrrec_create_ = +      reinterpret_cast<xdrrec_create_p> (::xdrrec_create); + +    // Read in the file. +    // +    std::auto_ptr<catalog> c (catalog_ (argv[1])); + +    cerr << *c << endl; + +    // Save to an XDR stream. +    // +    XDR xdr; +    xml_schema::buffer buf; + +    xdrrec_create_ (&xdr, 0, 0, reinterpret_cast<char*> (&buf), 0, &overflow); +    xdr.x_op = XDR_ENCODE; + +    xml_schema::ostream<XDR> oxdr (xdr); + +    oxdr << *c; + +    xdrrec_endofrecord (&xdr, true); // Flush the data. +    xdr_destroy (&xdr); + +    // The binary representation is now in the memory buffer 'buf'. +    // To get to the raw data use buf.data() and buf.size(). +    // +    cerr << endl +         << "binary representation size: " << buf.size () << endl; + +    // Load from an XDR stream. +    // +    underflow_info ui; +    ui.buf = &buf; +    ui.pos = 0; + +    xdrrec_create_ (&xdr, 0, 0, reinterpret_cast<char*> (&ui), &underflow, 0); +    xdr.x_op = XDR_DECODE; + +    xdrrec_skiprecord (&xdr); + +    xml_schema::istream<XDR> ixdr (xdr); + +    std::auto_ptr<catalog> copy (new catalog (ixdr)); + +    xdr_destroy (&xdr); + +    cerr << *copy << endl; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} + +extern "C" int +overflow (void* p, char* buf, int n_) +{ +  xml_schema::buffer* dst (reinterpret_cast<xml_schema::buffer*> (p)); +  size_t n (static_cast<size_t> (n_)); + +  size_t size (dst->size ()); +  size_t capacity (dst->capacity ()); + +  // Implement exponential growth. +  // +  if (size + n > capacity && size + n < capacity * 2) +    dst->capacity (capacity * 2); + +  dst->size (size + n); +  std::memcpy (dst->data () + size, buf, n); + +  return n; +} + +extern "C" int +underflow (void* p, char* buf, int n_) +{ +  underflow_info* ui (reinterpret_cast<underflow_info*> (p)); +  size_t n (static_cast<size_t> (n_)); + +  size_t size (ui->buf->size () - ui->pos); +  n = size > n ? n : size; + +  std::memcpy (buf, ui->buf->data () + ui->pos, n); +  ui->pos += n; + +  return n; +} diff --git a/xsd/examples/cxx/tree/binary/xdr/library.xml b/xsd/examples/cxx/tree/binary/xdr/library.xml new file mode 100644 index 0000000..dab6afb --- /dev/null +++ b/xsd/examples/cxx/tree/binary/xdr/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/binary/xdr/library.xml +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"> +    <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/xsd/examples/cxx/tree/binary/xdr/library.xsd b/xsd/examples/cxx/tree/binary/xdr/library.xsd new file mode 100644 index 0000000..7513e3b --- /dev/null +++ b/xsd/examples/cxx/tree/binary/xdr/library.xsd @@ -0,0 +1,75 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/binary/xdr/library.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:xse="http://www.codesynthesis.com/xmlns/xml-schema-extension" +            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:language"/> +      </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:date"/> +      <xsd:element name="died" type="xsd:date" minOccurs="0"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="author"> +    <xsd:complexContent> +      <xsd:extension base="lib:person"> +	<xsd:attribute name="recommends" type="xsd:IDREF" xse:refType="lib: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" default="true"/> +    <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/xsd/examples/cxx/tree/binary/xdr/makefile b/xsd/examples/cxx/tree/binary/xdr/makefile new file mode 100644 index 0000000..7939b29 --- /dev/null +++ b/xsd/examples/cxx/tree/binary/xdr/makefile @@ -0,0 +1,114 @@ +# file      : examples/cxx/tree/binary/xdr/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := library.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +# Build. +# +$(driver): $(obj) $(xerces_c.l) -lnsl + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-ostream \ +--generate-insertion XDR --generate-extraction XDR +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,xdr-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,xdr-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,xdr-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,xdr-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,xdr-vc12.sln) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/caching/README b/xsd/examples/cxx/tree/caching/README new file mode 100644 index 0000000..64e5a1a --- /dev/null +++ b/xsd/examples/cxx/tree/caching/README @@ -0,0 +1,29 @@ +This example shows how to use the C++/Tree mapping to parse several +XML documents while reusing the underlying XML parser and caching the +schemas used for validation. + +The example consists of the following files: + +library.xsd +  XML Schema which describes a library of books. + +library.xml +  Sample XML instance document. + +library.hxx +library.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by XSD from library.xsd. + +driver.cxx +  Driver for the example. It first sets up the Xerces-C++ DOM parser +  and caches the library.xsd schema for validation. It then performs +  ten iterations that parse the input file to a DOM document using +  the DOM parser and call one of the parsing functions that constructs +  the object model from this DOM document. On each iteration the driver +  prints a number of books in the object model to STDERR. + +To run the example on the sample XML instance document simply execute: + +$ ./driver library.xml diff --git a/xsd/examples/cxx/tree/caching/driver.cxx b/xsd/examples/cxx/tree/caching/driver.cxx new file mode 100644 index 0000000..2aa9396 --- /dev/null +++ b/xsd/examples/cxx/tree/caching/driver.cxx @@ -0,0 +1,165 @@ +// file      : examples/cxx/tree/caching/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <fstream> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/XMLUniDefs.hpp> // chLatin_* +#include <xercesc/util/PlatformUtils.hpp> +#include <xercesc/validators/common/Grammar.hpp> // xercesc::Grammar +#include <xercesc/framework/Wrapper4InputSource.hpp> + +#include <xsd/cxx/xml/dom/auto-ptr.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> +#include <xsd/cxx/xml/sax/std-input-source.hxx> + +#include <xsd/cxx/tree/error-handler.hxx> + +#include "library.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml" << endl; +    return 1; +  } + +  int r (0); + +  // We need to initialize the Xerces-C++ runtime because we +  // are doing the XML-to-DOM parsing ourselves. +  // +  xercesc::XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace xercesc; +    namespace xml = xsd::cxx::xml; +    namespace tree = xsd::cxx::tree; + +    const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; + +    // Get an implementation of the Load-Store (LS) interface. +    // +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls_id)); + +    xml::dom::auto_ptr<DOMLSParser> parser ( +      impl->createLSParser (DOMImplementationLS::MODE_SYNCHRONOUS, 0)); + +    DOMConfiguration* conf (parser->getDomConfig ()); + +    // Discard comment nodes in the document. +    // +    conf->setParameter (XMLUni::fgDOMComments, false); + +    // Enable datatype normalization. +    // +    conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); + +    // Do not create EntityReference nodes in the DOM tree. No +    // EntityReference nodes will be created, only the nodes +    // corresponding to their fully expanded substitution text +    // will be created. +    // +    conf->setParameter (XMLUni::fgDOMEntities, false); + +    // Perform namespace processing. +    // +    conf->setParameter (XMLUni::fgDOMNamespaces, true); + +    // Do not include ignorable whitespace in the DOM tree. +    // +    conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); + +    // Enable validation. +    // +    conf->setParameter (XMLUni::fgDOMValidate, true); +    conf->setParameter (XMLUni::fgXercesSchema, true); +    conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); + +    // Xerces-C++ 3.1.0 is the first version with working multi import +    // support. +    // +#if _XERCES_VERSION >= 30100 +    conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +    // Set error handler. +    // +    tree::error_handler<char> eh; +    xml::dom::bits::error_handler_proxy<char> ehp (eh); +    conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +    // Initialize the schema cache. +    // +    if (!parser->loadGrammar ("library.xsd", Grammar::SchemaGrammarType, true)) +    { +      // In Xerces-C++ grammar loading failure results in just a warning. +      // Make it a fatal error. +      // +      eh.handle ("library.xsd", 0, 0, +                 tree::error_handler<char>::severity::fatal, +                 "unable to load schema"); +    } + +    eh.throw_if_failed<xml_schema::parsing> (); + +    // Use the loaded grammar during parsing. +    // +    conf->setParameter (XMLUni::fgXercesUseCachedGrammarInParse, true); + +    // Disable loading schemas via other means (e.g., schemaLocation). +    // +    conf->setParameter (XMLUni::fgXercesLoadSchema, false); + +    // We will release the DOM document ourselves. +    // +    conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + +    // Parse XML documents. +    // +    for (unsigned long i (0); i < 10; ++i) +    { +      ifstream ifs; +      ifs.exceptions (ifstream::badbit | ifstream::failbit); +      ifs.open (argv[1]); + +      // Wrap the standard input stream. +      // +      xml::sax::std_input_source isrc (ifs, argv[1]); +      Wrapper4InputSource wrap (&isrc, false); + +      // Parse XML to DOM. +      // +      xml_schema::dom::auto_ptr<DOMDocument> doc (parser->parse (&wrap)); + +      eh.throw_if_failed<xml_schema::parsing> (); + +      // Parse DOM to the object model. +      // +      auto_ptr<library::catalog> c (library::catalog_ (*doc)); + +      cerr << "catalog with " << c->book ().size () << " books" << endl; +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    r = 1; +  } + +  xercesc::XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/caching/library.xml b/xsd/examples/cxx/tree/caching/library.xml new file mode 100644 index 0000000..6d4d6f1 --- /dev/null +++ b/xsd/examples/cxx/tree/caching/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/caching/library.xml +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"> +    <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/xsd/examples/cxx/tree/caching/library.xsd b/xsd/examples/cxx/tree/caching/library.xsd new file mode 100644 index 0000000..a46c558 --- /dev/null +++ b/xsd/examples/cxx/tree/caching/library.xsd @@ -0,0 +1,72 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/caching/library.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:xse="http://www.codesynthesis.com/xmlns/xml-schema-extension" +            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:language"/> +      </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:date"/> +      <xsd:element name="died" type="xsd:date" minOccurs="0"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="author"> +    <xsd:complexContent> +      <xsd:extension base="lib:person"> +	<xsd:attribute name="recommends" type="xsd:IDREF" xse:refType="lib: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" default="true"/> +    <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/xsd/examples/cxx/tree/caching/makefile b/xsd/examples/cxx/tree/caching/makefile new file mode 100644 index 0000000..cb9b191 --- /dev/null +++ b/xsd/examples/cxx/tree/caching/makefile @@ -0,0 +1,101 @@ +# file      : examples/cxx/tree/caching/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := library.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/compression/README b/xsd/examples/cxx/tree/compression/README new file mode 100644 index 0000000..f163970 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/README @@ -0,0 +1,48 @@ +This example shows how to compress an XML document during serialization  +and decompress it during parsing. The example uses the compression  +functionality provided by the zlib library[1] which needs to be installed +in order to build and run this example. It should also be fairly straight- +forward to modify the code in this example to use other compression  +libraries. + +[1] http://www.zlib.net + +The example consists of the following files: + +library.xsd +  XML Schema which describes a library of books. + +library.xml.gz +  Sample XML instance document compressed using the gzip format. + +compressed-format-target.hxx +compressed-format-target.cxx +  Implementation of the Xerces-C++ XMLFormatTarget interface with the on- +  the-fly compression support. You can use it in your application to add +  XML compression. + +compressed-input-source.hxx +compressed-input-source.cxx +  Implementation of the Xerces-C++ InputSource interface with the on-the- +  fly decompression support. You can use it in your application to add +  XML decompression. + +library.hxx +library.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by XSD from library.xsd. + +driver.cxx +  Driver for the example. It first creates the compressed_input_source  +  object and passes it to one of the parsing functions that constructs  +  the object model from the compressed input file. It then prints the  +  content of the object model to STDERR. Finally, the driver creates the  +  compressed_format_target object and passes it to one of the serialization +  functions which converts the object model back to the compressed XML. + +To run the example on the sample XML document simply execute: + +$ ./driver library.xml.gz + +The serialization output is written to the out.xml.gz file. diff --git a/xsd/examples/cxx/tree/compression/compressed-format-target.cxx b/xsd/examples/cxx/tree/compression/compressed-format-target.cxx new file mode 100644 index 0000000..1f183e2 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/compressed-format-target.cxx @@ -0,0 +1,152 @@ +// file      : examples/cxx/tree/compression/compressed-format-target.cxx +// copyright : not copyrighted - public domain + +#include <ostream> +#include <cstring> // std::memcpy + +#include "compressed-format-target.hxx" + +using namespace std; + +// +// compression_failure +// + +const char* compression_failure:: +what () const throw () +{ +  return "compression failure"; +} + +// +// compressed_format_target +// + +compressed_format_target:: +compressed_format_target (ostream& os, compression_type t) +    : os_ (os), closed_ (false), n_ (0) +  { +    zs_.zalloc = Z_NULL; +    zs_.zfree  = Z_NULL; +    zs_.opaque = Z_NULL; + +    int window = 0; + +    switch (t) +    { +    case raw: +      { +        window = -15; +        break; +      } +    case zlib: +      { +        window = 15; +        break; +      } +    case gzip: +      { +        window = 16 + 15; +        break; +      } +    } + +    int r (deflateInit2 (&zs_, +                         Z_DEFAULT_COMPRESSION, +                         Z_DEFLATED, +                         window, +                         8, +                         Z_DEFAULT_STRATEGY)); +    if (r != Z_OK) +      throw compression_failure (r); +  } + +compressed_format_target:: +~compressed_format_target () +{ +  try +  { +    // Close the free the compression stream. +    // +    if (!closed_) +      close (); +  } +  catch (...) +  { +  } + +  deflateEnd (&zs_); +} + +void compressed_format_target:: +writeChars (const XMLByte* const buf, +            const XMLSize_t size, +            xercesc::XMLFormatter* const) +{ +  // Flush the buffer if the block is too large or if we don't have +  // any space left. +  // +  if ((size >= buf_size_ / 8 || n_ + size > buf_size_) && n_ != 0) +  { +    write (in_, n_); +    n_ = 0; +  } + +  if (size < buf_size_ / 8) +  { +    memcpy (in_ + n_, reinterpret_cast<const char*> (buf), size); +    n_ += size; +  } +  else +    write (reinterpret_cast<const char*> (buf), size); +} + + +void compressed_format_target:: +flush () +{ +  if (n_ != 0) +  { +    write (in_, n_); +    n_ = 0; +  } + +  if (!os_.fail ()) +    os_.flush (); +} + +void compressed_format_target:: +close () +{ +  write (in_, n_, true); +  n_ = 0; + +  if (!os_.fail ()) +    os_.flush (); + +  closed_ = true; +} + +void compressed_format_target:: +write (const char* buf, size_t size, bool flush) +{ +  zs_.next_in = reinterpret_cast<Bytef*> (const_cast<char*> (buf)); +  zs_.avail_in = static_cast<uInt> (size); + +  do +  { +    zs_.next_out = reinterpret_cast<Bytef*> (out_); +    zs_.avail_out = buf_size_; + +    int r (deflate (&zs_, flush ? Z_FINISH : Z_NO_FLUSH)); + +    if (r != Z_OK && r != Z_BUF_ERROR && r != Z_STREAM_END) +      throw compression_failure (r); + +    size_t n (buf_size_ - zs_.avail_out); + +    if (!os_.fail () && n > 0) +      os_.write (out_, static_cast<streamsize> (n)); + +  } while (zs_.avail_out == 0); +} diff --git a/xsd/examples/cxx/tree/compression/compressed-format-target.hxx b/xsd/examples/cxx/tree/compression/compressed-format-target.hxx new file mode 100644 index 0000000..835b676 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/compressed-format-target.hxx @@ -0,0 +1,91 @@ +// file      : examples/cxx/tree/compression/compressed-format-target.hxx +// copyright : not copyrighted - public domain + +#ifndef COMPRESSED_FORMAT_TARGET_HXX +#define COMPRESSED_FORMAT_TARGET_HXX + +#include <zlib.h> + +#include <iosfwd> +#include <cstddef>   // std::size_t +#include <exception> + +#include <xercesc/framework/XMLFormatter.hpp> + +struct compression_failure: std::exception +{ +  explicit +  compression_failure (int code) +      : code_ (code) +  { +  } + +  int +  code () const +  { +    return code_; +  } + +  const char* +  message () const +  { +    return zError (code_); +  } + +  virtual const char* +  what () const throw (); + +private: +  int code_; +}; + +// Xerces-C++ XMLFormatTarget interface implementation with on-the-fly, +// zlib-based compression. +// +class compressed_format_target: public xercesc::XMLFormatTarget +{ +public: +  enum compression_type +  { +    raw, +    zlib, +    gzip +  }; + +  compressed_format_target (std::ostream&, compression_type); + +  virtual +  ~compressed_format_target (); + +  virtual void +  writeChars (const XMLByte* const buf, +              const XMLSize_t size, +              xercesc::XMLFormatter* const); + +  virtual void +  flush (); + +  // Close the compressed stream by writing out the zlib or gzip trailer. +  // This function is automatically called from the destructor but you +  // may want to call it explicitly to be able to catch any exceptions +  // that it might throw. +  // +  void +  close (); + +private: +  void +  write (const char* buf, std::size_t size, bool flush = false); + +private: +  std::ostream& os_; +  z_stream zs_; +  bool closed_; + +  static const std::size_t buf_size_ = 65536; +  char in_[buf_size_]; +  char out_[buf_size_]; +  size_t n_; +}; + +#endif // COMPRESSED_FORMAT_TARGET_HXX diff --git a/xsd/examples/cxx/tree/compression/compressed-input-source.cxx b/xsd/examples/cxx/tree/compression/compressed-input-source.cxx new file mode 100644 index 0000000..e25b169 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/compressed-input-source.cxx @@ -0,0 +1,195 @@ +// file      : examples/cxx/tree/compression/compressed-input-source.cxx +// copyright : not copyrighted - public domain + +#include <istream> + +#include <xsd/cxx/xml/string.hxx> + +#include "compressed-input-source.hxx" + +using namespace std; +using namespace xercesc; +namespace xml = xsd::cxx::xml; + +// +// decompression_failure +// + +const char* decompression_failure:: +what () const throw () +{ +  return "decompression failure"; +} + +// +// compressed_input_source +// + +compressed_input_source:: +compressed_input_source (istream& is, compression_type t) +    : is_ (&is), type_ (t) +{ +} + +compressed_input_source:: +compressed_input_source (istream& is, +                         compression_type t, +                         const string& sysid) +    : InputSource (xml::string (sysid).c_str ()), is_ (&is), type_ (t) +{ +} + +compressed_input_source:: +compressed_input_source (istream& is, +                         compression_type t, +                         const string& sysid, +                         const string& pubid) +    : xercesc::InputSource (xml::string (sysid).c_str (), +                            xml::string (pubid).c_str ()), +      is_ (&is), +      type_ (t) +{ +} + +BinInputStream* compressed_input_source:: +makeStream () const +{ +  if (is_ == 0) +    throw copy (); + +  istream& is (*is_); +  is_ = 0; +  return new compressed_input_stream ( +    is, static_cast<compressed_input_stream::compression_type> (type_)); +} + +// +// compressed_input_stream +// + +compressed_input_stream:: +compressed_input_stream (istream& is, compression_type t) +    : is_ (is), end_ (false), pos_ (0) +{ +  zs_.zalloc = Z_NULL; +  zs_.zfree  = Z_NULL; +  zs_.opaque = Z_NULL; +  zs_.next_in = Z_NULL; +  zs_.avail_in = 0; + +  int window = 0; + +  switch (t) +  { +  case raw: +    { +      window = -15; +      break; +    } +  case zlib: +    { +      window = 15; +      break; +    } +  case gzip: +    { +      window = 16 + 15; +      break; +    } +  } + +  int r (inflateInit2 (&zs_, window)); + +  if (r != Z_OK) +    throw decompression_failure (r); +} + +compressed_input_stream:: +~compressed_input_stream () +{ +  inflateEnd (&zs_); +} + +XMLFilePos compressed_input_stream:: +curPos () const +{ +  return static_cast<XMLFilePos> (pos_); +} + +XMLSize_t compressed_input_stream:: +readBytes (XMLByte* const buf, const XMLSize_t size) +{ +  if (end_) +    return 0; + +  // Keep calling inflate() until we fill up the buffer or reach the +  // end of stream. If we run out of input data, call the underlying +  // stream for more. +  // +  zs_.next_out = reinterpret_cast<Bytef*> (buf); +  zs_.avail_out = static_cast<uInt> (size); + +  int r; + +  do +  { +    if (zs_.avail_in == 0) +    { +      zs_.avail_in = static_cast<uInt> (read ()); +      zs_.next_in = reinterpret_cast<Bytef*> (const_cast<char*> (in_)); + +      if (zs_.avail_in == 0) +        throw decompression_failure (Z_DATA_ERROR); +    } + +    r = inflate (&zs_, Z_NO_FLUSH); + +    if (r != Z_OK && r != Z_STREAM_END) +      throw decompression_failure (r); + +  } while (r != Z_STREAM_END && zs_.avail_out != 0); + +  if (r == Z_STREAM_END) +    end_ = true; + +  size_t n (size - zs_.avail_out); +  pos_ += n; + +  return static_cast<XMLSize_t> (n); +} + +const XMLCh* compressed_input_stream:: +getContentType () const +{ +  return 0; +} + +size_t compressed_input_stream:: +read () +{ +  // Some implementations don't clear gcount if you call read() on a +  // stream that is in the eof state. +  // +  if (is_.eof ()) +    return 0; + +  // Unset the exception failbit while we are working with the stream. +  // +  ios_base::iostate old (is_.exceptions ()); +  is_.exceptions (old & ~ios_base::failbit); + +  is_.read (in_, static_cast<streamsize> (buf_size_)); + +  // Clear the fail bit if it was caused by eof and restore the original +  // exception state. If there are any pending errors then the exception +  // will be thrown now. +  // +  if (is_.fail () && is_.eof ()) +    is_.clear (is_.rdstate () & ~ios_base::failbit); + +  is_.exceptions (old); + +  // Make sure that if we failed, we won't be called again. +  // +  return !is_.fail () ? static_cast<size_t> (is_.gcount ()) : 0; +} diff --git a/xsd/examples/cxx/tree/compression/compressed-input-source.hxx b/xsd/examples/cxx/tree/compression/compressed-input-source.hxx new file mode 100644 index 0000000..8065445 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/compressed-input-source.hxx @@ -0,0 +1,121 @@ +// file      : examples/cxx/tree/compression/compressed-input-source.hxx +// copyright : not copyrighted - public domain + +#ifndef COMPRESSED_INPUT_SOURCE_HXX +#define COMPRESSED_INPUT_SOURCE_HXX + +#include <zlib.h> + +#include <iosfwd> +#include <string> +#include <cstddef>   // std::size_t +#include <exception> + +#include <xercesc/sax/InputSource.hpp> +#include <xercesc/util/BinInputStream.hpp> + +struct decompression_failure: std::exception +{ +  explicit +  decompression_failure (int code) +      : code_ (code) +  { +  } + +  int +  code () const +  { +    return code_; +  } + +  const char* +  message () const +  { +    return zError (code_); +  } + +  virtual const char* +  what () const throw (); + +private: +  int code_; +}; + +// Xerces-C++ InputSource interface implementation with on-the-fly, zlib- +// based decompression. +// +class compressed_input_source: public xercesc::InputSource +{ +public: +  enum compression_type +  { +    raw, +    zlib, +    gzip +  }; + +  compressed_input_source (std::istream&, compression_type); + +  compressed_input_source (std::istream&, +                           compression_type, +                           const std::string& system_id); + +  compressed_input_source (std::istream&, +                           compression_type, +                           const std::string& system_id, +                           const std::string& public_id); + +  struct copy {}; + +  // Throws the copy exception if this function is called more than once. +  // +  virtual xercesc::BinInputStream* +  makeStream () const; + +private: +  mutable std::istream* is_; +  compression_type type_; +}; + +// Xerces-C++ BinInputStream interface implementation with on-the-fly, zlib- +// based decompression. +// +class compressed_input_stream: public xercesc::BinInputStream +{ +public: +  enum compression_type +  { +    raw, +    zlib, +    gzip +  }; + +  compressed_input_stream (std::istream&, compression_type); + +  virtual +  ~compressed_input_stream (); + +  virtual XMLFilePos +  curPos () const; + +  virtual XMLSize_t +  readBytes (XMLByte* const buf, const XMLSize_t size); + +  virtual const XMLCh* +  getContentType () const; + +private: +  std::size_t +  read (); + +private: +  std::istream& is_; +  z_stream zs_; +  bool end_; + +  static const std::size_t buf_size_ = 65536; +  char in_[buf_size_]; +  std::size_t pos_; // Current decompressed stream position. +}; + +#endif // COMPRESSED_INPUT_SOURCE_HXX diff --git a/xsd/examples/cxx/tree/compression/driver.cxx b/xsd/examples/cxx/tree/compression/driver.cxx new file mode 100644 index 0000000..34238b1 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/driver.cxx @@ -0,0 +1,124 @@ +// file      : examples/cxx/tree/compression/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <fstream> +#include <iostream> + +#include <xercesc/util/PlatformUtils.hpp> + +#include "library.hxx" + +#include "compressed-input-source.hxx" +#include "compressed-format-target.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml.gz" << endl; +    return 1; +  } + +  int r (0); + +  // We need to initialize the Xerces-C++ runtime because we are +  // using the Xerces-C++ input/output interfaces. +  // +  xercesc::XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace library; + +    // Read in the XML file and obtain its object model. +    // +    ifstream ifs; +    ifs.exceptions (ifstream::badbit | ifstream::failbit); +    ifs.open (argv[1], ifstream::in | ifstream::binary); + +    compressed_input_source cis (ifs, compressed_input_source::gzip, argv[1]); + +    std::auto_ptr<catalog> c ( +      catalog_ (cis, xml_schema::flags::dont_initialize)); + + +    // Let's print what we've got. +    // +    for (catalog::book_const_iterator bi (c->book ().begin ()); +         bi != c->book ().end (); +         ++bi) +    { +      cerr << endl +           << "ID           : " << bi->id () << endl +           << "ISBN         : " << bi->isbn () << endl +           << "Title        : " << bi->title () << endl +           << "Genre        : " << bi->genre () << endl; + +      for (book::author_const_iterator ai (bi->author ().begin ()); +           ai != bi->author ().end (); +           ++ai) +      { +        cerr << "Author       : " << ai->name () << endl; +        cerr << "  Born       : " << ai->born () << endl; + +        if (ai->died ()) +          cerr << "  Died       : " << *ai->died () << endl; + +        if (ai->recommends ()) +          cerr << "  Recommends : " << (*ai->recommends ())->title () << endl; +      } + +      cerr  << "Available    : " << std::boolalpha << bi->available () << endl; +    } + +    // Prepare namespace mapping and schema location information. +    // +    xml_schema::namespace_infomap map; + +    map["lib"].name = "http://www.codesynthesis.com/library"; +    map["lib"].schema = "library.xsd"; + +    ofstream ofs; +    ofs.exceptions (ofstream::badbit | ofstream::failbit | ofstream::eofbit); +    ofs.open ("out.xml.gz", ofstream::out | ofstream::binary); + +    compressed_format_target cft (ofs, compressed_format_target::gzip); + +    // Write it out. +    // +    catalog_ (cft, *c, map, "UTF-8", xml_schema::flags::dont_initialize); + +    // Write out the compression stream trailer. If we don't do this +    // explicitly, it will be done automatically in the cft's destructor +    // but then any exceptions that might be throws will be ignored. +    // +    cft.close(); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const compression_failure& e) +  { +    cerr << "compression failure: " << e.message () << endl; +    r = 1; +  } +  catch (const decompression_failure& e) +  { +    cerr << "decompression failure: " << e.message () << endl; +    r = 1; +  } +  catch (const ios_base::failure&) +  { +    cerr << "file open or read/write failure" << endl; +    r = 1; +  } + +  xercesc::XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/compression/library.xml.gz b/xsd/examples/cxx/tree/compression/library.xml.gz Binary files differnew file mode 100644 index 0000000..dd71159 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/library.xml.gz diff --git a/xsd/examples/cxx/tree/compression/library.xsd b/xsd/examples/cxx/tree/compression/library.xsd new file mode 100644 index 0000000..728acc7 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/library.xsd @@ -0,0 +1,72 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/compression/library.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:xse="http://www.codesynthesis.com/xmlns/xml-schema-extension" +            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:language"/> +      </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:date"/> +      <xsd:element name="died" type="xsd:date" minOccurs="0"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="author"> +    <xsd:complexContent> +      <xsd:extension base="lib:person"> +	<xsd:attribute name="recommends" type="xsd:IDREF" xse:refType="lib: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" default="true"/> +    <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/xsd/examples/cxx/tree/compression/makefile b/xsd/examples/cxx/tree/compression/makefile new file mode 100644 index 0000000..43913f7 --- /dev/null +++ b/xsd/examples/cxx/tree/compression/makefile @@ -0,0 +1,128 @@ +# file      : examples/cxx/tree/compression/makefile +# copyright : Copyright (c) 2005-2014 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 compressed-input-source.cxx compressed-format-target.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +ifeq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(call import,\ +  $(scf_root)/import/libz/stub.make,\ +  l: z.l,cpp-options: z.l.cpp-options) +endif + +# Build. +# +$(driver): $(obj) $(xerces_c.l) $(z.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) $(z.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-ostream --generate-serialization +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/compressed-format-target.hxx,$(install_doc_dir)/xsd/$(path)/compressed-format-target.hxx) +	$(call install-data,$(src_base)/compressed-format-target.cxx,$(install_doc_dir)/xsd/$(path)/compressed-format-target.cxx) +	$(call install-data,$(src_base)/compressed-input-source.hxx,$(install_doc_dir)/xsd/$(path)/compressed-input-source.hxx) +	$(call install-data,$(src_base)/compressed-input-source.cxx,$(install_doc_dir)/xsd/$(path)/compressed-input-source.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml.gz,$(install_doc_dir)/xsd/$(path)/library.xml.gz) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/compressed-format-target.hxx,$(dist_prefix)/$(path)/compressed-format-target.hxx) +	$(call install-data,$(src_base)/compressed-format-target.cxx,$(dist_prefix)/$(path)/compressed-format-target.cxx) +	$(call install-data,$(src_base)/compressed-input-source.hxx,$(dist_prefix)/$(path)/compressed-input-source.hxx) +	$(call install-data,$(src_base)/compressed-input-source.cxx,$(dist_prefix)/$(path)/compressed-input-source.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml.gz,$(dist_prefix)/$(path)/library.xml.gz) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,compression-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,compression-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,compression-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,compression-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,compression-vc12.sln) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) +	$(call message,rm $$1,rm -f $$1,$(out_base)/out.xml.gz) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver out.xml.gz $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/README b/xsd/examples/cxx/tree/custom/README new file mode 100644 index 0000000..b2a65b5 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/README @@ -0,0 +1,40 @@ +This directory contains a number of examples that show how to customize the +C++/Tree mapping. The following list gives an overview of each example: + +calendar +  Shows how to customize XML Schema built-in types by mapping xsd:date +  built-in type to the date class from the Boost date_time library. + +comments +  This example shows how to customize the anyType XML Schema built-in +  type to implement preservation of comments stored in XML documents. +  Because anyType is a base type for every generated type, you can use +  this technique to implement custom functionality that spans the +  entire type system. + +contacts +  Shows how to map a user-defined XML Schema type to a custom C++ class. +  This example presents the simple case where the customized type is not +  used as a base in the same schema. + +double +  Shows how to customize parsing and serialization code for the xsd:double +  XML Schema built-in type. It can be used as a guide on how to customize +  built-in XML Schema types that are mapped to fundamental C++ types. + +mixed +  Shows how to use type customization to parse and serialize mixed content. + +taxonomy +  Shows how to map user-defined XML Schema types to custom C++ classes. +  This example presents the complex case where the customized types are +  inherited from in the same schema. + +wildcard +  Shows how to use type customization to parse and serialize a specific +  attribute that is matched by a wildcard (anyAttribute). + +For more information on the C++/Tree mapping customization see the +C++/Tree Mapping Customization Guide[1]. + +[1] http://wiki.codesynthesis.com/Tree/Customization_guide diff --git a/xsd/examples/cxx/tree/custom/calendar/README b/xsd/examples/cxx/tree/custom/calendar/README new file mode 100644 index 0000000..f7f6989 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/calendar/README @@ -0,0 +1,47 @@ +This example shows how to customize the XML Schema built-in types by mapping +xsd:date built-in type to the date class from the Boost date_time library. +You will need the Boost date_time library[1] installed in order to build +and run this example. For more information on the C++/Tree mapping +customization see the C++/Tree Mapping Customization Guide[2]. + +[1] http://www.boost.org +[2] http://wiki.codesynthesis.com/Tree/Customization_guide + +The example consists of the following files: + +calendar.xsd +  XML Schema definition for a simple calendar format. + +calendar.xml +  Sample XML instance document. + +xml-schema.hxx +  C++ types for XML Schema built-in types. This header file is generated +  by XSD using the --generate-xml-schema option. The --custom-type option +  is also used to customize the xsd:date type. + +calendar.hxx +calendar.ixx +calendar.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by XSD from calendar.xsd with the +  --extern-xml-schema option in order to include xml-schema.hxx. + +xml-schema-custom.hxx +  Header file which defines our own xml_schema::date class. It is +  included at the end of xml-schema.hxx using the --hxx-epilogue +  option. + +xml-schema-custom.cxx +  Source file which contains the implementation of our xml_schema:date +  class. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the calendar events to STDERR. + +To run the example on the sample XML instance document simply execute: + +$ ./driver calendar.xml diff --git a/xsd/examples/cxx/tree/custom/calendar/calendar.xml b/xsd/examples/cxx/tree/custom/calendar/calendar.xml new file mode 100644 index 0000000..5cc898a --- /dev/null +++ b/xsd/examples/cxx/tree/custom/calendar/calendar.xml @@ -0,0 +1,22 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/calendar/calendar.xml +copyright : not copyrighted - public domain + +--> + +<cal:events xmlns:cal="http://www.codesynthesis.com/calendar" +	     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	     xsi:schemaLocation="http://www.codesynthesis.com/calendar calendar.xsd"> + +  <event title="Bike ride" date="2006-09-04"> +  Don't forget to change the tire. +  </event> + +  <event title="Mountain hike" date="2006-09-05"> +  Can be cancelled if it is too cold. +  </event> + +</cal:events> diff --git a/xsd/examples/cxx/tree/custom/calendar/calendar.xsd b/xsd/examples/cxx/tree/custom/calendar/calendar.xsd new file mode 100644 index 0000000..04b3af1 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/calendar/calendar.xsd @@ -0,0 +1,31 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/calendar/calendar.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:cal="http://www.codesynthesis.com/calendar" +            targetNamespace="http://www.codesynthesis.com/calendar"> + +  <xsd:complexType name="event"> +    <xsd:simpleContent> +      <xsd:extension base="xsd:string"> +        <xsd:attribute name="title" type="xsd:string" use="required"/> +        <xsd:attribute name="date" type="xsd:date" use="required"/> +      </xsd:extension> +    </xsd:simpleContent> +  </xsd:complexType> + +  <xsd:complexType name="events"> +    <xsd:sequence> +      <xsd:element name="event" type="cal:event" maxOccurs="unbounded"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:element name="events" type="cal:events"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/custom/calendar/driver.cxx b/xsd/examples/cxx/tree/custom/calendar/driver.cxx new file mode 100644 index 0000000..a5b223e --- /dev/null +++ b/xsd/examples/cxx/tree/custom/calendar/driver.cxx @@ -0,0 +1,39 @@ +// file      : examples/cxx/tree/custom/calendar/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "calendar.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " calendar.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace calendar; + +    std::auto_ptr<events> e (events_ (argv[1])); + +    for (events::event_const_iterator i (e->event ().begin ()); +         i != e->event ().end (); ++i) +    { +      cerr << i->date () << " " << i->title () << endl +           << *i << endl; +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/custom/calendar/makefile b/xsd/examples/cxx/tree/custom/calendar/makefile new file mode 100644 index 0000000..6998ffd --- /dev/null +++ b/xsd/examples/cxx/tree/custom/calendar/makefile @@ -0,0 +1,137 @@ +# file      : examples/cxx/tree/custom/calendar/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := calendar.xsd +cxx := driver.cxx xml-schema-custom.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +ifeq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(call import,\ +  $(scf_root)/import/libboost/date-time/stub.make,\ +  l: boost_date_time.l,cpp-options: boost_date_time.l.cpp-options) +endif + +# Build. +# +$(driver): $(obj) $(xerces_c.l) $(boost_date_time.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) $(boost_date_time.l.cpp-options) + +# Header file for XML Schema namespace. +# +$(out_base)/xml-schema.hxx: $(out_root)/xsd/xsd +	$(call message,xsd $(src_base)/xml-schema.xsd,\ +$(out_root)/xsd/xsd cxx-tree --output-dir $(out_base) --generate-xml-schema \ +--custom-type date \ +--hxx-epilogue '#include "xml-schema-custom.hxx"' xml-schema.xsd) + +# +# +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += \ +--generate-inline \ +--extern-xml-schema xml-schema.xsd + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/calendar.xsd,$(install_doc_dir)/xsd/$(path)/calendar.xsd) +	$(call install-data,$(src_base)/calendar.xml,$(install_doc_dir)/xsd/$(path)/calendar.xml) +	$(call install-data,$(src_base)/xml-schema-custom.hxx,$(install_doc_dir)/xsd/$(path)/xml-schema-custom.hxx) +	$(call install-data,$(src_base)/xml-schema-custom.cxx,$(install_doc_dir)/xsd/$(path)/xml-schema-custom.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/calendar.xsd,$(dist_prefix)/$(path)/calendar.xsd) +	$(call install-data,$(src_base)/calendar.xml,$(dist_prefix)/$(path)/calendar.xml) +	$(call install-data,$(src_base)/xml-schema-custom.hxx,$(dist_prefix)/$(path)/xml-schema-custom.hxx) +	$(call install-data,$(src_base)/xml-schema-custom.cxx,$(dist_prefix)/$(path)/xml-schema-custom.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,calendar-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,calendar-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,calendar-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,calendar-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,calendar-vc12.sln) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) +	$(call message,rm $$1,rm -f $$1,$(out_base)/xml-schema.hxx) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver xml-schema.hxx $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/calendar/xml-schema-custom.cxx b/xsd/examples/cxx/tree/custom/calendar/xml-schema-custom.cxx new file mode 100644 index 0000000..645880b --- /dev/null +++ b/xsd/examples/cxx/tree/custom/calendar/xml-schema-custom.cxx @@ -0,0 +1,56 @@ +// file      : examples/cxx/tree/custom/calendar/xml-schema-custom.cxx +// copyright : not copyrighted - public domain + +// Include xml-schema.hxx instead of xml-schema-custom.hxx here. +// +#include "xml-schema.hxx" + +#include <xsd/cxx/xml/string.hxx> // xsd::cxx::xml::transcode +#include <xsd/cxx/tree/text.hxx> // xsd::cxx::tree::text_content + +using namespace boost; +using namespace boost::gregorian; + +namespace xml_schema +{ +  date:: +  date (const xercesc::DOMElement& e, flags f, container* c) +      : simple_type (e, f, c), +        gregorian::date ( +          from_simple_string ( +            xsd::cxx::tree::text_content<char> (e))) +  { +  } + +  date:: +  date (const xercesc::DOMAttr& a, flags f, container* c) +      : simple_type (a, f, c), +        gregorian::date ( +          from_simple_string ( +            xsd::cxx::xml::transcode<char> (a.getValue ()))) +  { +  } + +  date:: +  date (const std::string& s, +        const xercesc::DOMElement* e, +        flags f, +        container* c) +      : simple_type (s, e, f, c), +        gregorian::date (from_simple_string (s)) +  { +  } + +  date:: +  date (const date& d, flags f, container* c) +      : simple_type (d, f, c), +        gregorian::date (d) +  { +  } + +  date* date:: +  _clone (flags f, container* c) const +  { +    return new date (*this, f, c); +  } +} diff --git a/xsd/examples/cxx/tree/custom/calendar/xml-schema-custom.hxx b/xsd/examples/cxx/tree/custom/calendar/xml-schema-custom.hxx new file mode 100644 index 0000000..58f57e6 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/calendar/xml-schema-custom.hxx @@ -0,0 +1,33 @@ +// file      : examples/cxx/tree/custom/calendar/xml-schema-custom.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use xml-schema.hxx instead. This +// file is included into generated xml-schema.hxx so we do not need to +// guard against multiple inclusions. +// + +#include <boost/date_time/gregorian/gregorian.hpp> // boost::gregorian::date + +namespace xml_schema +{ +  class date: public simple_type, +              public boost::gregorian::date +  { +  public: +    // Parsing c-tors: element, attribute, and list item. +    // +    date (const xercesc::DOMElement&, flags = 0, container* = 0); +    date (const xercesc::DOMAttr&, flags = 0, container* = 0); +    date (const std::string&, +          const xercesc::DOMElement*, +          flags = 0, +          container* = 0); + +    // Copy c-tor and _clone. +    // +    date (const date&, flags = 0, container* = 0); + +    virtual date* +    _clone (flags = 0, container* = 0) const; +  }; +} diff --git a/xsd/examples/cxx/tree/custom/comments/README b/xsd/examples/cxx/tree/custom/comments/README new file mode 100644 index 0000000..8fd69d0 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/README @@ -0,0 +1,57 @@ +This example shows how to customize the anyType XML Schema built-in +type to implement preservation of comments stored in XML documents. +Because anyType is a base type for every generated type, you can use +this technique to implement custom functionality that spans the +entire type system. For more information on the C++/Tree mapping +customization see the C++/Tree Mapping Customization Guide[2]. + +[2] http://wiki.codesynthesis.com/Tree/Customization_guide + +The example consists of the following files: + +people.xsd +  XML Schema definition for a simple person record vocabulary. + +people.xml +  Sample XML instance document. + +xml-schema.hxx +  C++ types for XML Schema built-in types. This header file is generated +  by XSD using the --generate-xml-schema option. The --custom-type option +  is also used to customize the xsd:anyType type. + +people.hxx +people.ixx +people.cxx +  C++ types that represent the person record vocabulary, a set of +  parsing functions that convert XML instance documents to a tree-like +  in-memory object model, and a set of serialization functions that +  convert the object model back to XML. These are generated by XSD +  from people.xsd with the --extern-xml-schema option in order to +  include xml-schema.hxx. + +xml-schema-custom.hxx +  Header file which defines our own xml_schema::type class. It is +  included at the end of xml-schema.hxx using the --hxx-epilogue +  option. + +xml-schema-custom.cxx +  Source file which contains the implementation of our xml_schema:type +  class. + +dom-parse.hxx +dom-parse.cxx +  Definition and implementation of the parse() function that +  parses an XML document to a DOM document while preserving +  XML comments. + +driver.cxx +  Driver for the example. It first calls the above parse() function +  to parse the input file to a DOM document. It then parses the DOM +  document to the object model and performs a number of modifications +  on this object model. Finally, it serializes the modified object +  model back to XML, including XML comments. + +To run the example on the sample XML instance document simply execute: + +$ ./driver people.xml diff --git a/xsd/examples/cxx/tree/custom/comments/dom-parse.cxx b/xsd/examples/cxx/tree/custom/comments/dom-parse.cxx new file mode 100644 index 0000000..9999f67 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/dom-parse.cxx @@ -0,0 +1,93 @@ +// file      : examples/cxx/tree/custom/comments/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include <istream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/XMLUniDefs.hpp> // chLatin_* +#include <xercesc/framework/Wrapper4InputSource.hpp> + +#include <xsd/cxx/xml/sax/std-input-source.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> + +#include <xsd/cxx/tree/exceptions.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::auto_ptr<DOMDocument> +parse (std::istream& is, const std::string& id, bool validate) +{ +  const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; + +  // Get an implementation of the Load-Store (LS) interface. +  // +  DOMImplementation* impl ( +    DOMImplementationRegistry::getDOMImplementation (ls_id)); + +  xml::dom::auto_ptr<DOMLSParser> parser ( +    impl->createLSParser (DOMImplementationLS::MODE_SYNCHRONOUS, 0)); + +  DOMConfiguration* conf (parser->getDomConfig ()); + +  // Preserve comment nodes in the document. +  // +  conf->setParameter (XMLUni::fgDOMComments, true); + +  // Enable datatype normalization. +  // +  conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); + +  // Do not create EntityReference nodes in the DOM tree. No +  // EntityReference nodes will be created, only the nodes +  // corresponding to their fully expanded substitution text +  // will be created. +  // +  conf->setParameter (XMLUni::fgDOMEntities, false); + +  // Perform namespace processing. +  // +  conf->setParameter (XMLUni::fgDOMNamespaces, true); + +  // Do not include ignorable whitespace in the DOM tree. +  // +  conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); + +  // Enable/Disable validation. +  // +  conf->setParameter (XMLUni::fgDOMValidate, validate); +  conf->setParameter (XMLUni::fgXercesSchema, validate); +  conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); + +  // Xerces-C++ 3.1.0 is the first version with working multi import +  // support. +  // +#if _XERCES_VERSION >= 30100 +  conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +  // We will release the DOM document ourselves. +  // +  conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + +  // Set error handler. +  // +  tree::error_handler<char> eh; +  xml::dom::bits::error_handler_proxy<char> ehp (eh); +  conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +  // Prepare input stream. +  // +  xml::sax::std_input_source isrc (is, id); +  Wrapper4InputSource wrap (&isrc, false); + +  xml::dom::auto_ptr<DOMDocument> doc (parser->parse (&wrap)); + +  eh.throw_if_failed<tree::parsing<char> > (); + +  return doc; +} diff --git a/xsd/examples/cxx/tree/custom/comments/dom-parse.hxx b/xsd/examples/cxx/tree/custom/comments/dom-parse.hxx new file mode 100644 index 0000000..fea46d0 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/dom-parse.hxx @@ -0,0 +1,22 @@ +// file      : examples/cxx/tree/custom/comments/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include <string> +#include <iosfwd> + +#include <xercesc/dom/DOMDocument.hpp> +#include <xsd/cxx/xml/dom/auto-ptr.hxx> + +// Parse an XML document from the standard input stream with an +// optional resource id. Resource id is used in diagnostics as +// well as to locate schemas referenced from inside the document. +// +xsd::cxx::xml::dom::auto_ptr<xercesc::DOMDocument> +parse (std::istream& is, +       const std::string& id, +       bool validate); + +#endif // DOM_PARSE diff --git a/xsd/examples/cxx/tree/custom/comments/driver.cxx b/xsd/examples/cxx/tree/custom/comments/driver.cxx new file mode 100644 index 0000000..39b16f7 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/driver.cxx @@ -0,0 +1,90 @@ +// file      : examples/cxx/tree/custom/commens/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <fstream> +#include <iostream> + +#include <xercesc/dom/DOMDocument.hpp> +#include <xercesc/util/PlatformUtils.hpp> + +#include "people.hxx" +#include "dom-parse.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " people.xml" << endl; +    return 1; +  } + +  int r (0); + +  // We need to initialize the Xerces-C++ runtime because we +  // are doing the XML-to-DOM parsing ourselves (see below). +  // +  xercesc::XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace people; +    namespace xml = xsd::cxx::xml; + +    ifstream ifs; +    ifs.exceptions (ifstream::badbit | ifstream::failbit); +    ifs.open (argv[1]); + +    // For performance reasons the internal XML to DOM parsing code +    // discards comments in the resulting DOM document. To overcome +    // this we are going to use our own parse() function from  +    // dom-parse.hxx that preserves comments in the resulting DOM +    // documents. +    // +    xml_schema::dom::auto_ptr<xercesc::DOMDocument> doc ( +      parse (ifs, argv[1], true)); + +    // Parse the DOM document to the object model. +    // +    std::auto_ptr<catalog> c (catalog_ (*doc)); + +    // Change the object model. +    // +    catalog::person_sequence& ps (c->person ()); + +    for (catalog::person_iterator i (ps.begin ()); i != ps.end (); ++i) +    { +      i->age (i->age () + 1); +    } + +    person john ("John Doe", 30); +    john.comment ("Record for John Doe"); + +    ps.push_back (john); + +    // Serialize. +    // +    xml_schema::namespace_infomap map; + +    map["ppl"].name = "http://www.codesynthesis.com/people"; +    map["ppl"].schema = "people.xsd"; + +    catalog_ (std::cout, *c, map); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    r = 1; +  } + +  xercesc::XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/custom/comments/makefile b/xsd/examples/cxx/tree/custom/comments/makefile new file mode 100644 index 0000000..eebb75e --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/makefile @@ -0,0 +1,123 @@ +# file      : examples/cxx/tree/custom/comments/makefile +# copyright : Copyright (c) 2005-2014 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 xml-schema-custom.cxx dom-parse.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +# Header file for XML Schema namespace. +# +$(out_base)/xml-schema.hxx: $(out_root)/xsd/xsd +	$(call message,xsd $(src_base)/xml-schema.xsd,\ +$(out_root)/xsd/xsd cxx-tree --output-dir $(out_base) --generate-xml-schema \ +--generate-serialization --custom-type anyType=/type_base \ +--hxx-epilogue '#include "xml-schema-custom.hxx"' xml-schema.xsd) + +# +# +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += \ +--generate-inline \ +--generate-serialization \ +--extern-xml-schema xml-schema.xsd + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(install_doc_dir)/xsd/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(install_doc_dir)/xsd/$(path)/people.xml) +	$(call install-data,$(src_base)/xml-schema-custom.hxx,$(install_doc_dir)/xsd/$(path)/xml-schema-custom.hxx) +	$(call install-data,$(src_base)/xml-schema-custom.cxx,$(install_doc_dir)/xsd/$(path)/xml-schema-custom.cxx) +	$(call install-data,$(src_base)/dom-parse.hxx,$(install_doc_dir)/xsd/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(install_doc_dir)/xsd/$(path)/dom-parse.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(dist_prefix)/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(dist_prefix)/$(path)/people.xml) +	$(call install-data,$(src_base)/xml-schema-custom.hxx,$(dist_prefix)/$(path)/xml-schema-custom.hxx) +	$(call install-data,$(src_base)/xml-schema-custom.cxx,$(dist_prefix)/$(path)/xml-schema-custom.cxx) +	$(call install-data,$(src_base)/dom-parse.hxx,$(dist_prefix)/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(dist_prefix)/$(path)/dom-parse.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) +	$(call message,rm $$1,rm -f $$1,$(out_base)/xml-schema.hxx) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver xml-schema.hxx $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/comments/people.xml b/xsd/examples/cxx/tree/custom/comments/people.xml new file mode 100644 index 0000000..55c08a1 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/people.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/comments/people.xml +copyright : not copyrighted - public domain + +--> + +<ppl:catalog xmlns:ppl="http://www.codesynthesis.com/people" +	     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	     xsi:schemaLocation="http://www.codesynthesis.com/people people.xsd"> + +  <person> +    <!--Record for Joe Dirt--> +    <name>Joe Dirt</name> +    <age>28</age> +  </person> + +</ppl:catalog> diff --git a/xsd/examples/cxx/tree/custom/comments/people.xsd b/xsd/examples/cxx/tree/custom/comments/people.xsd new file mode 100644 index 0000000..e70dd2a --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/people.xsd @@ -0,0 +1,29 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/comments/people.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:ppl="http://www.codesynthesis.com/people" +            targetNamespace="http://www.codesynthesis.com/people"> + +  <xsd:complexType name="person"> +    <xsd:sequence> +      <xsd:element name="name" type="xsd:string"/> +      <xsd:element name="age" type="xsd:unsignedShort"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="catalog"> +    <xsd:sequence> +      <xsd:element name="person" type="ppl:person" maxOccurs="unbounded"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:element name="catalog" type="ppl:catalog"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/custom/comments/xml-schema-custom.cxx b/xsd/examples/cxx/tree/custom/comments/xml-schema-custom.cxx new file mode 100644 index 0000000..67937d1 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/xml-schema-custom.cxx @@ -0,0 +1,117 @@ +// file      : examples/cxx/tree/custom/comments/xml-schema-custom.cxx +// copyright : not copyrighted - public domain + +// Include xml-schema.hxx instead of xml-schema-custom.hxx here. +// +#include "xml-schema.hxx" + +#include <xercesc/dom/DOMComment.hpp> +#include <xercesc/dom/DOMDocument.hpp> + +#include <xsd/cxx/xml/string.hxx> // xml::transcode, xml::string + +namespace xml = xsd::cxx::xml; + +namespace xml_schema +{ +  type:: +  type () +      : type_base () +  { +  } + +  type:: +  type (const xercesc::DOMElement& e, flags f, container* c) +      : type_base (e, f, c) +  { +    using namespace xercesc; + +    // Here we are only handling a comment that is the first +    // node in the element's content. +    // +    const DOMNode* n (e.getFirstChild ()); + +    if (n != 0 && n->getNodeType () == DOMNode::COMMENT_NODE) +    { +      const DOMComment* c (static_cast<const DOMComment*> (n)); +      comment_ = xml::transcode<char> (c->getData ()); +    } +  } + +  type:: +  type (const xercesc::DOMAttr& a, flags f, container* c) +      : type_base (a, f, c) +  { +    // No comments for attributes. +    // +  } + +  type:: +  type (const std::string& s, const xercesc::DOMElement* e, +        flags f, container* c) +      : type_base (s, e, f, c) +  { +    // No comments for list items. +    // +  } + +  type:: +  type (const type& x, flags f, container* c) +      : type_base (x, f, c), comment_ (x.comment_) +  { +  } + +  type* type:: +  _clone (flags f, container* c) const +  { +    return new type (*this, f, c); +  } + +  // Serialization operators. +  // +  void +  operator<< (xercesc::DOMElement& e, const type& x) +  { +    // Call our base first. +    // +    const type_base& b (x); +    e << b; + +    // Add the comment if any. +    // +    const std::string s (x.comment ()); + +    if (!s.empty ()) +    { +      using namespace xercesc; + +      DOMDocument* doc (e.getOwnerDocument ()); +      DOMComment* c (doc->createComment (xml::string (s).c_str ())); +      e.appendChild (c); +    } +  } + +  void +  operator<< (xercesc::DOMAttr& a, const type& x) +  { +    // Call our base first. +    // +    const type_base& b (x); +    a << b; + +    // No comments for attributes. +    // +  } + +  void +  operator<< (xml_schema::list_stream& ls, const type& x) +  { +    // Call our base first. +    // +    const type_base& b (x); +    ls << b; + +    // No comments for list items. +    // +  } +} diff --git a/xsd/examples/cxx/tree/custom/comments/xml-schema-custom.hxx b/xsd/examples/cxx/tree/custom/comments/xml-schema-custom.hxx new file mode 100644 index 0000000..0442a44 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/comments/xml-schema-custom.hxx @@ -0,0 +1,57 @@ +// file      : examples/cxx/tree/custom/comments/xml-schema-custom.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use xml-schema.hxx instead. This +// file is included into generated xml-schema.hxx so we do not need to +// guard against multiple inclusions. +// + +#include <string> + +namespace xml_schema +{ +  // When customizing anyType always inherit from the original type. +  // +  class type: public type_base +  { +  public: +    type (); +    type (const xercesc::DOMElement&, flags = 0, container* = 0); +    type (const xercesc::DOMAttr&, flags = 0, container* = 0); +    type (const std::string&, const xercesc::DOMElement*, +          flags = 0, container* = 0); +    type (const type&, flags = 0, container* = 0); + +    virtual type* +    _clone (flags = 0, container* = 0) const; + +  public: +    // Comment manipulation API. +    // +    const std::string& +    comment () const +    { +      return comment_; +    } + +    void +    comment (const std::string& c) +    { +      comment_ = c; +    } + +  private: +    std::string comment_; +  }; + +  // New serialization operators. +  // +  void +  operator<< (xercesc::DOMElement&, const type&); + +  void +  operator<< (xercesc::DOMAttr&, const type&); + +  void +  operator<< (xml_schema::list_stream&, const type&); +} diff --git a/xsd/examples/cxx/tree/custom/contacts/README b/xsd/examples/cxx/tree/custom/contacts/README new file mode 100644 index 0000000..072ede3 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/contacts/README @@ -0,0 +1,40 @@ +This example shows how to map a user-defined XML Schema type to a custom +C++ class. It presents the simple case where the customized type is not +used as a base in the same schema. For the complex case see the taxonomy +example. For more information on the C++/Tree mapping customization see +the C++/Tree Mapping Customization Guide[1]. + +[1] http://wiki.codesynthesis.com/Tree/Customization_guide + +The example consists of the following files: + +contacts.xsd +  XML Schema definition for a simple contacts database. + +contacts.xml +  Sample XML instance document. + +contacts.hxx +contacts.ixx +contacts.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by XSD from contacts.xsd with the +  --custom-type option in order to customize the contact type. + +contacts-custom.hxx +  Header file which defines our own contact class by inheriting from the +  generated contact_base. It is included at the end of contacts.hxx using +  the --hxx-epilogue option. + +contacts-custom.cxx +  Source file which contains the implementation of our contact class. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the contacts to STDERR. + +To run the example on the sample XML instance document simply execute: + +$ ./driver contacts.xml diff --git a/xsd/examples/cxx/tree/custom/contacts/contacts-custom.cxx b/xsd/examples/cxx/tree/custom/contacts/contacts-custom.cxx new file mode 100644 index 0000000..8bb0e22 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/contacts/contacts-custom.cxx @@ -0,0 +1,50 @@ +// file      : examples/cxx/tree/custom/contacts/contacts-custom.cxx +// copyright : not copyrighted - public domain + +#include <ostream> + +// Include contacts.hxx instead of contacts-custom.hxx here. +// +#include "contacts.hxx" + +namespace contacts +{ +  // We implement the following constructs by simply forwarding +  // to our base. +  // +  contact:: +  contact (const name_type& n, +           const email_type& e, +           const phone_type& p) +      : contact_base (n, e, p) +  { +  } + +  contact:: +  contact (const xercesc::DOMElement& e, +           xml_schema::flags f, +           xml_schema::container* c) +      : contact_base (e, f, c) +  { +  } + +  contact:: +  contact (const contact& x, +           xml_schema::flags f, +           xml_schema::container* c) +      : contact_base (x, f, c) +  { +  } + +  contact* contact:: +  _clone (xml_schema::flags f, xml_schema::container* c) const +  { +    return new contact (*this, f, c); +  } + +  void contact:: +  print (std::ostream& os) const +  { +    os << name () << " e| " << email () << " t| " << phone () << std::endl; +  } +} diff --git a/xsd/examples/cxx/tree/custom/contacts/contacts-custom.hxx b/xsd/examples/cxx/tree/custom/contacts/contacts-custom.hxx new file mode 100644 index 0000000..65d6244 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/contacts/contacts-custom.hxx @@ -0,0 +1,43 @@ +// file      : examples/cxx/tree/custom/contacts/contacts-custom.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use contacts.hxx instead. This +// file is included into generated contacts.hxx so we do not need to +// guard against multiple inclusions. +// + +#include <iosfwd> // std::ostream + +namespace contacts +{ +  class contact: public contact_base +  { +    // The following constructor signatures are copied from +    // contact_base except for the copy constructor and the +    // _clone function where we had to change the type from +    // contact_base to contact. +    // +  public: +    contact (const name_type&, +             const email_type&, +             const phone_type&); + +    contact (const xercesc::DOMElement&, +             xml_schema::flags = 0, +             xml_schema::container* = 0); + +    contact (const contact&, +             xml_schema::flags = 0, +             xml_schema::container* = 0); + +    virtual contact* +    _clone (xml_schema::flags = 0, +            xml_schema::container* = 0) const; + +    // Our customizations. +    // +  public: +    void +    print (std::ostream&) const; +  }; +} diff --git a/xsd/examples/cxx/tree/custom/contacts/contacts.xml b/xsd/examples/cxx/tree/custom/contacts/contacts.xml new file mode 100644 index 0000000..331e692 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/contacts/contacts.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/contacts/contacts.xml +copyright : not copyrighted - public domain + +--> + +<cts:catalog xmlns:cts="http://www.codesynthesis.com/contacts" +	     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	     xsi:schemaLocation="http://www.codesynthesis.com/contacts contacts.xsd"> + +  <contact> +    <name>Joe Dirt</name> +    <email>joe@dirt.com</email> +    <phone>555 DIRT</phone> +  </contact> + +</cts:catalog> diff --git a/xsd/examples/cxx/tree/custom/contacts/contacts.xsd b/xsd/examples/cxx/tree/custom/contacts/contacts.xsd new file mode 100644 index 0000000..d6110fe --- /dev/null +++ b/xsd/examples/cxx/tree/custom/contacts/contacts.xsd @@ -0,0 +1,31 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/contacts/contacts.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:cts="http://www.codesynthesis.com/contacts" +            targetNamespace="http://www.codesynthesis.com/contacts"> + +  <xsd:complexType name="contact"> +    <xsd:sequence> +      <xsd:element name="name" type="xsd:string"/> +      <xsd:element name="email" type="xsd:string"/> +      <xsd:element name="phone" type="xsd:string"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="catalog"> +    <xsd:sequence> +      <xsd:element name="contact" type="cts:contact" maxOccurs="unbounded"/> +    </xsd:sequence> +  </xsd:complexType> + + +  <xsd:element name="catalog" type="cts:catalog"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/custom/contacts/driver.cxx b/xsd/examples/cxx/tree/custom/contacts/driver.cxx new file mode 100644 index 0000000..ae8a2da --- /dev/null +++ b/xsd/examples/cxx/tree/custom/contacts/driver.cxx @@ -0,0 +1,38 @@ +// file      : examples/cxx/tree/custom/contacts/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "contacts.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " contacts.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace contacts; + +    std::auto_ptr<catalog> c (catalog_ (argv[1])); + +    for (catalog::contact_const_iterator i (c->contact ().begin ()); +         i != c->contact ().end (); ++i) +    { +      i->print (cerr); +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/custom/contacts/makefile b/xsd/examples/cxx/tree/custom/contacts/makefile new file mode 100644 index 0000000..ec9d902 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/contacts/makefile @@ -0,0 +1,113 @@ +# file      : examples/cxx/tree/custom/contacts/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := contacts.xsd +cxx := driver.cxx contacts-custom.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd + +# We have to double-escape '#' because the message function +# (which is used in command scripts) expands things twice. +# +$(gen): xsd_options += \ +--generate-inline \ +--custom-type contact=/contact_base \ +--hxx-epilogue '\#include "contacts-custom.hxx"' + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/contacts.xsd,$(install_doc_dir)/xsd/$(path)/contacts.xsd) +	$(call install-data,$(src_base)/contacts.xml,$(install_doc_dir)/xsd/$(path)/contacts.xml) +	$(call install-data,$(src_base)/contacts-custom.hxx,$(install_doc_dir)/xsd/$(path)/contacts-custom.hxx) +	$(call install-data,$(src_base)/contacts-custom.cxx,$(install_doc_dir)/xsd/$(path)/contacts-custom.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/contacts.xsd,$(dist_prefix)/$(path)/contacts.xsd) +	$(call install-data,$(src_base)/contacts.xml,$(dist_prefix)/$(path)/contacts.xml) +	$(call install-data,$(src_base)/contacts-custom.hxx,$(dist_prefix)/$(path)/contacts-custom.hxx) +	$(call install-data,$(src_base)/contacts-custom.cxx,$(dist_prefix)/$(path)/contacts-custom.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/double/README b/xsd/examples/cxx/tree/custom/double/README new file mode 100644 index 0000000..15348d2 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/double/README @@ -0,0 +1,62 @@ +This example shows how to customize parsing and serialization code for the +xsd:double XML Schema built-in type using the type customization mechanism +provided by the C++/Tree Mapping. For more information on type customization +see the C++/Tree Mapping Customization Guide, particularly sections 1 and 4: + +http://wiki.codesynthesis.com/Tree/Customization_guide + +In this example our schema uses xsd:double to represent a price. There are +two potential problems with this choice of a price type. First, xsd:double +can be serialized in the scientific notation which would be an unusual way +of representing a price. Second, we would like to limit the number of  +fraction digits in our prices to 2. Furthermore, we would like to always +have two fraction digits, even if one or both of them are zeros, for +example: 12.99, 12.90, 12.00. + +In case we can modify the schema, a better approach would be to define the +price type as a restriction of the xsd:decimal type (always fixed notation) +and specify the fractionDigits facet to limit the number of fraction digits +to 2. However, there is no way in XML Schema to specify that there should +always be exactly 2 fraction digits. Therefore, it may still be desirable +to customize this price type to get the required serialization behavior. + +Finally, it is worth noting that the behavior achieved in this example via +type customization can also be achieved by compiling your code with the +following macros defined: + +XSD_TREE_DOUBLE_FIXED +XSD_TREE_DOUBLE_PRECISION 2 + +However, the type customization approach while requiring more work is +cleaner since it does not rely on global macro definitions. + +This example consists of the following files: + +order.xsd +  XML Schema definition for a simple order vocabulary. + +double-custom.hxx +double-custom.cxx +  Custom parsing and serialization code for the xsd:double types. The +  double-custom.hxx file is included at the end of the xml-schema.hxx +  file described below. + +xml-schema.hxx +  C++ types for XML Schema built-in types. This header file is generated +  by the XSD compiler using the --generate-xml-schema option. The +  --custom-type option is used to customize the xsd:double type. The  +  --hxx-epilogue option is used to include the double-custom.hxx file +  at the end of this file. + +order.hxx +order.cxx +  C++ types generated from order.xsd. The --extern-xml-schema option +  is used to include xml-schema.hxx into order.hxx. + +driver.cxx +  Test driver for the example. It creates a sample order and then +  writes it to XML to test the custom xsd:double serialization code. + +To run the example simply execute: + +$ ./driver diff --git a/xsd/examples/cxx/tree/custom/double/double-custom.cxx b/xsd/examples/cxx/tree/custom/double/double-custom.cxx new file mode 100644 index 0000000..6aad908 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/double/double-custom.cxx @@ -0,0 +1,96 @@ +// file      : examples/cxx/tree/custom/double/double-custom.cxx +// copyright : not copyrighted - public domain + +// Include xml-schema.hxx instead of double-custom.hxx here. +// +#include "xml-schema.hxx" + +#include <limits> +#include <locale> +#include <sstream> + +#include <xsd/cxx/ro-string.hxx> +#include <xsd/cxx/zc-istream.hxx> + +using namespace std; + +// Parsing. +// +namespace xsd +{ +  namespace cxx +  { +    namespace tree +    { +      double traits<double, char, schema_type::double_>:: +      create (const std::string& s, +              const xercesc::DOMElement*, +              flags, +              type*) +      { +        // This type cannot have whitespaces in its values. As result we +        // don't need to waste time collapsing whitespaces. All we need to +        // do is trim the string representation which can be done without +        // copying. +        // +        ro_string<char> tmp (s); +        trim (tmp); + +        zc_istream<char> is (tmp); +        is.imbue (locale::classic ()); + +        double t; +        is >> t; + +        return t; +      } +    } +  } +} + +// Serialization. +// +namespace XERCES_CPP_NAMESPACE +{ +  void +  operator<< (xercesc::DOMElement& e, const xml_schema::as_double& d) +  { +    ostringstream os; +    os.imbue (locale::classic ()); + +    os.precision (2); +    os << fixed << d.x; + +    e << os.str (); +  } + +  void +  operator<< (xercesc::DOMAttr& a, const xml_schema::as_double& d) +  { +    ostringstream os; +    os.imbue (locale::classic ()); + +    os.precision (2); +    os << fixed << d.x; + +    a << os.str (); +  } +} + +namespace xsd +{ +  namespace cxx +  { +    namespace tree +    { +      void +      operator<< (xml_schema::list_stream& ls, +                  const xml_schema::as_double& d) +      { +        ls.os_.imbue (locale::classic ()); +        ls.os_.precision (2); +        ls.os_ << fixed << d.x; +      } +    } +  } +} diff --git a/xsd/examples/cxx/tree/custom/double/double-custom.hxx b/xsd/examples/cxx/tree/custom/double/double-custom.hxx new file mode 100644 index 0000000..1516211 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/double/double-custom.hxx @@ -0,0 +1,67 @@ +// file      : examples/cxx/tree/custom/double/double-custom.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use xml-schema.hxx instead. This +// file is included into generated xml-schema.hxx so we do not need to +// guard against multiple inclusions. +// + +#include <xsd/cxx/xml/string.hxx> // xml::transcode +#include <xsd/cxx/tree/text.hxx>  // text_content + +// Parsing. +// +namespace xsd +{ +  namespace cxx +  { +    namespace tree +    { +      template<> +      struct traits<double, char, schema_type::double_> +      { +        static double +        create (const xercesc::DOMElement& e, flags f, type* c) +        { +          return create (text_content<char> (e), 0, f, c); +        } + +        static double +        create (const xercesc::DOMAttr& a, flags f, type* c) +        { +          return create (xml::transcode<char> (a.getValue ()), 0, f, c); +        } + +        static double +        create (const std::string& s, +                const xercesc::DOMElement*, +                flags, +                type*); +      }; +    } +  } +} + +// Serialization. +// +namespace XERCES_CPP_NAMESPACE +{ +  void +  operator<< (xercesc::DOMElement& e, const xml_schema::as_double& d); + +  void +  operator<< (xercesc::DOMAttr& a, const xml_schema::as_double& d); +} + +namespace xsd +{ +  namespace cxx +  { +    namespace tree +    { +      void +      operator<< (xml_schema::list_stream& ls, +                  const xml_schema::as_double& d); +    } +  } +} diff --git a/xsd/examples/cxx/tree/custom/double/driver.cxx b/xsd/examples/cxx/tree/custom/double/driver.cxx new file mode 100644 index 0000000..8b102a5 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/double/driver.cxx @@ -0,0 +1,31 @@ +// file      : examples/cxx/tree/custom/double/driver.cxx +// copyright : not copyrighted - public domain + +#include <iostream> + +#include "order.hxx" + +using std::cerr; +using std::endl; + +int +main () +{ +  try +  { +    // Order one Airbus A380. +    // +    order o; +    o.item ().push_back (item ("Airbus A380", 317000000.90)); + + +    // Serialize. +    // +    order_ (std::cout, o); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/custom/double/makefile b/xsd/examples/cxx/tree/custom/double/makefile new file mode 100644 index 0000000..2eed216 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/double/makefile @@ -0,0 +1,112 @@ +# file      : examples/cxx/tree/custom/double/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := order.xsd +cxx := driver.cxx double-custom.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +$(out_base)/xml-schema.hxx: $(out_root)/xsd/xsd +	$(call message,xsd $(src_base)/xml-schema.xsd,\ +$(out_root)/xsd/xsd cxx-tree --output-dir $(out_base) --generate-xml-schema \ +--generate-serialization --custom-type double=double \ +--hxx-epilogue '#include "double-custom.hxx"' xml-schema.xsd) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-serialization \ +--extern-xml-schema xml-schema.xsd + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/order.xsd,$(install_doc_dir)/xsd/$(path)/order.xsd) +	$(call install-data,$(src_base)/double-custom.hxx,$(install_doc_dir)/xsd/$(path)/double-custom.hxx) +	$(call install-data,$(src_base)/double-custom.cxx,$(install_doc_dir)/xsd/$(path)/double-custom.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/order.xsd,$(dist_prefix)/$(path)/order.xsd) +	$(call install-data,$(src_base)/double-custom.hxx,$(dist_prefix)/$(path)/double-custom.hxx) +	$(call install-data,$(src_base)/double-custom.cxx,$(dist_prefix)/$(path)/double-custom.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) +	$(call message,rm $$1,rm -f $$1,$(out_base)/xml-schema.hxx) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver xml-schema.hxx $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/double/order.xsd b/xsd/examples/cxx/tree/custom/double/order.xsd new file mode 100644 index 0000000..9cf1a1d --- /dev/null +++ b/xsd/examples/cxx/tree/custom/double/order.xsd @@ -0,0 +1,25 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/double/order.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + +  <xsd:complexType name="item"> +    <xsd:attribute name="name" type="xsd:string" use="required"/> +    <xsd:attribute name="price" type="xsd:double" use="required"/> +  </xsd:complexType> + +  <xsd:complexType name="order"> +    <xsd:sequence> +      <xsd:element name="item" type="item" maxOccurs="unbounded"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:element name="order" type="order"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/custom/makefile b/xsd/examples/cxx/tree/custom/makefile new file mode 100644 index 0000000..d84f840 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/makefile @@ -0,0 +1,61 @@ +# file      : examples/cxx/tree/custom/makefile +# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +all_examples   := comments contacts double mixed taxonomy wildcard calendar +build_examples := comments contacts double mixed taxonomy wildcard + +ifeq ($(xsd_with_boost_date_time),y) +build_examples += calendar +endif + +default  := $(out_base)/ +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Build. +# +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples))) + +# Install & Dist. +# +$(install) $(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base)) + +$(install): $(addprefix $(out_base)/,$(addsuffix /.install,$(all_examples))) +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) + +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,custom-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,custom-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,custom-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,custom-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,custom-vc12.sln) + + +# Clean. +# +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples))) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) + +ifneq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile)) +else +$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile)) +endif + diff --git a/xsd/examples/cxx/tree/custom/mixed/README b/xsd/examples/cxx/tree/custom/mixed/README new file mode 100644 index 0000000..7b56812 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/mixed/README @@ -0,0 +1,50 @@ +This example shows how to use type customization to parse and serialize +mixed content. The example achieves this by customizing the type with  +the mixed content model to include a DOM document that stores the data  +as a raw XML representation. The customized type also provides its own +parsing constructor and serialization operator where the mixed content +is extracted from and inserted back to DOM, respectively. The use of +DOM for mixed content storage is one of the options. You may find other +data structures (e.g., a string) more suitable depending on your situation. + +For more information on the C++/Tree mapping customization see the C++/Tree +Mapping Customization Guide[1]. + +[1] http://wiki.codesynthesis.com/Tree/Customization_guide + +The example consists of the following files: + +people.xsd +  XML Schema definition for a simple person record vocabulary. Each +  record includes the bio element which represents arbitrary XHTML +  fragments as mixed content. + +people.xml +  Sample XML instance document. + +people.hxx +people.ixx +people.cxx +  C++ types that represent the given vocabulary, a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model, and a set of serialization functions that convert the +  object model back to XML. These are generated by XSD from people.xsd +  with the --custom-type option in order to customize the bio type. + +people-custom.hxx +  Header file which defines our own bio class by inheriting from the +  generated bio_base. It is included at the end of people.hxx using +  the --hxx-epilogue option. + +people-custom.cxx +  Source file which contains the implementation of our bio class. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the data to STDERR, including the bio information converted to text. +  Finally, the driver serializes the object model back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver people.xml diff --git a/xsd/examples/cxx/tree/custom/mixed/driver.cxx b/xsd/examples/cxx/tree/custom/mixed/driver.cxx new file mode 100644 index 0000000..0378f18 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/mixed/driver.cxx @@ -0,0 +1,123 @@ +// file      : examples/cxx/tree/custom/mixed/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/PlatformUtils.hpp> + +#include "people.hxx" + +// The following transcode() utility function is handy when working with +// Xerces. Include it after the generated header in order to get only char +// or wchar_t version depending on how you compiled your schemas. +// +#include <xsd/cxx/xml/string.hxx> + +using std::cerr; +using std::endl; +using namespace xercesc; + + +void +xhtml2txt (const DOMElement*); + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " people.xml" << endl; +    return 1; +  } + +  int r (0); + +  // The Xerces-C++ DOM document that will be used to store the XHTML +  // fragments "out-live" the call to the parsing function. Therefore +  // we need to initialize the Xerces-C++ runtime ourselves. +  // +  XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace people; + +    // Parse. +    // +    std::auto_ptr<directory> d ( +      directory_ (argv[1], xml_schema::flags::dont_initialize)); + +    // Print what we've got. +    // +    const directory::person_sequence& s (d->person ()); + +    for (directory::person_const_iterator i (s.begin ()); i != s.end (); ++i) +    { +      cerr << "First  : " << i->first_name () << endl +           << "Last   : " << i->last_name () << endl +           << "Gender : " << i->gender () << endl +           << "Age    : " << i->age () << endl; + +      const bio& b (i->bio ()); +      const DOMElement* xhtml (b.xhtml ()); + +      if (xhtml != 0) +      { +        cerr << "Bio    : " << endl; +        xhtml2txt (xhtml); +      } + +      cerr << endl; +    } + +    // Serialize. +    // +    xml_schema::namespace_infomap map; + +    map["ppl"].name = "http://www.codesynthesis.com/people"; +    map["ppl"].schema = "people.xsd"; + +    directory_ ( +      std::cout, *d, map, "UTF-8", xml_schema::flags::dont_initialize); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } + +  XMLPlatformUtils::Terminate (); +  return r; +} + +// Primitive XHTML to text converter that just prints all the text +// nodes and ignores everything else. +// +void +xhtml2txt (const DOMElement* e) +{ +  namespace xml = xsd::cxx::xml; + +  for (const DOMNode* n (e->getFirstChild ()); +       n != 0; +       n = n->getNextSibling ()) +  { +    switch (n->getNodeType ()) +    { +    case DOMNode::TEXT_NODE: +      { +        cerr << xml::transcode<char> (n->getTextContent ()); +        break; +      } +    case DOMNode::ELEMENT_NODE: +      { +        xhtml2txt (static_cast<const DOMElement*> (n)); +        break; +      } +    default: +      break; // Ignore all other nodes (e.g., comments, etc). +    } +  } +} diff --git a/xsd/examples/cxx/tree/custom/mixed/makefile b/xsd/examples/cxx/tree/custom/mixed/makefile new file mode 100644 index 0000000..54610f0 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/mixed/makefile @@ -0,0 +1,115 @@ +# file      : examples/cxx/tree/custom/mixed/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := people.xsd +cxx := driver.cxx people-custom.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd + +# We have to double-escape '#' because the message function +# (which is used in command scripts) expands things twice. +# +$(gen): xsd_options += \ +--generate-inline \ +--generate-serialization \ +--custom-type bio=/bio_base \ +--hxx-epilogue '\#include "people-custom.hxx"' + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(install_doc_dir)/xsd/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(install_doc_dir)/xsd/$(path)/people.xml) +	$(call install-data,$(src_base)/people-custom.hxx,$(install_doc_dir)/xsd/$(path)/people-custom.hxx) +	$(call install-data,$(src_base)/people-custom.cxx,$(install_doc_dir)/xsd/$(path)/people-custom.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(dist_prefix)/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(dist_prefix)/$(path)/people.xml) +	$(call install-data,$(src_base)/people-custom.hxx,$(dist_prefix)/$(path)/people-custom.hxx) +	$(call install-data,$(src_base)/people-custom.cxx,$(dist_prefix)/$(path)/people-custom.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/mixed/people-custom.cxx b/xsd/examples/cxx/tree/custom/mixed/people-custom.cxx new file mode 100644 index 0000000..7cd1947 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/mixed/people-custom.cxx @@ -0,0 +1,89 @@ +// file      : examples/cxx/tree/custom/mixed/people-custom.cxx +// copyright : not copyrighted - public domain + +#include <ostream> + +// Include people.hxx instead of people-custom.hxx here. +// +#include "people.hxx" + +namespace people +{ +  using namespace xercesc; + +  const XMLCh ls[] = {chLatin_L, chLatin_S, chNull}; + +  bio:: +  bio () +      : xhtml_ (0) +  { +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls)); + +    doc_.reset (impl->createDocument ()); +  } + +  bio:: +  bio (const DOMElement& e, +       xml_schema::flags f, +       xml_schema::container* c) +      : bio_base (e, f, c), xhtml_ (0) +  { +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls)); + +    doc_.reset (impl->createDocument ()); + +    // Copy the xhtml element. Assume the first child element in +    // e is always xhtml. +    // +    for (DOMNode* n (e.getFirstChild ()); n != 0; n = n->getNextSibling ()) +    { +      if (n->getNodeType () == DOMNode::ELEMENT_NODE) +      { +        xhtml_ = static_cast<DOMElement*> (doc_->importNode (n, true)); +        break; +      } +    } +  } + +  bio:: +  bio (const bio& d, +       xml_schema::flags f, +       xml_schema::container* c) +      : bio_base (d, f, c), xhtml_ (0) +  { +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls)); + +    doc_.reset (impl->createDocument ()); + +    xhtml_ = static_cast<DOMElement*> ( +      doc_->importNode (const_cast<DOMElement*> (d.xhtml_), true)); +  } + +  bio* bio:: +  _clone (xml_schema::flags f, xml_schema::container* c) const +  { +    return new bio (*this, f, c); +  } + +  void +  operator<< (DOMElement& e, const bio& x) +  { +    // Allow our base to serialize first. +    // +    const bio_base& b (x); +    e << b; + +    // Copy the XHTML fragment if we have one. +    // +    const DOMElement* xhtml (x.xhtml ()); + +    if (xhtml != 0) +    { +      DOMDocument* doc (e.getOwnerDocument ()); +      e.appendChild (doc->importNode (const_cast<DOMElement*> (xhtml), true)); +    } +  } +} diff --git a/xsd/examples/cxx/tree/custom/mixed/people-custom.hxx b/xsd/examples/cxx/tree/custom/mixed/people-custom.hxx new file mode 100644 index 0000000..54dfb21 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/mixed/people-custom.hxx @@ -0,0 +1,83 @@ +// file      : examples/cxx/tree/custom/mixed/people-custom.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use people.hxx instead. This +// file is included into generated people.hxx so we do not need to +// guard against multiple inclusions. +// + +#include <cassert> +#include <xercesc/dom/DOM.hpp> + +namespace people +{ +  class bio: public bio_base +  { +    // Standard constructors. +    // +  public: +    bio (); + +    bio (const xercesc::DOMElement&, +         xml_schema::flags = 0, +         xml_schema::container* = 0); + +    bio (const bio&, +         xml_schema::flags = 0, +         xml_schema::container* = 0); + +    virtual bio* +    _clone (xml_schema::flags = 0, +            xml_schema::container* = 0) const; + +    // XHTML bio as a DOM document. +    // +  public: +    const xercesc::DOMElement* +    xhtml () const +    { +      return xhtml_; +    } + +    xercesc::DOMElement* +    xhtml () +    { +      return xhtml_; +    } + +    // The element should belong to the DOMDocument returned by +    // the dom_document() functions. +    // +    void +    xhtml (xercesc::DOMElement* e) +    { +      assert (e->getOwnerDocument () == doc_.get ()); + +      if (xhtml_ != 0) +        xhtml_->release (); + +      xhtml_ = e; +    } + +    const xercesc::DOMDocument& +    dom_document () const +    { +      return *doc_; +    } + +    xercesc::DOMDocument& +    dom_document () +    { +      return *doc_; +    } + +  private: +    xercesc::DOMElement* xhtml_; +    xml_schema::dom::auto_ptr<xercesc::DOMDocument> doc_; +  }; + +  // Serialization operator. +  // +  void +  operator<< (xercesc::DOMElement&, const bio&); +} diff --git a/xsd/examples/cxx/tree/custom/mixed/people.xml b/xsd/examples/cxx/tree/custom/mixed/people.xml new file mode 100644 index 0000000..47e68b9 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/mixed/people.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/mixed/people.xml +copyright : not copyrighted - public domain + +--> + +<ppl:directory xmlns:ppl="http://www.codesynthesis.com/people" +               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +               xsi:schemaLocation="http://www.codesynthesis.com/people people.xsd"> + +  <person> +    <first-name>John</first-name> +    <last-name>Doe</last-name> +    <gender>male</gender> +    <age>32</age> +    <bio> +      <xhtml xmlns="http://www.w3.org/1999/xhtml"> +        <p>Married to Jane Doe.</p> +      </xhtml> +    </bio> +  </person> + +  <person> +    <first-name>Jane</first-name> +    <last-name>Doe</last-name> +    <gender>female</gender> +    <age>28</age> +    <bio> +      <xhtml xmlns="http://www.w3.org/1999/xhtml"> +        <p>Married to John Doe.</p> +      </xhtml> +    </bio> +  </person> + +</ppl:directory> diff --git a/xsd/examples/cxx/tree/custom/mixed/people.xsd b/xsd/examples/cxx/tree/custom/mixed/people.xsd new file mode 100644 index 0000000..03e6c97 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/mixed/people.xsd @@ -0,0 +1,45 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/mixed/people.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:ppl="http://www.codesynthesis.com/people" +            targetNamespace="http://www.codesynthesis.com/people"> + +  <xsd:simpleType name="gender"> +    <xsd:restriction base="xsd:string"> +      <xsd:enumeration value="male"/> +      <xsd:enumeration value="female"/> +    </xsd:restriction> +  </xsd:simpleType> + +  <xsd:complexType name="bio" mixed="true"> +    <xsd:sequence minOccurs="0" maxOccurs="unbounded"> +      <xsd:any namespace="http://www.w3.org/1999/xhtml" processContents="skip"/> +    </xsd:sequence> +  </xsd:complexType> + +  <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="ppl:gender"/> +      <xsd:element name="age" type="xsd:unsignedShort"/> +      <xsd:element name="bio" type="ppl:bio"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="directory"> +    <xsd:sequence> +      <xsd:element name="person" type="ppl:person" maxOccurs="unbounded"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:element name="directory" type="ppl:directory"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/custom/taxonomy/README b/xsd/examples/cxx/tree/custom/taxonomy/README new file mode 100644 index 0000000..c2e425a --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/README @@ -0,0 +1,53 @@ +This example shows how to map user-defined XML Schema types to custom C++ +classes. It presents the complex case where the customized types are +inherited from in the same schema. For the simple case see the contacts +example. For more information on the C++/Tree mapping customization see +the C++/Tree Mapping Customization Guide[1]. + +[1] http://wiki.codesynthesis.com/Tree/Customization_guide + +The example consists of the following files: + +people.xsd +  XML Schema definition for a simple people database. + +people.xml +  Sample XML instance document. + +people-fwd.hxx +people.hxx +people.ixx +people.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by XSD from people.xsd with the +  --custom-type option in order to customize the person, superman, and +  batman types. Generation of the people-fwd.hxx forward declaration +  file is requested with the --generate-forward option. Note also that  +  we use the --generate-polymorphic command line option as well as  +  --polymorphic-type to mark the type hierarchy starting with the  +  person type as polymorphic. + +people-custom-fwd.hxx +  Header file which forward-declares our own person, superman, and batman +  as class templates. It is included at the beginning of people-fwd.hxx +  using the --fwd-prologue option. + +people-custom.hxx +  Header file which defines our own person, superman, and batman class +  templates by inheriting from the generated person_base, superman_base, +  and batman_base. It is included at the beginning of people.hxx using +  the --hxx-prologue option. + +people-custom.cxx +  Source file which contains the implementations and instantiations of +  our person, superman, and batman class templates. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the database to STDERR. + +To run the example on the sample XML instance document simply execute: + +$ ./driver people.xml diff --git a/xsd/examples/cxx/tree/custom/taxonomy/driver.cxx b/xsd/examples/cxx/tree/custom/taxonomy/driver.cxx new file mode 100644 index 0000000..ec562f6 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/driver.cxx @@ -0,0 +1,38 @@ +// file      : examples/cxx/tree/custom/taxonomy/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "people.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " people.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace people; + +    std::auto_ptr<catalog> c (catalog_ (argv[1])); + +    for (catalog::person_const_iterator i (c->person ().begin ()); +         i != c->person ().end (); ++i) +    { +      i->print (cerr); +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/custom/taxonomy/makefile b/xsd/examples/cxx/tree/custom/taxonomy/makefile new file mode 100644 index 0000000..5637f17 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/makefile @@ -0,0 +1,122 @@ +# file      : examples/cxx/tree/custom/taxonomy/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := people.xsd +cxx := driver.cxx people-custom.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=-fwd.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd + +# We have to double-escape '#' because the message function +# (which is used in command scripts) expands things twice. +# +$(gen): xsd_options += \ +--generate-inline \ +--generate-forward \ +--generate-polymorphic \ +--polymorphic-type person \ +--custom-type "person=person_impl<person_base>/person_base" \ +--custom-type "superman=superman_impl<superman_base>/superman_base" \ +--custom-type "batman=batman_impl<batman_base>/batman_base" \ +--fwd-prologue '\#include "people-custom-fwd.hxx"' \ +--hxx-prologue '\#include "people-custom.hxx"' + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(install_doc_dir)/xsd/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(install_doc_dir)/xsd/$(path)/people.xml) +	$(call install-data,$(src_base)/people-custom.hxx,$(install_doc_dir)/xsd/$(path)/people-custom.hxx) +	$(call install-data,$(src_base)/people-custom.cxx,$(install_doc_dir)/xsd/$(path)/people-custom.cxx) +	$(call install-data,$(src_base)/people-custom-fwd.hxx,$(install_doc_dir)/xsd/$(path)/people-custom-fwd.hxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(dist_prefix)/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(dist_prefix)/$(path)/people.xml) +	$(call install-data,$(src_base)/people-custom.hxx,$(dist_prefix)/$(path)/people-custom.hxx) +	$(call install-data,$(src_base)/people-custom.cxx,$(dist_prefix)/$(path)/people-custom.cxx) +	$(call install-data,$(src_base)/people-custom-fwd.hxx,$(dist_prefix)/$(path)/people-custom-fwd.hxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/taxonomy/people-custom-fwd.hxx b/xsd/examples/cxx/tree/custom/taxonomy/people-custom-fwd.hxx new file mode 100644 index 0000000..2c26bf5 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/people-custom-fwd.hxx @@ -0,0 +1,19 @@ +// file      : examples/cxx/tree/custom/taxonomy/people-custom-fwd.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use people-fwd.hxx instead. This +// file is included into generated people-fwd.hxx so we do not need to +// guard against multiple inclusions. +// + +namespace people +{ +  template <typename base> +  class person_impl; + +  template <typename base> +  class superman_impl; + +  template <typename base> +  class batman_impl; +} diff --git a/xsd/examples/cxx/tree/custom/taxonomy/people-custom.cxx b/xsd/examples/cxx/tree/custom/taxonomy/people-custom.cxx new file mode 100644 index 0000000..a06a6ea --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/people-custom.cxx @@ -0,0 +1,156 @@ +// file      : examples/cxx/tree/custom/taxonomy/people-custom.cxx +// copyright : not copyrighted - public domain + +#include <ostream> + +// Include people.hxx instead of people-custom.hxx here. +// +#include "people.hxx" + +namespace people +{ +  // person_impl +  // +  template <typename base> +  person_impl<base>:: +  person_impl (const xml_schema::string& name) +      : base (name) +  { +  } + +  template <typename base> +  person_impl<base>:: +  person_impl (const xercesc::DOMElement& e, +               xml_schema::flags f, +               xml_schema::container* c) +      : base (e, f, c) +  { +  } + +  template <typename base> +  person_impl<base>:: +  person_impl (const person_impl& p, +               xml_schema::flags f, +               xml_schema::container* c) +      : base (p, f, c) +  { +  } + +  template <typename base> +  person_impl<base>* person_impl<base>:: +  _clone (xml_schema::flags f, xml_schema::container* c) const +  { +    return new person_impl (*this, f, c); +  } + +  template <typename base> +  void person_impl<base>:: +  print (std::ostream& os) const +  { +    os << this->name () << std::endl; +  } + +  // Explicitly instantiate person_impl class template for person_base. +  // +  template class person_impl<person_base>; + + +  // superman_impl +  // +  template <typename base> +  superman_impl<base>:: +  superman_impl (const xml_schema::string& name, bool can_fly) +      : base (name, can_fly) +  { +  } + +  template <typename base> +  superman_impl<base>:: +  superman_impl (const xercesc::DOMElement& e, +                 xml_schema::flags f, +                 xml_schema::container* c) +      : base (e, f, c) +  { +  } + +  template <typename base> +  superman_impl<base>:: +  superman_impl (const superman_impl& s, +                 xml_schema::flags f, +                 xml_schema::container* c) +      : base (s, f, c) +  { +  } + +  template <typename base> +  superman_impl<base>* superman_impl<base>:: +  _clone (xml_schema::flags f, xml_schema::container* c) const +  { +    return new superman_impl (*this, f, c); +  } + +  template <typename base> +  void superman_impl<base>:: +  print (std::ostream& os) const +  { +    if (this->can_fly ()) +      os << "Flying superman "; +    else +      os << "Superman "; + +    os << this->name () << std::endl; +  } + +  // Explicitly instantiate superman_impl class template for superman_base. +  // +  template class superman_impl<superman_base>; + + +  // batman_impl +  // +  template <typename base> +  batman_impl<base>:: +  batman_impl (const xml_schema::string& name, +               bool can_fly, +               unsigned int wing_span) +      : base (name, can_fly, wing_span) +  { +  } + +  template <typename base> +  batman_impl<base>:: +  batman_impl (const xercesc::DOMElement& e, +               xml_schema::flags f, +               xml_schema::container* c) +      : base (e, f, c) +  { +  } + +  template <typename base> +  batman_impl<base>:: +  batman_impl (const batman_impl& s, +               xml_schema::flags f, +               xml_schema::container* c) +      : base (s, f, c) +  { +  } + +  template <typename base> +  batman_impl<base>* batman_impl<base>:: +  _clone (xml_schema::flags f, xml_schema::container* c) const +  { +    return new batman_impl (*this, f, c); +  } + +  template <typename base> +  void batman_impl<base>:: +  print (std::ostream& os) const +  { +    os << "Batman " << this->name () << " with " << +      this->wing_span () << "m wing span" << std::endl; +  } + +  // Explicitly instantiate batman_impl class template for batman_base. +  // +  template class batman_impl<batman_base>; +} diff --git a/xsd/examples/cxx/tree/custom/taxonomy/people-custom.hxx b/xsd/examples/cxx/tree/custom/taxonomy/people-custom.hxx new file mode 100644 index 0000000..a60edc8 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/people-custom.hxx @@ -0,0 +1,96 @@ +// file      : examples/cxx/tree/custom/taxonomy/people-custom.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use people.hxx instead. This +// file is included into generated people.hxx so we do not need to +// guard against multiple inclusions. +// + +#include <iosfwd> // std::ostream + +// Include people-fwd.hxx here so that we can refer to the generated +// types. +// +#include "people-fwd.hxx" + +namespace people +{ +  // +  // +  template <typename base> +  class person_impl: public base +  { +  public: +    person_impl (const xml_schema::string& name); + +    person_impl (const xercesc::DOMElement&, +                 xml_schema::flags = 0, +                 xml_schema::container* = 0); + +    person_impl (const person_impl&, +                 xml_schema::flags = 0, +                 xml_schema::container* = 0); + +    virtual person_impl* +    _clone (xml_schema::flags = 0, +            xml_schema::container* = 0) const; + +  public: +    virtual void +    print (std::ostream&) const; +  }; + + +  // +  // +  template <typename base> +  class superman_impl: public base +  { +  public: +    superman_impl (const xml_schema::string& name, bool can_fly); + +    superman_impl (const xercesc::DOMElement&, +                   xml_schema::flags = 0, +                   xml_schema::container* = 0); + +    superman_impl (const superman_impl&, +                   xml_schema::flags = 0, +                   xml_schema::container* = 0); + +    virtual superman_impl* +    _clone (xml_schema::flags = 0, +            xml_schema::container* = 0) const; + +  public: +    virtual void +    print (std::ostream&) const; +  }; + + +  // +  // +  template <typename base> +  class batman_impl: public base +  { +  public: +    batman_impl (const xml_schema::string& name, +                 bool can_fly, +                 unsigned int wing_span); + +    batman_impl (const xercesc::DOMElement&, +                 xml_schema::flags = 0, +                 xml_schema::container* = 0); + +    batman_impl (const batman_impl&, +                 xml_schema::flags = 0, +                 xml_schema::container* = 0); + +    virtual batman_impl* +    _clone (xml_schema::flags = 0, +            xml_schema::container* = 0) const; + +  public: +    virtual void +    print (std::ostream&) const; +  }; +} diff --git a/xsd/examples/cxx/tree/custom/taxonomy/people.xml b/xsd/examples/cxx/tree/custom/taxonomy/people.xml new file mode 100644 index 0000000..b53b576 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/people.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/taxonomy/people.xml +copyright : not copyrighted - public domain + +--> + +<ppl:catalog xmlns:ppl="http://www.codesynthesis.com/people" +	     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	     xsi:schemaLocation="http://www.codesynthesis.com/people people.xsd"> + +  <person> +    <name>Joe Dirt</name> +  </person> + +  <person xsi:type="ppl:superman" can-fly="false"> +    <name>James "007" Bond</name> +  </person> + +  <person xsi:type="ppl:batman" can-fly="true" wing-span="10"> +    <name>Bruce Wayne</name> +  </person> + +</ppl:catalog> diff --git a/xsd/examples/cxx/tree/custom/taxonomy/people.xsd b/xsd/examples/cxx/tree/custom/taxonomy/people.xsd new file mode 100644 index 0000000..1181270 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/taxonomy/people.xsd @@ -0,0 +1,44 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/taxonomy/people.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:ppl="http://www.codesynthesis.com/people" +            targetNamespace="http://www.codesynthesis.com/people"> + +  <xsd:complexType name="person"> +    <xsd:sequence> +      <xsd:element name="name" type="xsd:string"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="superman"> +    <xsd:complexContent> +      <xsd:extension base="ppl:person"> +        <xsd:attribute name="can-fly" type="xsd:boolean" use="required"/> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:complexType name="batman"> +    <xsd:complexContent> +      <xsd:extension base="ppl:superman"> +        <xsd:attribute name="wing-span" type="xsd:unsignedInt" use="required"/> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:complexType name="catalog"> +    <xsd:sequence> +      <xsd:element name="person" type="ppl:person" maxOccurs="unbounded"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:element name="catalog" type="ppl:catalog"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/custom/wildcard/README b/xsd/examples/cxx/tree/custom/wildcard/README new file mode 100644 index 0000000..70eaea4 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/wildcard/README @@ -0,0 +1,45 @@ +This example shows how to use type customization to parse and serialize +a specific attribute that is matched by a wildcard (anyAttribute). The +example achieves this by customizing the type to include the data +members and accessors/modifiers that represent the attribute as well as +the parsing constructor and serialization operator where the attribute +value is extracted from and inserted back to DOM, respectively. For +more information on the C++/Tree mapping customization see the C++/Tree +Mapping Customization Guide[1]. + +[1] http://wiki.codesynthesis.com/Tree/Customization_guide + +The example consists of the following files: + +wildcard.xsd +  XML Schema definition for simple data type and element. + +wildcard.xml +  Sample XML instance document. + +wildcard.hxx +wildcard.ixx +wildcard.cxx +  C++ types that represent the given vocabulary, a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model, and a set of serialization functions that convert the +  object model back to XML. These are generated by XSD from wildcard.xsd +  with the --custom-type option in order to customize the data type. + +wildcard-custom.hxx +  Header file which defines our own data class by inheriting from the +  generated data_base. It is included at the end of wildcard.hxx using +  the --hxx-epilogue option. + +wildcard-custom.cxx +  Source file which contains the implementation of our data class. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the data to STDERR, including the extra attribute. Finally, the driver +  serializes the object model back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver wildcard.xml diff --git a/xsd/examples/cxx/tree/custom/wildcard/driver.cxx b/xsd/examples/cxx/tree/custom/wildcard/driver.cxx new file mode 100644 index 0000000..d29f125 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/wildcard/driver.cxx @@ -0,0 +1,47 @@ +// file      : examples/cxx/tree/custom/wildcard/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "wildcard.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " wildcard.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace wildcard; + +    // Parse. +    // +    std::auto_ptr<data> d (data_ (argv[1])); + +    // Print. +    // +    cerr << *d << endl; + +    // Serialize. +    // +    xml_schema::namespace_infomap map; + +    map["wc"].name = "http://www.codesynthesis.com/wildcard"; +    map["wc"].schema = "wildcard.xsd"; + +    data_ (std::cout, *d, map); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/custom/wildcard/makefile b/xsd/examples/cxx/tree/custom/wildcard/makefile new file mode 100644 index 0000000..55e94b0 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/wildcard/makefile @@ -0,0 +1,116 @@ +# file      : examples/cxx/tree/custom/wildcard/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := wildcard.xsd +cxx := driver.cxx wildcard-custom.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd + +# We have to double-escape '#' because the message function +# (which is used in command scripts) expands things twice. +# +$(gen): xsd_options += \ +--generate-inline \ +--generate-ostream \ +--generate-serialization \ +--custom-type data=/data_base \ +--hxx-epilogue '\#include "wildcard-custom.hxx"' + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/wildcard.xsd,$(install_doc_dir)/xsd/$(path)/wildcard.xsd) +	$(call install-data,$(src_base)/wildcard.xml,$(install_doc_dir)/xsd/$(path)/wildcard.xml) +	$(call install-data,$(src_base)/wildcard-custom.hxx,$(install_doc_dir)/xsd/$(path)/wildcard-custom.hxx) +	$(call install-data,$(src_base)/wildcard-custom.cxx,$(install_doc_dir)/xsd/$(path)/wildcard-custom.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/wildcard.xsd,$(dist_prefix)/$(path)/wildcard.xsd) +	$(call install-data,$(src_base)/wildcard.xml,$(dist_prefix)/$(path)/wildcard.xml) +	$(call install-data,$(src_base)/wildcard-custom.hxx,$(dist_prefix)/$(path)/wildcard-custom.hxx) +	$(call install-data,$(src_base)/wildcard-custom.cxx,$(dist_prefix)/$(path)/wildcard-custom.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/custom/wildcard/wildcard-custom.cxx b/xsd/examples/cxx/tree/custom/wildcard/wildcard-custom.cxx new file mode 100644 index 0000000..006f93a --- /dev/null +++ b/xsd/examples/cxx/tree/custom/wildcard/wildcard-custom.cxx @@ -0,0 +1,84 @@ +// file      : examples/cxx/tree/custom/wildcard/wildcard-custom.cxx +// copyright : not copyrighted - public domain + +#include <ostream> + +// Include wildcard.hxx instead of wildcard-custom.hxx here. +// +#include "wildcard.hxx" + +namespace wildcard +{ +  data:: +  data (const xml_schema::string& d) +      : data_base (d), scope_present_ (false) +  { +  } + +  data:: +  data (const xercesc::DOMElement& e, +        xml_schema::flags f, +        xml_schema::container* c) +      : data_base (e, f, c), scope_present_ (false) +  { +    // Check if we've got the scope attribute. +    // +    namespace xml = xsd::cxx::xml; +    xml::string name ("scope"); + +    if (e.hasAttribute (name.c_str ())) +    { +      scope (xml::transcode<char> (e.getAttribute (name.c_str ()))); +    } +  } + +  data:: +  data (const data& d, +        xml_schema::flags f, +        xml_schema::container* c) +      : data_base (d, f, c), +        scope_present_ (d.scope_present_), +        scope_ (d.scope_) +  { +  } + +  data* data:: +  _clone (xml_schema::flags f, xml_schema::container* c) const +  { +    return new data (*this, f, c); +  } + +  void +  operator<< (xercesc::DOMElement& e, const data& x) +  { +    // Use our base to serialize data and id. +    // +    const data_base& b (x); +    e << b; + +    // Add the scope attribute if present. +    // +    if (x.scope_present ()) +    { +      namespace xml = xsd::cxx::xml; +      xml::string name ("scope"); +      xml::string value (x.scope ()); + +      e.setAttribute (name.c_str (), value.c_str ()); +    } +  } + +  std::ostream& +  operator<< (std::ostream& os, const data& x) +  { +    // Use our base to print date and id. +    // +    const data_base& b (x); +    os << b; + +    if (x.scope_present ()) +      os << std::endl << "scope: " << x.scope (); + +    return os; +  } +} diff --git a/xsd/examples/cxx/tree/custom/wildcard/wildcard-custom.hxx b/xsd/examples/cxx/tree/custom/wildcard/wildcard-custom.hxx new file mode 100644 index 0000000..0546d38 --- /dev/null +++ b/xsd/examples/cxx/tree/custom/wildcard/wildcard-custom.hxx @@ -0,0 +1,66 @@ +// file      : examples/cxx/tree/custom/wildcard/wildcard-custom.hxx +// copyright : not copyrighted - public domain + +// Do not include this file directly, use wildcard.hxx instead. This +// file is included into generated wildcard.hxx so we do not need to +// guard against multiple inclusions. +// + +namespace wildcard +{ +  class data: public data_base +  { +    // Standard constructors. +    // +  public: +    data (const xml_schema::string&); + +    data (const xercesc::DOMElement&, +          xml_schema::flags = 0, +          xml_schema::container* = 0); + +    data (const data&, +          xml_schema::flags = 0, +          xml_schema::container* = 0); + +    virtual data* +    _clone (xml_schema::flags = 0, +            xml_schema::container* = 0) const; + +    // Our customizations. +    // +  public: +    bool +    scope_present () const +    { +      return scope_present_; +    } + +    const xml_schema::string& +    scope () const +    { +      return scope_; +    } + +    void +    scope (const xml_schema::string& s) +    { +      scope_present_ = true; +      scope_ = s; +    } + +  private: +    bool scope_present_; +    xml_schema::string scope_; +  }; + +  // Serialization operator. +  // +  void +  operator<< (xercesc::DOMElement&, const data&); + +  // std::ostream insertion operator. +  // +  std::ostream& +  operator<< (std::ostream&, const data&); +} diff --git a/xsd/examples/cxx/tree/custom/wildcard/wildcard.xml b/xsd/examples/cxx/tree/custom/wildcard/wildcard.xml new file mode 100644 index 0000000..80f215a --- /dev/null +++ b/xsd/examples/cxx/tree/custom/wildcard/wildcard.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/wildcard/wildcard.xml +copyright : not copyrighted - public domain + +--> + +<wc:data xmlns:wc="http://www.codesynthesis.com/wildcard" +	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	 xsi:schemaLocation="http://www.codesynthesis.com/wildcard wildcard.xsd" +         id="1" +         scope="global">abc123</wc:data> diff --git a/xsd/examples/cxx/tree/custom/wildcard/wildcard.xsd b/xsd/examples/cxx/tree/custom/wildcard/wildcard.xsd new file mode 100644 index 0000000..1a32b1e --- /dev/null +++ b/xsd/examples/cxx/tree/custom/wildcard/wildcard.xsd @@ -0,0 +1,25 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/custom/wildcard/wildcard.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:wc="http://www.codesynthesis.com/wildcard" +            targetNamespace="http://www.codesynthesis.com/wildcard"> + +  <xsd:complexType name="data"> +    <xsd:simpleContent> +      <xsd:extension base="xsd:string"> +        <xsd:attribute name="id" type="xsd:unsignedInt"/> +        <xsd:anyAttribute namespace="##any" processContents="skip"/> +      </xsd:extension> +    </xsd:simpleContent> +  </xsd:complexType> + +  <xsd:element name="data" type="wc:data"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/embedded/README b/xsd/examples/cxx/tree/embedded/README new file mode 100644 index 0000000..266a8ff --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/README @@ -0,0 +1,48 @@ +This example shows how to embed the binary representation of the schema +grammar into an application and then use it with the C++/Tree mapping to  +parse and validate XML documents. This example is similar to the 'caching' +example except that it loads the binary representation of the schemas +embedded into the application instead of pre-parsing external schema files. + +The example consists of the following files: + +xsdbin.cxx +  Tool for converting one or more XML Schema files to the compressed binary +  representation. The output is written as a pair of C++ source files  +  containing the array with the binary data. Use the --help option to see +  the tool's usage information. + +library.xsd +  XML Schema which describes a library of books. + +library.xml +  Sample XML instance document. + +library.hxx +library.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by the XSD compiler from library.xsd. + +library-schema.hxx +library-schema.cxx +  Binary representation of the library.xsd schema. These files are generated +  by the xsdbin tool. + +grammar-input-stream.hxx +grammar-input-stream.cxx +  Input stream implementation with the special-purpose schema grammar  +  decompression algorithm. It is used to load the binary schema representation +  produced by the xsdbin tool. + +driver.cxx +  Driver for the example. It first sets up the Xerces-C++ DOM parser and +  loads the embedded binary schema grammar for validation. It then performs +  ten iterations that parse the input file to a DOM document using the DOM +  parser and call one of the parsing functions that constructs the object +  model from this DOM document. On each iteration the driver prints a number +  of books in the object model to STDERR. + +To run the example on the sample XML instance document simply execute: + +$ ./driver library.xml diff --git a/xsd/examples/cxx/tree/embedded/driver.cxx b/xsd/examples/cxx/tree/embedded/driver.cxx new file mode 100644 index 0000000..5ceafa4 --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/driver.cxx @@ -0,0 +1,183 @@ +// file      : examples/cxx/tree/embedded/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <fstream> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/XMLUniDefs.hpp> // chLatin_* +#include <xercesc/util/PlatformUtils.hpp> +#include <xercesc/validators/common/Grammar.hpp> // xercesc::Grammar +#include <xercesc/framework/Wrapper4InputSource.hpp> + +#include <xercesc/framework/XMLGrammarPoolImpl.hpp> + +#include <xsd/cxx/xml/string.hxx> +#include <xsd/cxx/xml/dom/auto-ptr.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> +#include <xsd/cxx/xml/sax/std-input-source.hxx> + +#include <xsd/cxx/tree/error-handler.hxx> + +#include "library.hxx" +#include "library-schema.hxx" +#include "grammar-input-stream.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml" << endl; +    return 1; +  } + +  int r (0); + +  // We need to initialize the Xerces-C++ runtime because we +  // are doing the XML-to-DOM parsing ourselves. +  // +  xercesc::XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace xercesc; +    namespace xml = xsd::cxx::xml; +    namespace tree = xsd::cxx::tree; + +    // Create and load the grammar pool. +    // +    MemoryManager* mm (XMLPlatformUtils::fgMemoryManager); + +    auto_ptr<XMLGrammarPool> gp (new XMLGrammarPoolImpl (mm)); + +    try +    { +      grammar_input_stream is (library_schema, sizeof (library_schema)); +      gp->deserializeGrammars(&is); +    } +    catch(const XSerializationException& e) +    { +      cerr << "unable to load schema: " << +        xml::transcode<char> (e.getMessage ()) << endl; +      return 1; +    } + +    // Lock the grammar pool. This is necessary if we plan to use the +    // same grammar pool in multiple threads (this way we can reuse the +    // same grammar in multiple parsers). Locking the pool disallows any +    // modifications to the pool, such as an attempt by one of the threads +    // to cache additional schemas. +    // +    gp->lockPool (); + +    // Get an implementation of the Load-Store (LS) interface. +    // +    const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; + +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls_id)); + +    xml::dom::auto_ptr<DOMLSParser> parser ( +      impl->createLSParser ( +        DOMImplementationLS::MODE_SYNCHRONOUS, 0, mm, gp.get ())); + +    DOMConfiguration* conf (parser->getDomConfig ()); + +    // Discard comment nodes in the document. +    // +    conf->setParameter (XMLUni::fgDOMComments, false); + +    // Enable datatype normalization. +    // +    conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); + +    // Do not create EntityReference nodes in the DOM tree. No +    // EntityReference nodes will be created, only the nodes +    // corresponding to their fully expanded substitution text +    // will be created. +    // +    conf->setParameter (XMLUni::fgDOMEntities, false); + +    // Perform namespace processing. +    // +    conf->setParameter (XMLUni::fgDOMNamespaces, true); + +    // Do not include ignorable whitespace in the DOM tree. +    // +    conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); + +    // Enable validation. +    // +    conf->setParameter (XMLUni::fgDOMValidate, true); +    conf->setParameter (XMLUni::fgXercesSchema, true); +    conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); + +    // Xerces-C++ 3.1.0 is the first version with working multi import +    // support. +    // +#if _XERCES_VERSION >= 30100 +    conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +    // Use the loaded grammar during parsing. +    // +    conf->setParameter (XMLUni::fgXercesUseCachedGrammarInParse, true); + +    // Disable loading schemas via other means (e.g., schemaLocation). +    // +    conf->setParameter (XMLUni::fgXercesLoadSchema, false); + +    // We will release the DOM document ourselves. +    // +    conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + +    // Set error handler. +    // +    tree::error_handler<char> eh; +    xml::dom::bits::error_handler_proxy<char> ehp (eh); +    conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +    // Parse XML documents. +    // +    for (unsigned long i (0); i < 10; ++i) +    { +      ifstream ifs; +      ifs.exceptions (ifstream::badbit | ifstream::failbit); +      ifs.open (argv[1]); + +      // Wrap the standard input stream. +      // +      xml::sax::std_input_source isrc (ifs, argv[1]); +      Wrapper4InputSource wrap (&isrc, false); + +      // Parse XML to DOM. +      // +      xml_schema::dom::auto_ptr<DOMDocument> doc (parser->parse (&wrap)); + +      eh.throw_if_failed<xml_schema::parsing> (); + +      // Parse DOM to the object model. +      // +      auto_ptr<library::catalog> c (library::catalog_ (*doc)); + +      cerr << "catalog with " << c->book ().size () << " books" << endl; +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    r = 1; +  } + +  xercesc::XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/embedded/grammar-input-stream.cxx b/xsd/examples/cxx/tree/embedded/grammar-input-stream.cxx new file mode 100644 index 0000000..f3a6d52 --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/grammar-input-stream.cxx @@ -0,0 +1,95 @@ +// file      : examples/cxx/tree/embedded/grammar-input-stream.cxx +// copyright : not copyrighted - public domain + +#include <cassert> +#include "grammar-input-stream.hxx" + +grammar_input_stream:: +grammar_input_stream (const XMLByte* data, std::size_t size) +      : data_ (data), +        size_ (size), +        pos_ (0), +        vpos_ (0), +        cseq_ (0), +        add_zero_ (false) +{ +} + +XMLFilePos grammar_input_stream:: +curPos () const +{ +  return static_cast<XMLFilePos> (vpos_); +} + +XMLSize_t grammar_input_stream:: +readBytes (XMLByte* const buf, const XMLSize_t size) +{ +  std::size_t i (0); + +  // Add a zero from the alternating sequence if it didn't +  // fit on the previous read. +  // +  if (add_zero_) +  { +    buf[i++] = 0; +    add_zero_ = false; +  } + +  // If have an unfinished sequential sequence, output it now. +  // +  if (cseq_ != 0 && !alt_) +  { +    for (; cseq_ != 0 && i < size; --cseq_) +      buf[i++] = 0; +  } + +  for (; i < size && pos_ < size_;) +  { +    XMLByte b = buf[i++] = data_[pos_++]; + +    // See if we are in a compression sequence. +    // +    if (cseq_ != 0) +    { +      if (i < size) +        buf[i++] = 0; +      else +        add_zero_ = true; // Add it on the next read. + +      cseq_--; +      continue; +    } + +    // If we are not in a compression sequence and this byte is +    // not zero then we are done. +    // +    if (b != 0) +      continue; + +    // We have a zero. +    // +    assert (pos_ < size_); // There has to be another byte. +    unsigned char v (static_cast<unsigned char> (data_[pos_++])); +    alt_ = (v & 128) != 0; +    cseq_ = v & 127; + +    // If it is a sequential sequence, output as many zeros as +    // we can. +    // +    if (!alt_) +    { +      for (; cseq_ != 0 && i < size; --cseq_) +        buf[i++] = 0; +    } +  } + +  vpos_ += i; + +  return static_cast<XMLSize_t> (i); +} + +const XMLCh* grammar_input_stream:: +getContentType () const +{ +  return 0; +} diff --git a/xsd/examples/cxx/tree/embedded/grammar-input-stream.hxx b/xsd/examples/cxx/tree/embedded/grammar-input-stream.hxx new file mode 100644 index 0000000..ed12b7c --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/grammar-input-stream.hxx @@ -0,0 +1,40 @@ +// file      : examples/cxx/tree/embedded/grammar-input-stream.hxx +// copyright : not copyrighted - public domain + +#ifndef GRAMMAR_INPUT_STREAM_HXX +#define GRAMMAR_INPUT_STREAM_HXX + +#include <cstddef> +#include <xercesc/util/BinInputStream.hpp> + +// Memory buffer input stream with the special-purpose schema +// grammar decompression. +// +class grammar_input_stream: public xercesc::BinInputStream +{ +public : +  grammar_input_stream (const XMLByte* data, std::size_t size); + +  virtual XMLFilePos +  curPos () const; + +  virtual XMLSize_t +  readBytes (XMLByte* const buf, const XMLSize_t size); + +  virtual const XMLCh* +  getContentType () const; + +private : +  const XMLByte* data_; +  std::size_t size_; +  std::size_t pos_; +  std::size_t vpos_; + +  // Compression data. +  // +  size_t cseq_;   // Number of bytes left in a compression sequence. +  bool alt_;      // Alternating or sequential sequence. +  bool add_zero_; // Add a zero on the next read. +}; + +#endif // GRAMMAR_INPUT_STREAM_HXX diff --git a/xsd/examples/cxx/tree/embedded/library.xml b/xsd/examples/cxx/tree/embedded/library.xml new file mode 100644 index 0000000..f57c042 --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/embedded/library.xml +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"> +    <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/xsd/examples/cxx/tree/embedded/library.xsd b/xsd/examples/cxx/tree/embedded/library.xsd new file mode 100644 index 0000000..6a9ad01 --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/library.xsd @@ -0,0 +1,72 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/embedded/library.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:xse="http://www.codesynthesis.com/xmlns/xml-schema-extension" +            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:language"/> +      </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:date"/> +      <xsd:element name="died" type="xsd:date" minOccurs="0"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="author"> +    <xsd:complexContent> +      <xsd:extension base="lib:person"> +	<xsd:attribute name="recommends" type="xsd:IDREF" xse:refType="lib: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" default="true"/> +    <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/xsd/examples/cxx/tree/embedded/makefile b/xsd/examples/cxx/tree/embedded/makefile new file mode 100644 index 0000000..d0fdc33 --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/makefile @@ -0,0 +1,123 @@ +# file      : examples/cxx/tree/embedded/makefile +# copyright : Copyright (c) 2005-2014 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 grammar-input-stream.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o) \ +$(xsd:.xsd=-schema.o)) +obj2 := $(out_base)/xsdbin.o +dep := $(obj:.o=.o.d) $(obj2:.o=.o.d) + +driver   := $(out_base)/driver +xsdbin   := $(out_base)/xsdbin +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) +$(xsdbin): $(obj2) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(obj2) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): $(out_root)/xsd/xsd + +genf += $(xsd:.xsd=-schema.hxx) $(xsd:.xsd=-schema.cxx) + +.PRECIOUS: $(out_base)/%-schema.hxx $(out_base)/%-schema.cxx +$(out_base)/%: xsdbin := $(xsdbin) +$(out_base)/%-schema.hxx $(out_base)/%-schema.cxx: $(src_base)/%.xsd $(xsdbin) +	$(call message,xsdbin $<,$(xsdbin) --output-dir $(out_base) $<) + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/xsdbin.cxx,$(install_doc_dir)/xsd/$(path)/xsdbin.cxx) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/grammar-input-stream.hxx,$(install_doc_dir)/xsd/$(path)/grammar-input-stream.hxx) +	$(call install-data,$(src_base)/grammar-input-stream.cxx,$(install_doc_dir)/xsd/$(path)/grammar-input-stream.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) + +$(dist-common): +	$(call install-data,$(src_base)/xsdbin.cxx,$(dist_prefix)/$(path)/xsdbin.cxx) +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/grammar-input-stream.hxx,$(dist_prefix)/$(path)/grammar-input-stream.hxx) +	$(call install-data,$(src_base)/grammar-input-stream.cxx,$(dist_prefix)/$(path)/grammar-input-stream.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +        # Note: solution files are not automatically generated. + +# Clean. +# +$(clean): files := $(out_base)/$(xsd:.xsd=-schema.?xx) +$(clean): $(driver).o.clean $(xsdbin).o.clean          \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(obj2))                      \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) +	$(call message,rm '$(out_base)/*-schema.?xx',rm -f $(files)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver xsdbin $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +$(call include,$(bld_root)/install.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/embedded/xsdbin.cxx b/xsd/examples/cxx/tree/embedded/xsdbin.cxx new file mode 100644 index 0000000..656b830 --- /dev/null +++ b/xsd/examples/cxx/tree/embedded/xsdbin.cxx @@ -0,0 +1,494 @@ +// file      : examples/cxx/tree/embedded/xsdbin.cxx +// copyright : not copyrighted - public domain + +// This program loads the XML Schema file(s) and converts them to +// the Xerces-C++ binary schema format which can then be embedded +// into C++ programs and used to validate XML documents. The output +// is written as a C++ source file containing the array with the +// binary data. +// + +#include <string> +#include <memory>   // std::auto_ptr +#include <cstddef>  // std::size_t +#include <fstream> +#include <iostream> + +#include <xercesc/util/XMLUni.hpp> +#include <xercesc/util/XMLString.hpp> +#include <xercesc/util/PlatformUtils.hpp> +#include <xercesc/util/XercesVersion.hpp> + +#include <xercesc/internal/BinMemOutputStream.hpp> +#include <xercesc/validators/common/Grammar.hpp> + +#include <xercesc/sax/ErrorHandler.hpp> +#include <xercesc/sax/SAXParseException.hpp> +#include <xercesc/sax2/SAX2XMLReader.hpp> +#include <xercesc/sax2/XMLReaderFactory.hpp> + +#include <xercesc/framework/XMLGrammarPoolImpl.hpp> + +using namespace std; +using namespace xercesc; + +class error_handler: public ErrorHandler +{ +public: +  error_handler () +      : failed_ (false) +  { +  } + +  bool +  failed () const +  { +    return failed_; +  } + +  enum severity {s_warning, s_error, s_fatal}; + +  virtual void +  warning (const SAXParseException&); + +  virtual void +  error (const SAXParseException&); + +  virtual void +  fatalError (const SAXParseException&); + +  virtual void +  resetErrors () +  { +    failed_ = false; +  } + +  void +  handle (const SAXParseException&, severity); + +private: +  bool failed_; +}; + +void +cxx_escape (string&); + +int +main (int argc, char* argv[]) +{ +  const char* hxx_suffix = "-schema.hxx"; +  const char* cxx_suffix = "-schema.cxx"; + +  string name; +  string base; +  string outdir; + +  struct usage +  { +    usage (bool e = true): error (e) {} +    bool error; +  }; + +  int argi (1); +  bool multi_import (true); +  bool verbose (false); + +  try +  { +    for (; argi < argc; ++argi) +    { +      string a (argv[argi]); + +      if (a == "--help") +        throw usage (false); +      else if (a == "--verbose") +      { +        verbose = true; +      } +      else if (a == "--hxx-suffix") +      { +        if (++argi >= argc) +          throw usage (); + +        hxx_suffix = argv[argi]; +      } +      else if (a == "--cxx-suffix") +      { +        if (++argi >= argc) +          throw usage (); + +        cxx_suffix = argv[argi]; +      } +      else if (a == "--output-dir") +      { +        if (++argi >= argc) +          throw usage (); + +        outdir = argv[argi]; +      } +      else if (a == "--array-name") +      { +        if (++argi >= argc) +          throw usage (); + +        name = argv[argi]; +      } +      else if (a == "--disable-multi-import") +      { +        multi_import = false; +      } +      else +        break; +    } + +    if (argi >= argc) +    { +      cerr << "no input file specified" << endl; +      throw usage (); +    } + +    base = argv[argi]; +  } +  catch (usage const& e) +  { +    ostream& o (e.error ? cerr : cout); + +    o << "Usage: " << argv[0] << " [options] <files>" << endl +      << "Options:" << endl +      << "  --help                 Print usage information and exit." << endl +      << "  --verbose              Print progress information." << endl +      << "  --output-dir <dir>     Write generated files to <dir>." << endl +      << "  --hxx-suffix <sfx>     Header file suffix instead of '-schema.hxx'." << endl +      << "  --cxx-suffix <sfx>     Source file suffix instead of '-schema.cxx'." << endl +      << "  --array-name <name>    Binary data array name." << endl +      << "  --disable-multi-import Disable multiple import support." << endl +      << endl; + +    return e.error ? 0 : 1; +  } + +  XMLPlatformUtils::Initialize (); + +  { +    MemoryManager* mm (XMLPlatformUtils::fgMemoryManager); + +    auto_ptr<XMLGrammarPool> gp (new XMLGrammarPoolImpl (mm)); + +    // Load the schemas into grammar pool. +    // +    { +      auto_ptr<SAX2XMLReader> parser ( +        XMLReaderFactory::createXMLReader (mm, gp.get ())); + +      parser->setFeature (XMLUni::fgSAX2CoreNameSpaces, true); +      parser->setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes, true); +      parser->setFeature (XMLUni::fgSAX2CoreValidation, true); +      parser->setFeature (XMLUni::fgXercesSchema, true); +      parser->setFeature (XMLUni::fgXercesSchemaFullChecking, true); +      parser->setFeature (XMLUni::fgXercesValidationErrorAsFatal, true); + +      // Xerces-C++ 3.1.0 is the first version with working multi import +      // support. +      // +#if _XERCES_VERSION >= 30100 +      parser->setFeature (XMLUni::fgXercesHandleMultipleImports, multi_import); +#endif + +      error_handler eh; +      parser->setErrorHandler (&eh); + +      for (; argi < argc; ++argi) +      { +        if (verbose) +          cerr << "loading " << argv[argi] << endl; + +        if (!parser->loadGrammar (argv[argi], Grammar::SchemaGrammarType, true)) +        { +          cerr << argv[argi] << ": error: unable to load" << endl; +          return 1; +        } + +        if (eh.failed ()) +          return 1; +      } +    } + +    // Get the binary representation. +    // +    BinMemOutputStream data; + +    try +    { +      gp->serializeGrammars (&data); +    } +    catch (const XSerializationException& e) +    { +      char* msg (XMLString::transcode (e.getMessage ())); +      cerr << "error: " << msg << endl; +      XMLString::release (&msg); +      return 1; +    } + +    size_t n (static_cast<size_t> (data.curPos ())); +    const unsigned char* buf ( +      static_cast<const unsigned char*> (data.getRawBuffer ())); + +    if (verbose) +      cerr << "uncomressed data size " << n << " bytes" << endl; + +    // Compress zeros. +    // +    size_t cn (0); +    unsigned char* cbuf = new unsigned char[n]; + +    size_t cseq (0);  // Number of bytes left in a compression sequence. +    bool alt (false); // Alternating or sequential sequence. + +    for (size_t i (0); i < n;) +    { +      unsigned char v (buf[i++]); + +      // See if we are in a compression sequence. +      // +      if (cseq != 0) +      { +        // See if this byte needs to be copied. +        // +        if (alt && cseq % 2 == 0) +          cbuf[cn++] = v; + +        cseq--; +        continue; +      } + +      // If we are not in a compression sequence and this byte is +      // not zero then simply copy it. +      // +      if (v != 0) +      { +        cbuf[cn++] = v; +        continue; +      } + +      // We have a zero. +      // +      cbuf[cn++] = 0; + +      // See if we can start a new compression sequence. +      // +      if (i < n) +      { +        if (buf[i] == 0) +        { +          // Sequential sequence. See how far it runs. +          // +          alt = false; + +          for (cseq = 1; cseq < 127 && cseq + i < n; cseq++) +            if (buf[cseq + i] != 0) +              break; +        } +        else if (i + 1 < n && buf[i + 1] == 0) +        { +          // Alternating sequence. See how far it runs. +          // +          alt = true; + +          for (cseq = 1; cseq < 127 && cseq * 2 + i + 1 < n; cseq++) +          { +            if (buf[cseq * 2 + i + 1] != 0) +              break; + +            // For longer sequences prefer sequential to alternating. +            // +            if (cseq > 2 && +                buf[cseq * 2 + i] == 0 && +                buf[(cseq - 1) * 2 + i] == 0 && +                buf[(cseq - 2) * 2 + i] == 0) +            { +              cseq -= 2; +              break; +            } +          } + +          cseq *= 2; +        } +      } + +      if (cseq != 0) +      { +        cbuf[cn++] = static_cast<unsigned char> ( +          alt ? (128  | cseq / 2) : cseq); +      } +      else +        cbuf[cn++] = 0; +    } + +    if (verbose) +      cerr << "comressed data size " << cn << " bytes" << endl; + +    buf = cbuf; +    n = cn; + +    // Figure out the file names. +    // +    string::size_type p (base.rfind ('/')), p1 (base.rfind ('\\')); + +    if (p1 != string::npos && p1 > p) +      p = p1; + +    if (p != string::npos) +      base = string (base, p + 1); + +    p = base.rfind ('.'); + +    if (p != string::npos) +      base.resize (p); + +    string hxx (base + hxx_suffix); +    string cxx (base + cxx_suffix); + +    if (!outdir.empty ()) +    { +#if defined (WIN32) || defined (__WIN32__) +      hxx = outdir + '\\' + hxx; +      cxx = outdir + '\\' + cxx; +#else +      hxx = outdir + '/' + hxx; +      cxx = outdir + '/' + cxx; +#endif +    } + +    if (name.empty ()) +    { +      name = base + "_schema"; +      cxx_escape (name); +    } + +    // Write header. +    // +    { +      ofstream os (hxx.c_str ()); + +      if (!os.is_open ()) +      { +        cerr << hxx << ": error: unable to open" << endl; +        return 1; +      } + +      os << "// Automatically generated. Do not edit." << endl +         << "//" << endl +         << endl +         << "#include <xercesc/util/XercesDefs.hpp>" << endl +         << endl +         << "extern const XMLByte " << name << "[" << n << "UL];" << endl; +    } + +    { +      ofstream os (cxx.c_str ()); + +      if (!os.is_open ()) +      { +        cerr << cxx << ": error: unable to open" << endl; +        return 1; +      } + +      os << "// Automatically generated. Do not edit." << endl +         << "//" << endl +         << endl +         << "#include <xercesc/util/XercesDefs.hpp>" << endl +         << "#include <xercesc/util/XercesVersion.hpp>" << endl +         << endl +         << "#if XERCES_GRAMMAR_SERIALIZATION_LEVEL != " << +        XERCES_GRAMMAR_SERIALIZATION_LEVEL << endl +         << "#  error incompatible Xerces-C++ version detected" << endl +         << "#endif" << endl +         << endl +         << "extern const XMLByte " << name << "[" << n << "UL] =" << endl +         << "{"; + +      for (size_t i (0); i < n; ++i) +      { +        if (i != 0) +          os << ','; + +        os << (i % 12 == 0 ? "\n  " : " ") << "0x"; +        os.width (2); +        os.fill ('0'); +        os << hex << static_cast<unsigned short> (buf[i]); +      } + +      os << endl +         << "};" << endl +         << endl; +    } + +    delete[] cbuf; +  } + +  XMLPlatformUtils::Terminate (); +} + +void +cxx_escape (string& s) +{ +  for (string::size_type i (0); i < s.size (); ++i) +  { +    char& c (s[i]); + +    if (i == 0) +    { +      if (!((c >= 'a' && c <= 'z') || +            (c >= 'A' && c <= 'Z') || +            c == '_')) +        c = '_'; +    } +    else +    { +      if (!((c >= 'a' && c <= 'z') || +            (c >= 'A' && c <= 'Z') || +            (c >= '0' && c <= '9') || +            c == '_')) +        c = '_'; +    } +  } +} + +void error_handler:: +warning (const SAXParseException& e) +{ +  handle (e, s_warning); +} + +void error_handler:: +error (const SAXParseException& e) +{ +  failed_ = true; +  handle (e, s_error); +} + +void error_handler:: +fatalError (const SAXParseException& e) +{ +  failed_ = true; +  handle (e, s_fatal); +} + +void error_handler:: +handle (const SAXParseException& e, severity s) +{ +  const XMLCh* xid (e.getPublicId ()); + +  if (xid == 0) +    xid = e.getSystemId (); + +  char* id (XMLString::transcode (xid)); +  char* msg (XMLString::transcode (e.getMessage ())); + +  cerr << id << ":" +       << e.getLineNumber () << ":" << e.getColumnNumber () << " " +       << (s == s_warning ? "warning: " : "error: ") << msg << endl; + +  XMLString::release (&id); +  XMLString::release (&msg); +} diff --git a/xsd/examples/cxx/tree/hello/README b/xsd/examples/cxx/tree/hello/README new file mode 100644 index 0000000..bb98584 --- /dev/null +++ b/xsd/examples/cxx/tree/hello/README @@ -0,0 +1,26 @@ +This is a "Hello, world!" example that shows how to use the C++/Tree +mapping to access XML instance documents described by XML Schema +definitions. + +The example consists of the following files: + +hello.xsd +  XML Schema which describes "hello" instance documents. + +hello.xml +  Sample XML instance document. + +hello.hxx +hello.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by XSD from hello.xsd. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the content of the object model to STDERR. + +To run the example on the sample XML instance document simply execute: + +$ ./driver hello.xml diff --git a/xsd/examples/cxx/tree/hello/driver.cxx b/xsd/examples/cxx/tree/hello/driver.cxx new file mode 100644 index 0000000..b6629b3 --- /dev/null +++ b/xsd/examples/cxx/tree/hello/driver.cxx @@ -0,0 +1,36 @@ +// file      : examples/cxx/tree/hello/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "hello.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " hello.xml" << endl; +    return 1; +  } + +  try +  { +    auto_ptr<hello_t> h (hello (argv[1])); + +    for (hello_t::name_const_iterator i (h->name ().begin ()); +         i != h->name ().end (); +         ++i) +    { +      cout << h->greeting () << ", " << *i << "!" << endl; +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/hello/hello.xml b/xsd/examples/cxx/tree/hello/hello.xml new file mode 100644 index 0000000..8b25b5b --- /dev/null +++ b/xsd/examples/cxx/tree/hello/hello.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/hello/hello.xml +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/xsd/examples/cxx/tree/hello/hello.xsd b/xsd/examples/cxx/tree/hello/hello.xsd new file mode 100644 index 0000000..8326ff0 --- /dev/null +++ b/xsd/examples/cxx/tree/hello/hello.xsd @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/hello/hello.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + +  <xsd:complexType name="hello_t"> + +    <xsd:annotation> +      <xsd:documentation> +        The hello_t type consists of a greeting phrase and a +        collection of names to which this greeting applies. +      </xsd:documentation> +    </xsd:annotation> + +    <xsd:sequence> + +      <xsd:element name="greeting" type="xsd:string"> +        <xsd:annotation> +          <xsd:documentation> +            The greeting element contains the greeting phrase +            for this hello object. +          </xsd:documentation> +        </xsd:annotation> +      </xsd:element> + +      <xsd:element name="name" type="xsd:string" maxOccurs="unbounded"> +        <xsd:annotation> +          <xsd:documentation> +            The name elements contains names to be greeted. +          </xsd:documentation> +        </xsd:annotation> +      </xsd:element> + +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:element name="hello" type="hello_t"> +    <xsd:annotation> +      <xsd:documentation> +        The hello element is a root of the Hello XML vocabulary. +        Every conforming document should start with this element. +      </xsd:documentation> +    </xsd:annotation> +  </xsd:element> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/hello/makefile b/xsd/examples/cxx/tree/hello/makefile new file mode 100644 index 0000000..2657fc6 --- /dev/null +++ b/xsd/examples/cxx/tree/hello/makefile @@ -0,0 +1,101 @@ +# file      : examples/cxx/tree/hello/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := hello.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/hello.xsd,$(install_doc_dir)/xsd/$(path)/hello.xsd) +	$(call install-data,$(src_base)/hello.xml,$(install_doc_dir)/xsd/$(path)/hello.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/hello.xsd,$(dist_prefix)/$(path)/hello.xsd) +	$(call install-data,$(src_base)/hello.xml,$(dist_prefix)/$(path)/hello.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/library/README b/xsd/examples/cxx/tree/library/README new file mode 100644 index 0000000..0b8638c --- /dev/null +++ b/xsd/examples/cxx/tree/library/README @@ -0,0 +1,32 @@ +This example shows how to use the C++/Tree mapping to parse XML documents +into a tree-like in-memory object model, modify this object model, and +finally serialize it back to XML. + +The example consists of the following files: + +library.xsd +  XML Schema which describes a library of books. + +library.xml +  Sample XML instance document. + +library.hxx +library.ixx +library.cxx +  C++ types that represent the given vocabulary, a set of parsing +  functions that convert XML documents to a tree-like in-memory object +  model, and a set of serialization functions that convert the object +  model back to XML. These are generated by XSD from library.xsd. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the content of the object model to STDERR. Finally, the driver modifies +  the object model and serializes it back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver library.xml + +This example also shows how to use the ID/IDREF cross-referencing +mechanism and the xsd:enumeration to C++ enum mapping. diff --git a/xsd/examples/cxx/tree/library/driver.cxx b/xsd/examples/cxx/tree/library/driver.cxx new file mode 100644 index 0000000..5913ddf --- /dev/null +++ b/xsd/examples/cxx/tree/library/driver.cxx @@ -0,0 +1,130 @@ +// file      : examples/cxx/tree/library/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "library.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " library.xml" << endl; +    return 1; +  } + +  try +  { +    using namespace library; + +    // Read in the XML file and obtain its object model. +    // +    std::auto_ptr<catalog> c (catalog_ (argv[1])); + + +    // Let's print what we've got. +    // +    for (catalog::book_const_iterator bi (c->book ().begin ()); +         bi != c->book ().end (); +         ++bi) +    { +      cerr << endl +           << "ID           : " << bi->id () << endl +           << "ISBN         : " << bi->isbn () << endl +           << "Title        : " << bi->title () << endl +           << "Genre        : " << bi->genre () << endl; + +      for (book::author_const_iterator ai (bi->author ().begin ()); +           ai != bi->author ().end (); +           ++ai) +      { +        cerr << "Author       : " << ai->name () << endl; +        cerr << "  Born       : " << ai->born () << endl; + +        if (ai->died ()) +          cerr << "  Died       : " << *ai->died () << endl; + +        if (ai->recommends ()) +          cerr << "  Recommends : " << (*ai->recommends ())->title () << endl; +      } + +      cerr  << "Available    : " << std::boolalpha << bi->available () << endl; +    } + + +    // Now we are going to modify the object model and serialize it +    // back to XML. +    // + +    catalog::book_sequence& books (c->book ()); + + +    // Get rid of all unavailable books. +    // +    for (catalog::book_iterator bi (books.begin ()); bi != books.end ();) +    { +      if (!bi->available ()) +        bi = books.erase (bi); +      else +        ++bi; +    } + + +    // Insert a new book. +    // +    book b (679776443,         // ISBN +            "Dead Souls",      // Title +            genre::philosophy, // Genre +            "DS");             // ID + +    b.author ().push_back (author ("Nikolai Gogol", +                                   xml_schema::date (1809, 3, 31))); + +    books.insert (books.begin (), b); + + +    // Because we removed all unavailable books, some IDREFs might be +    // broken. Let's fix this. +    // +    for (catalog::book_iterator bi (books.begin ()); bi != books.end (); ++bi) +    { +      for (book::author_iterator ai (bi->author ().begin ()); +           ai != bi->author ().end (); +           ++ai) +      { +        author::recommends_optional& c (ai->recommends ()); + +        if (c.present ()) +        { +          author::recommends_type& ref (c.get ()); + +          if (!ref) +            c.reset (); +        } +      } +    } + + +    // Prepare namespace mapping and schema location information. +    // +    xml_schema::namespace_infomap map; + +    map["lib"].name = "http://www.codesynthesis.com/library"; +    map["lib"].schema = "library.xsd"; + + +    // Write it out. +    // +    catalog_ (std::cout, *c, map); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/library/library.xml b/xsd/examples/cxx/tree/library/library.xml new file mode 100644 index 0000000..ca4ca9c --- /dev/null +++ b/xsd/examples/cxx/tree/library/library.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/library/library.xml +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"> +    <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/xsd/examples/cxx/tree/library/library.xsd b/xsd/examples/cxx/tree/library/library.xsd new file mode 100644 index 0000000..b183efc --- /dev/null +++ b/xsd/examples/cxx/tree/library/library.xsd @@ -0,0 +1,72 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/library/library.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:xse="http://www.codesynthesis.com/xmlns/xml-schema-extension" +            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:language"/> +      </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:date"/> +      <xsd:element name="died" type="xsd:date" minOccurs="0"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="author"> +    <xsd:complexContent> +      <xsd:extension base="lib:person"> +	<xsd:attribute name="recommends" type="xsd:IDREF" xse:refType="lib: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" default="true"/> +    <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/xsd/examples/cxx/tree/library/makefile b/xsd/examples/cxx/tree/library/makefile new file mode 100644 index 0000000..3db03de --- /dev/null +++ b/xsd/examples/cxx/tree/library/makefile @@ -0,0 +1,102 @@ +# file      : examples/cxx/tree/library/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := library.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-inline --generate-ostream \ +--generate-serialization +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(install_doc_dir)/xsd/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(install_doc_dir)/xsd/$(path)/library.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/library.xsd,$(dist_prefix)/$(path)/library.xsd) +	$(call install-data,$(src_base)/library.xml,$(dist_prefix)/$(path)/library.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/makefile b/xsd/examples/cxx/tree/makefile new file mode 100644 index 0000000..172195a --- /dev/null +++ b/xsd/examples/cxx/tree/makefile @@ -0,0 +1,70 @@ +# file      : examples/cxx/tree/makefile +# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make + +all_examples := binary caching embedded custom hello library messaging \ +mixed multiroot order performance polymorphism streaming wildcard \ +compression xpath + +build_examples := binary caching embedded custom hello library messaging \ +mixed multiroot order performance polymorphism streaming wildcard + +ifeq ($(xsd_with_zlib),y) +build_examples += compression +endif + +ifeq ($(xsd_with_xqilla),y) +build_examples += xpath +endif + +default  := $(out_base)/ +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Build. +# +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples))) + +# Install & Dist. +# +$(install) $(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base)) + +$(install): $(addprefix $(out_base)/,$(addsuffix /.install,$(all_examples))) +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) + +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): export dirs := $(shell find $(src_base) -type d -exec test -f {}/driver.cxx ';' -printf '%P ') +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,tree-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,tree-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,tree-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,tree-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,tree-vc12.sln) +	$(call meta-vctest,tree-vc8.sln,$(src_root)/dist/examples/test.bat,test.bat) + +# Clean. +# +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples))) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) +$(call include,$(bld_root)/meta/vctest.make) + +ifneq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile)) +else +$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile)) +endif diff --git a/xsd/examples/cxx/tree/messaging/README b/xsd/examples/cxx/tree/messaging/README new file mode 100644 index 0000000..435a4cf --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/README @@ -0,0 +1,58 @@ +This example shows how to handle XML vocabularies with multiple +root elements using the element type and element map features +of the C++/Tree mapping. The main purpose of element types is +to distinguish object models with the same root type but with +different root elements. The element map allows uniform parsing +and serialization of multiple root elements. + +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. Note that some request +  and response elements are of the same type. + +balance.xml +withdraw.xml +deposit.xml +  Sample XML instances for the protocol requests. + +protocol.hxx +protocol.cxx +  C++ types that represent the given vocabulary. These are +  generated by the XSD compiler from protocol.xsd. Generation of +  element types instead of parsing and serialization functions is +  requested with the --generate-element-type option. Generation of +  the element map is requested with the --generate-element-map +  option.  + +dom-parse.hxx +dom-parse.cxx +  Definition and implementation of the parse() function that +  parses an XML document to a DOM document. + +dom-serialize.hxx +dom-serialize.cxx +  Definition and implementation of the serialize() function that +  serializes a DOM document to XML. + +driver.cxx +  Driver for the example. It first calls the above-mentioned parse() +  function to parse the input file to a DOM document. It then calls +  the parse() function on the element map to parse the root document +  element to the object model. The object model is returned as a +  pointer to xml_schema::element_type which is a common base type for +  all element types. The driver then determines which request it has +  received either using RTTI or by comparing the root element names. +  Once the request type is determined, information about it is printed +  to STDERR and the corresponding response is created. Finally, the +  driver serializes the opaque response object to a DOM document +  using the element map and then serializes this DOM document to +  STDOUT using the above-mentioned serialize() function. +   +To run the example on the sample XML request documents simply +execute: + +$ ./driver balance.xml +$ ./driver withdraw.xml +$ ./driver deposit.xml diff --git a/xsd/examples/cxx/tree/messaging/balance.xml b/xsd/examples/cxx/tree/messaging/balance.xml new file mode 100644 index 0000000..83b9692 --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/balance.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/messaging/balance.xml +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/xsd/examples/cxx/tree/messaging/deposit.xml b/xsd/examples/cxx/tree/messaging/deposit.xml new file mode 100644 index 0000000..c59153d --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/deposit.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/messaging/deposit.xml +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/xsd/examples/cxx/tree/messaging/dom-parse.cxx b/xsd/examples/cxx/tree/messaging/dom-parse.cxx new file mode 100644 index 0000000..61f9f4a --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/dom-parse.cxx @@ -0,0 +1,93 @@ +// file      : examples/cxx/tree/messaging/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include <istream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/XMLUniDefs.hpp> // chLatin_* +#include <xercesc/framework/Wrapper4InputSource.hpp> + +#include <xsd/cxx/xml/sax/std-input-source.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> + +#include <xsd/cxx/tree/exceptions.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::auto_ptr<DOMDocument> +parse (std::istream& is, const std::string& id, bool validate) +{ +  const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; + +  // Get an implementation of the Load-Store (LS) interface. +  // +  DOMImplementation* impl ( +    DOMImplementationRegistry::getDOMImplementation (ls_id)); + +  xml::dom::auto_ptr<DOMLSParser> parser ( +    impl->createLSParser (DOMImplementationLS::MODE_SYNCHRONOUS, 0)); + +  DOMConfiguration* conf (parser->getDomConfig ()); + +  // Discard comment nodes in the document. +  // +  conf->setParameter (XMLUni::fgDOMComments, false); + +  // Enable datatype normalization. +  // +  conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); + +  // Do not create EntityReference nodes in the DOM tree. No +  // EntityReference nodes will be created, only the nodes +  // corresponding to their fully expanded substitution text +  // will be created. +  // +  conf->setParameter (XMLUni::fgDOMEntities, false); + +  // Perform namespace processing. +  // +  conf->setParameter (XMLUni::fgDOMNamespaces, true); + +  // Do not include ignorable whitespace in the DOM tree. +  // +  conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); + +  // Enable/Disable validation. +  // +  conf->setParameter (XMLUni::fgDOMValidate, validate); +  conf->setParameter (XMLUni::fgXercesSchema, validate); +  conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); + +  // Xerces-C++ 3.1.0 is the first version with working multi import +  // support. +  // +#if _XERCES_VERSION >= 30100 +  conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +  // We will release the DOM document ourselves. +  // +  conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + +  // Set error handler. +  // +  tree::error_handler<char> eh; +  xml::dom::bits::error_handler_proxy<char> ehp (eh); +  conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +  // Prepare input stream. +  // +  xml::sax::std_input_source isrc (is, id); +  Wrapper4InputSource wrap (&isrc, false); + +  xml::dom::auto_ptr<DOMDocument> doc (parser->parse (&wrap)); + +  eh.throw_if_failed<tree::parsing<char> > (); + +  return doc; +} diff --git a/xsd/examples/cxx/tree/messaging/dom-parse.hxx b/xsd/examples/cxx/tree/messaging/dom-parse.hxx new file mode 100644 index 0000000..6eccacd --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/dom-parse.hxx @@ -0,0 +1,22 @@ +// file      : examples/cxx/tree/messaging/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include <string> +#include <iosfwd> + +#include <xercesc/dom/DOMDocument.hpp> +#include <xsd/cxx/xml/dom/auto-ptr.hxx> + +// Parse an XML document from the standard input stream with an +// optional resource id. Resource id is used in diagnostics as +// well as to locate schemas referenced from inside the document. +// +xsd::cxx::xml::dom::auto_ptr<xercesc::DOMDocument> +parse (std::istream& is, +       const std::string& id, +       bool validate); + +#endif // DOM_PARSE diff --git a/xsd/examples/cxx/tree/messaging/dom-serialize.cxx b/xsd/examples/cxx/tree/messaging/dom-serialize.cxx new file mode 100644 index 0000000..dbf3370 --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/dom-serialize.cxx @@ -0,0 +1,64 @@ +// file      : examples/cxx/tree/messaging/dom-serialize.cxx +// copyright : not copyrighted - public domain + +#include "dom-serialize.hxx" + +#include <ostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/XMLUniDefs.hpp> + +#include <xsd/cxx/xml/string.hxx> +#include <xsd/cxx/xml/dom/auto-ptr.hxx> +#include <xsd/cxx/xml/dom/serialization-source.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> + +#include <xsd/cxx/tree/exceptions.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +void +serialize (std::ostream& os, +           const xercesc::DOMDocument& doc, +           const std::string& encoding) +{ +  const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; + +  // Get an implementation of the Load-Store (LS) interface. +  // +  DOMImplementation* impl ( +    DOMImplementationRegistry::getDOMImplementation (ls_id)); + +  tree::error_handler<char> eh; +  xml::dom::bits::error_handler_proxy<char> ehp (eh); + +  xml::dom::ostream_format_target oft (os); + +  // Create a DOMSerializer. +  // +  xml::dom::auto_ptr<DOMLSSerializer> writer ( +    impl->createLSSerializer ()); + +  DOMConfiguration* conf (writer->getDomConfig ()); + +  // Set error handler. +  // +  conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +  // Set some generally nice features. +  // +  conf->setParameter (XMLUni::fgDOMWRTDiscardDefaultContent, true); +  conf->setParameter (XMLUni::fgDOMWRTFormatPrettyPrint, true); +  conf->setParameter (XMLUni::fgDOMWRTXercesPrettyPrint, false); + +  xml::dom::auto_ptr<DOMLSOutput> out (impl->createLSOutput ()); +  out->setEncoding (xml::string (encoding).c_str ()); +  out->setByteStream (&oft); + +  writer->write (&doc, out.get ()); + +  eh.throw_if_failed<tree::serialization<char> > (); +} diff --git a/xsd/examples/cxx/tree/messaging/dom-serialize.hxx b/xsd/examples/cxx/tree/messaging/dom-serialize.hxx new file mode 100644 index 0000000..f80e22b --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/dom-serialize.hxx @@ -0,0 +1,20 @@ +// file      : examples/cxx/tree/messaging/dom-serialize.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_SERIALIZE +#define DOM_SERIALIZE + +#include <string> +#include <iosfwd> + +#include <xercesc/dom/DOMDocument.hpp> + +// Serialize a DOM document to XML which is written to the standard +// output stream. +// +void +serialize (std::ostream& os, +           const xercesc::DOMDocument& doc, +           const std::string& encoding = "UTF-8"); + +#endif // DOM_SERIALIZE diff --git a/xsd/examples/cxx/tree/messaging/driver.cxx b/xsd/examples/cxx/tree/messaging/driver.cxx new file mode 100644 index 0000000..095e2cd --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/driver.cxx @@ -0,0 +1,144 @@ +// file      : examples/cxx/tree/messaging/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <string> +#include <fstream> +#include <typeinfo> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/PlatformUtils.hpp> + +#include <xsd/cxx/xml/string.hxx> + +#include "dom-parse.hxx" +#include "dom-serialize.hxx" + +#include "protocol.hxx" + +using namespace std; +using namespace protocol; +using namespace xercesc; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " request.xml" << endl; +    return 1; +  } + +  int r (0); + +  // We need to initialize the Xerces-C++ runtime because we +  // are doing the XML-to-DOM parsing ourselves. +  // +  XMLPlatformUtils::Initialize (); + +  try +  { +    ifstream ifs; +    ifs.exceptions (ifstream::badbit | ifstream::failbit); +    ifs.open (argv[1]); + +    auto_ptr<xml_schema::element_type> req, res; + +    // Parse the XML request to a DOM document using the parse() +    // function from dom-parse.hxx. +    // +    { +      xml_schema::dom::auto_ptr<DOMDocument> doc (parse (ifs, argv[1], true)); +      DOMElement& root (*doc->getDocumentElement ()); + +      req = xml_schema::element_map::parse (root); +    } + +    // We can test which request we've got either using RTTI or by +    // comparing the element names, as shown below. +    // +    if (balance* b = dynamic_cast<balance*> (req.get ())) +    { +      account_t& a (b->value ()); + +      cerr << "balance request for acc# " << a.account () << endl; + +      res.reset (new success (balance_t (a.account (), 1000))); +    } +    else if (req->_name () == withdraw::name ()) +    { +      withdraw& w (static_cast<withdraw&> (*req)); +      change_t& c (w.value ()); + +      wcerr << "withdrawal request for acc# " << c.account () << ", " +            << "amount: " << c.amount () << endl; + +      if (c.amount () > 1000) +        res.reset (new insufficient_funds (balance_t (c.account (), 1000))); +      else +        res.reset (new success (balance_t (c.account (), 1000 - c.amount ()))); + +    } +    else if (req->_name () == deposit::name ()) +    { +      deposit& d (static_cast<deposit&> (*req)); +      change_t& c (d.value ()); + +      wcerr << "deposit request for acc# " << c.account () << ", " +            << "amount: " << c.amount () << endl; + +      res.reset (new success (balance_t (c.account (), 1000 + c.amount ()))); +    } + +    // Serialize the response to a DOM document. +    // +    namespace xml = xsd::cxx::xml; + +    const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; + +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls_id)); + +    const string& name (res->_name ()); +    const string& ns (res->_namespace ()); + +    xml_schema::dom::auto_ptr<DOMDocument> doc ( +      impl->createDocument ( +        xml::string (ns).c_str (), +        xml::string ("p:" + name).c_str (), +        0)); + +    xml_schema::element_map::serialize (*doc->getDocumentElement (), *res); + +    // Serialize the DOM document to XML using the serialize() function +    // from dom-serialize.hxx. +    // +    cout << "response:" << endl +         << endl; + +    serialize (cout, *doc); +  } +  catch (const xml_schema::no_element_info& e) +  { +    // This exception indicates that we tried to parse or serialize +    // an unknown element. +    // +    cerr << "unknown request: " << e.element_namespace () << "#" << +      e.element_name () << endl; +    r = 1; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    r = 1; +  } + +  XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/messaging/makefile b/xsd/examples/cxx/tree/messaging/makefile new file mode 100644 index 0000000..309147a --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/makefile @@ -0,0 +1,117 @@ +# file      : examples/cxx/tree/messaging/makefile +# copyright : Copyright (c) 2005-2014 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 dom-parse.cxx dom-serialize.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd + +$(gen): xsd_options += --root-element-all --generate-element-type \ +--generate-element-map --generate-serialization + +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/protocol.xsd,$(install_doc_dir)/xsd/$(path)/protocol.xsd) +	$(call install-data,$(src_base)/balance.xml,$(install_doc_dir)/xsd/$(path)/balance.xml) +	$(call install-data,$(src_base)/deposit.xml,$(install_doc_dir)/xsd/$(path)/deposit.xml) +	$(call install-data,$(src_base)/withdraw.xml,$(install_doc_dir)/xsd/$(path)/withdraw.xml) +	$(call install-data,$(src_base)/dom-parse.hxx,$(install_doc_dir)/xsd/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(install_doc_dir)/xsd/$(path)/dom-parse.cxx) +	$(call install-data,$(src_base)/dom-serialize.hxx,$(install_doc_dir)/xsd/$(path)/dom-serialize.hxx) +	$(call install-data,$(src_base)/dom-serialize.cxx,$(install_doc_dir)/xsd/$(path)/dom-serialize.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/protocol.xsd,$(dist_prefix)/$(path)/protocol.xsd) +	$(call install-data,$(src_base)/balance.xml,$(dist_prefix)/$(path)/balance.xml) +	$(call install-data,$(src_base)/deposit.xml,$(dist_prefix)/$(path)/deposit.xml) +	$(call install-data,$(src_base)/withdraw.xml,$(dist_prefix)/$(path)/withdraw.xml) +	$(call install-data,$(src_base)/dom-parse.hxx,$(dist_prefix)/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(dist_prefix)/$(path)/dom-parse.cxx) +	$(call install-data,$(src_base)/dom-serialize.hxx,$(dist_prefix)/$(path)/dom-serialize.hxx) +	$(call install-data,$(src_base)/dom-serialize.cxx,$(dist_prefix)/$(path)/dom-serialize.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/messaging/protocol.xsd b/xsd/examples/cxx/tree/messaging/protocol.xsd new file mode 100644 index 0000000..b371ba7 --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/protocol.xsd @@ -0,0 +1,53 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/messaging/protocol.xsd +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"> + +  <!-- types --> + +  <xsd:complexType name="account_t"> +    <xsd:sequence> +      <xsd:element name="account" type="xsd:unsignedInt"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="change_t"> +    <xsd:complexContent> +      <xsd:extension base="p:account_t"> +        <xsd:sequence> +          <xsd:element name="amount" type="xsd:unsignedInt"/> +        </xsd:sequence> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:complexType name="balance_t"> +    <xsd:complexContent> +      <xsd:extension base="p:account_t"> +        <xsd:sequence> +          <xsd:element name="balance" type="xsd:unsignedInt"/> +        </xsd:sequence> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <!-- request elements --> + +  <xsd:element name="balance" type="p:account_t"/> +  <xsd:element name="withdraw" type="p:change_t"/> +  <xsd:element name="deposit" type="p:change_t"/> + +  <!-- response elements --> + +  <xsd:element name="success" type="p:balance_t"/> +  <xsd:element name="insufficient-funds" type="p:balance_t"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/messaging/withdraw.xml b/xsd/examples/cxx/tree/messaging/withdraw.xml new file mode 100644 index 0000000..1f309f3 --- /dev/null +++ b/xsd/examples/cxx/tree/messaging/withdraw.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/messaging/withdraw.xml +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/xsd/examples/cxx/tree/mixed/README b/xsd/examples/cxx/tree/mixed/README new file mode 100644 index 0000000..fc23faa --- /dev/null +++ b/xsd/examples/cxx/tree/mixed/README @@ -0,0 +1,45 @@ +This example shows how to access the underlying DOM nodes in the +C++/Tree mapping in order to handle raw, "type-less content" such +as mixed content models, anyType/anySimpleType, and any/anyAttribute. + +For an alternative (and recommended) approach that employs ordered +types see the order/mixed example. + +For an alternative approach that employes type customization see +examples in the custom/ directory, in particular, custom/mixed and +custom/wildcard. + +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. + +text.hxx +text.cxx +  C++ types that represent the given vocabulary and a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model. These are generated by XSD from text.xsd. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then uses +  both the underlying DOM and statically-typed mapping to perform the +  transformation. + +To run the example on the sample XML instance document simply execute: + +$ ./driver text.xml diff --git a/xsd/examples/cxx/tree/mixed/driver.cxx b/xsd/examples/cxx/tree/mixed/driver.cxx new file mode 100644 index 0000000..17c3b55 --- /dev/null +++ b/xsd/examples/cxx/tree/mixed/driver.cxx @@ -0,0 +1,122 @@ +// file      : examples/cxx/tree/mixed/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include <xercesc/dom/DOM.hpp> + +#include "text.hxx" + +// The following transcode() utility function is handy when working with +// Xerces. Include it after the generated header in order to get only char +// or wchar_t version depending on how you compiled your schemas. +// +#include <xsd/cxx/xml/string.hxx> + +using std::cout; +using std::cerr; +using std::endl; +using std::auto_ptr; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " text.xml" << endl; +    return 1; +  } + +  using namespace xercesc; + +  int r (0); + +  // The Xerces-C++ DOM objects that will be associated with the +  // document tree "out-live" the call to the parsing function. +  // Therefore we need to initialize the Xerces-C++ runtime +  // ourselves. +  // +  XMLPlatformUtils::Initialize (); + +  try +  { +    auto_ptr<text> t ( +      text_ (argv[1], +             xml_schema::flags::keep_dom | +             xml_schema::flags::dont_initialize)); + +    // The DOM association can be recreated in a copy (the underlying +    // DOM document is cloned) if explicitly requested with the keep_dom +    // flag and only if this copy is "complete", i.e., made from the root +    // of the tree. +    // +    text copy (*t, xml_schema::flags::keep_dom); + +    // Print text. +    // +    { +      namespace xml = xsd::cxx::xml; + +      unsigned long ref (0); +      DOMNode* root (copy._node ()); + +      for (DOMNode* n (root->getFirstChild ()); +           n != 0; +           n = n->getNextSibling ()) +      { +        switch (n->getNodeType ()) +        { +        case DOMNode::TEXT_NODE: +          { +            cout << xml::transcode<char> (n->getTextContent ()); +            break; +          } +        case DOMNode::ELEMENT_NODE: +          { +            // Let's get back to a tree node from this DOM node. +            // +            xml_schema::type& t ( +              *reinterpret_cast<xml_schema::type*> ( +                n->getUserData (xml_schema::dom::tree_node_key))); + +	    anchor& a (dynamic_cast<anchor&> (t)); + +            cout << a << "[" << ref << "]"; + +            // Or we could continue using DOM interface: +            // +            //cout << xml::transcode<char> (n->getTextContent ()) +            //     << "[" << ref << "]"; + +            ++ref; +            break; +          } +        default: +          break; // Ignore all other nodes (e.g., comments, etc). +        } +      } +    } + +    // Print references. +    // +    { +      unsigned long r (0); + +      for (text::a_const_iterator i (copy.a ().begin ()); +           i != copy.a ().end (); +           ++i, ++r) +      { +        cout << "[" << r << "] "  << i->href () << endl; +      } +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } + +  XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/mixed/makefile b/xsd/examples/cxx/tree/mixed/makefile new file mode 100644 index 0000000..7c001f0 --- /dev/null +++ b/xsd/examples/cxx/tree/mixed/makefile @@ -0,0 +1,102 @@ +# file      : examples/cxx/tree/mixed/makefile +# copyright : Copyright (c) 2005-2014 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=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/text.xsd,$(install_doc_dir)/xsd/$(path)/text.xsd) +	$(call install-data,$(src_base)/text.xml,$(install_doc_dir)/xsd/$(path)/text.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/text.xsd,$(dist_prefix)/$(path)/text.xsd) +	$(call install-data,$(src_base)/text.xml,$(dist_prefix)/$(path)/text.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/mixed/text.xml b/xsd/examples/cxx/tree/mixed/text.xml new file mode 100644 index 0000000..21e32af --- /dev/null +++ b/xsd/examples/cxx/tree/mixed/text.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/mixed/text.xml +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/xsd/examples/cxx/tree/mixed/text.xsd b/xsd/examples/cxx/tree/mixed/text.xsd new file mode 100644 index 0000000..9777f8a --- /dev/null +++ b/xsd/examples/cxx/tree/mixed/text.xsd @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/mixed/text.xsd +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:anyURI" 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/xsd/examples/cxx/tree/multiroot/README b/xsd/examples/cxx/tree/multiroot/README new file mode 100644 index 0000000..b742422 --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/README @@ -0,0 +1,45 @@ +This example shows how to handle XML vocabularies with multiple +root elements using the C++/Tree mapping. + +See also the messaging example for an alternative approach that +uses the element type and element map features of the C++/Tree +mapping. + +The example consists of the following files: + +protocol.xsd +  XML Schema which defines a simple bank account protocol with +  requests such as withdraw and deposit. + +balance.xml +withdraw.xml +deposit.xml +  Sample XML instances for the protocol requests. + +protocol.hxx +protocol.cxx +  C++ types that represent the given vocabulary and a set of +  parsing functions that convert XML documents to a tree-like +  in-memory object model. These are generated by XSD from +  protocol.xsd. + +dom-parse.hxx +dom-parse.cxx +  Definition and implementation of the parse() function that +  parses an XML document to a DOM document. + +driver.cxx +  Driver for the example. It first calls the above parse() function +  to parse the input file to a DOM document. It then determines the +  type of request being handled and calls the corresponding parsing +  function that constructs the object model from this DOM document. +  Finally, it prints the content of this object model to STDERR. +  This example intentionally does not support the deposit request +  to show how to handle unknown documents. + +To run the example on the sample XML request documents simply +execute: + +$ ./driver balance.xml +$ ./driver withdraw.xml +$ ./driver deposit.xml diff --git a/xsd/examples/cxx/tree/multiroot/balance.xml b/xsd/examples/cxx/tree/multiroot/balance.xml new file mode 100644 index 0000000..68b434a --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/balance.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/multiroot/balance.xml +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/xsd/examples/cxx/tree/multiroot/deposit.xml b/xsd/examples/cxx/tree/multiroot/deposit.xml new file mode 100644 index 0000000..4d9449a --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/deposit.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/multiroot/deposit.xml +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/xsd/examples/cxx/tree/multiroot/dom-parse.cxx b/xsd/examples/cxx/tree/multiroot/dom-parse.cxx new file mode 100644 index 0000000..98fc82e --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/dom-parse.cxx @@ -0,0 +1,93 @@ +// file      : examples/cxx/tree/multiroot/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include <istream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/XMLUniDefs.hpp> // chLatin_* +#include <xercesc/framework/Wrapper4InputSource.hpp> + +#include <xsd/cxx/xml/sax/std-input-source.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> + +#include <xsd/cxx/tree/exceptions.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::auto_ptr<DOMDocument> +parse (std::istream& is, const std::string& id, bool validate) +{ +  const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; + +  // Get an implementation of the Load-Store (LS) interface. +  // +  DOMImplementation* impl ( +    DOMImplementationRegistry::getDOMImplementation (ls_id)); + +  xml::dom::auto_ptr<DOMLSParser> parser ( +    impl->createLSParser (DOMImplementationLS::MODE_SYNCHRONOUS, 0)); + +  DOMConfiguration* conf (parser->getDomConfig ()); + +  // Discard comment nodes in the document. +  // +  conf->setParameter (XMLUni::fgDOMComments, false); + +  // Enable datatype normalization. +  // +  conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); + +  // Do not create EntityReference nodes in the DOM tree. No +  // EntityReference nodes will be created, only the nodes +  // corresponding to their fully expanded substitution text +  // will be created. +  // +  conf->setParameter (XMLUni::fgDOMEntities, false); + +  // Perform namespace processing. +  // +  conf->setParameter (XMLUni::fgDOMNamespaces, true); + +  // Do not include ignorable whitespace in the DOM tree. +  // +  conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); + +  // Enable/Disable validation. +  // +  conf->setParameter (XMLUni::fgDOMValidate, validate); +  conf->setParameter (XMLUni::fgXercesSchema, validate); +  conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); + +  // Xerces-C++ 3.1.0 is the first version with working multi import +  // support. +  // +#if _XERCES_VERSION >= 30100 +  conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +  // We will release the DOM document ourselves. +  // +  conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + +  // Set error handler. +  // +  tree::error_handler<char> eh; +  xml::dom::bits::error_handler_proxy<char> ehp (eh); +  conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +  // Prepare input stream. +  // +  xml::sax::std_input_source isrc (is, id); +  Wrapper4InputSource wrap (&isrc, false); + +  xml::dom::auto_ptr<DOMDocument> doc (parser->parse (&wrap)); + +  eh.throw_if_failed<tree::parsing<char> > (); + +  return doc; +} diff --git a/xsd/examples/cxx/tree/multiroot/dom-parse.hxx b/xsd/examples/cxx/tree/multiroot/dom-parse.hxx new file mode 100644 index 0000000..c2ab0fb --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/dom-parse.hxx @@ -0,0 +1,22 @@ +// file      : examples/cxx/tree/multiroot/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include <string> +#include <iosfwd> + +#include <xercesc/dom/DOMDocument.hpp> +#include <xsd/cxx/xml/dom/auto-ptr.hxx> + +// Parse an XML document from the standard input stream with an +// optional resource id. Resource id is used in diagnostics as +// well as to locate schemas referenced from inside the document. +// +xsd::cxx::xml::dom::auto_ptr<xercesc::DOMDocument> +parse (std::istream& is, +       const std::string& id, +       bool validate); + +#endif // DOM_PARSE diff --git a/xsd/examples/cxx/tree/multiroot/driver.cxx b/xsd/examples/cxx/tree/multiroot/driver.cxx new file mode 100644 index 0000000..9497ef1 --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/driver.cxx @@ -0,0 +1,124 @@ +// file      : examples/cxx/tree/multiroot/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <string> +#include <fstream> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/PlatformUtils.hpp> + +#include <xsd/cxx/xml/string.hxx>       // xml::transcode + +#include "dom-parse.hxx" + +#include "protocol.hxx" + +using namespace std; +using namespace protocol; + +// Parse an XML document and return a pointer to request_t which can +// then be tested with dynamic_cast. If your vocabulary does not have +// a common base type for all root element types then you can use +// xml_schema::type which is a base for all generated types. +// +auto_ptr<request_t> +parse (istream& is, const string& id) +{ +  using namespace xercesc; +  namespace xml = xsd::cxx::xml; + +  // Parse an XML instance to a DOM document using the parse() +  // function from dom-parse.hxx. +  // +  xml_schema::dom::auto_ptr<DOMDocument> doc (parse (is, id, true)); + +  DOMElement* root (doc->getDocumentElement ()); + +  string ns (xml::transcode<char> (root->getNamespaceURI ())); +  string name (xml::transcode<char> (root->getLocalName ())); + +  auto_ptr<request_t> r; + +  // We could have handled the result directly in this function +  // instead of returning it as an opaque pointer and using +  // dynamic_cast later to figure out which request we are dealing +  // with. +  // +  if (ns == "http://www.codesynthesis.com/protocol") +  { +    if (name == "balance") +    { +      // Use the balance parsing function. +      // +      r.reset (balance (*doc).release ()); +    } +    else if (name == "withdraw") +    { +      // Use the withdraw parsing function. +      // +      r.reset (withdraw (*doc).release ()); +    } +  } + +  if (r.get () == 0) +    cerr << "ignoring unknown request: " << ns << "#" << name << endl; + +  return r; +} + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " request.xml" << endl; +    return 1; +  } + +  int r (0); + +  // We need to initialize the Xerces-C++ runtime because we +  // are doing the XML-to-DOM parsing ourselves. +  // +  xercesc::XMLPlatformUtils::Initialize (); + +  try +  { +    ifstream ifs; +    ifs.exceptions (ifstream::badbit | ifstream::failbit); +    ifs.open (argv[1]); + +    auto_ptr<request_t> r (parse (ifs, argv[1])); + +    // Let's print what we've got. +    // +    if (balance_t* b = dynamic_cast<balance_t*> (r.get ())) +    { +      cerr << "balance request for acc# " << b->account () << endl; +    } +    else if (withdraw_t* w = dynamic_cast<withdraw_t*> (r.get ())) +    { +      cerr << "withdrawal request for acc# " << w->account () << ", " +           << "amount: " << w->amount () << endl; +    } +    else +    { +      cerr << "unknown request" << endl; +    } +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    r = 1; +  } + +  xercesc::XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/multiroot/makefile b/xsd/examples/cxx/tree/multiroot/makefile new file mode 100644 index 0000000..4d6c907 --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/makefile @@ -0,0 +1,109 @@ +# file      : examples/cxx/tree/multiroot/makefile +# copyright : Copyright (c) 2005-2014 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 dom-parse.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --root-element-all +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/protocol.xsd,$(install_doc_dir)/xsd/$(path)/protocol.xsd) +	$(call install-data,$(src_base)/balance.xml,$(install_doc_dir)/xsd/$(path)/balance.xml) +	$(call install-data,$(src_base)/deposit.xml,$(install_doc_dir)/xsd/$(path)/deposit.xml) +	$(call install-data,$(src_base)/withdraw.xml,$(install_doc_dir)/xsd/$(path)/withdraw.xml) +	$(call install-data,$(src_base)/dom-parse.hxx,$(install_doc_dir)/xsd/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(install_doc_dir)/xsd/$(path)/dom-parse.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/protocol.xsd,$(dist_prefix)/$(path)/protocol.xsd) +	$(call install-data,$(src_base)/balance.xml,$(dist_prefix)/$(path)/balance.xml) +	$(call install-data,$(src_base)/deposit.xml,$(dist_prefix)/$(path)/deposit.xml) +	$(call install-data,$(src_base)/withdraw.xml,$(dist_prefix)/$(path)/withdraw.xml) +	$(call install-data,$(src_base)/dom-parse.hxx,$(dist_prefix)/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(dist_prefix)/$(path)/dom-parse.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/multiroot/protocol.xsd b/xsd/examples/cxx/tree/multiroot/protocol.xsd new file mode 100644 index 0000000..1121824 --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/protocol.xsd @@ -0,0 +1,50 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/multiroot/protocol.xsd +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_t"> +    <xsd:sequence> +      <xsd:element name="account" type="xsd:unsignedInt"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="balance_t"> +    <xsd:complexContent> +      <xsd:extension base="p:request_t"/> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:complexType name="withdraw_t"> +    <xsd:complexContent> +      <xsd:extension base="p:request_t"> +        <xsd:sequence> +          <xsd:element name="amount" type="xsd:unsignedInt"/> +        </xsd:sequence> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:complexType name="deposit_t"> +    <xsd:complexContent> +      <xsd:extension base="p:request_t"> +        <xsd:sequence> +          <xsd:element name="amount" type="xsd:unsignedInt"/> +        </xsd:sequence> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:element name="balance" type="p:balance_t"/> +  <xsd:element name="withdraw" type="p:withdraw_t"/> +  <xsd:element name="deposit" type="p:deposit_t"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/multiroot/withdraw.xml b/xsd/examples/cxx/tree/multiroot/withdraw.xml new file mode 100644 index 0000000..8f1dc54 --- /dev/null +++ b/xsd/examples/cxx/tree/multiroot/withdraw.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/multiroot/withdraw.xml +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/xsd/examples/cxx/tree/order/README b/xsd/examples/cxx/tree/order/README new file mode 100644 index 0000000..7125a2d --- /dev/null +++ b/xsd/examples/cxx/tree/order/README @@ -0,0 +1,11 @@ +This directory contains a number of examples that show how to use ordered +types to capture and maintain content order. The following list gives an +overview of each example: + +element +  Shows how to use ordered types to capture and maintain element order, +  including element wildcards. + +mixed +  Shows how to use ordered types to capture mixed content text and to +  maintain order information between elements and text. diff --git a/xsd/examples/cxx/tree/order/element/README b/xsd/examples/cxx/tree/order/element/README new file mode 100644 index 0000000..19f2381 --- /dev/null +++ b/xsd/examples/cxx/tree/order/element/README @@ -0,0 +1,35 @@ +This example shows how to use ordered types to capture and maintain +element order, including element wildcards. + +The example consists of the following files: + +transactions.xsd +  XML Schema which describes various bank transactions. A batch of +  transactions can contain any number of different transactions in +  any order but the order of transaction in the batch is significant. + +library.xml +  Sample XML instance document. + +transactions.hxx +transactions.cxx +  C++ types that represent the given vocabulary as well as a set of +  parsing and serialization functions. These are generated by XSD +  from transactions.xsd. Note that the --ordered-type option is +  used to indicate to the XSD compiler that the batch type is +  ordered. We also use the --generate-wildcard option to enable +  wildcard support. An element wildcard is used in the batch to +  allow transaction extensions. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input XML file. It then +  iterates over transactions in the batch using the content order +  sequence. The driver then performs various modifications of the +  object model while showing how to maintain the content order. +  Finally, it saves the modified transaction batch back to XML to +  verify that the content order is preserved in the output document. + +To run the example on the sample XML instance document simply execute: + +$ ./driver transactions.xml diff --git a/xsd/examples/cxx/tree/order/element/driver.cxx b/xsd/examples/cxx/tree/order/element/driver.cxx new file mode 100644 index 0000000..0ea6d6f --- /dev/null +++ b/xsd/examples/cxx/tree/order/element/driver.cxx @@ -0,0 +1,147 @@ +// file      : examples/cxx/tree/order/element/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <cassert> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/PlatformUtils.hpp> + +#include "transactions.hxx" + +// The following string class keeps us sane when working with Xerces. +// Include it after the generated header in order to get only char or +// wchar_t version depending on how you compiled your schemas. +// +#include <xsd/cxx/xml/string.hxx> + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " transactions.xml" << endl; +    return 1; +  } + +  using namespace xercesc; + +  int r (0); + +  // The Xerces-C++ DOM objects that will be used to store the +  // content matched by the wildcard "out-lives" the call to the +  // parsing function. Therefore we need to initialize the +  // Xerces-C++ runtime ourselves. +  // +  XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace transactions; + +    // Parse the batch. +    // +    std::auto_ptr<batch> b ( +      batch_ (argv[1], xml_schema::flags::dont_initialize)); + +    // Print what we've got in content order. +    // +    for (batch::content_order_const_iterator i (b->content_order ().begin ()); +         i != b->content_order ().end (); +         ++i) +    { +      switch (i->id) +      { +      case batch::balance_id: +        { +          const balance& t (b->balance ()[i->index]); +          cerr << t.account () << " balance" << endl; +          break; +        } +      case batch::withdraw_id: +        { +          const withdraw& t (b->withdraw ()[i->index]); +          cerr << t.account () << " withdraw " << t.amount () << endl; +          break; +        } +      case batch::deposit_id: +        { +          const deposit& t (b->deposit ()[i->index]); +          cerr << t.account () << " deposit " << t.amount () << endl; +          break; +        } +      case batch::any_id: +        { +          namespace xml = xsd::cxx::xml; + +          const DOMElement& e (b->any ()[i->index]); +          cerr << xml::transcode<char> (e.getLocalName ()) << endl; +          break; +        } +      default: +        { +          assert (false); // Unknown content id. +        } +      } +    } + +    cerr << endl; + +    // Modify the transaction batch. First remove the last transaction. +    // Note that we have to update both the content itself and content +    // order sequences. +    // +    batch::content_order_sequence& co (b->content_order ()); + +    co.pop_back (); +    b->withdraw ().pop_back (); + +    // Now add a few more transactions. Again we have to add both the +    // content and its ordering. The order information consists of the +    // content id and, in case of a sequence, the index. +    // +    b->deposit ().push_back (deposit (123456789, 100000)); +    co.push_back ( +      batch::content_order_type ( +        batch::deposit_id, b->deposit ().size () - 1)); + +    // The next transaction we add at the beginning of the batch. +    // +    b->balance ().push_back (balance (123456789)); +    co.insert (co.begin (), +               batch::content_order_type ( +                 batch::balance_id, b->balance ().size () - 1)); + +    // Note also that when we merely modify the content of one +    // of the elements in place, we don't need to update its +    // order. For example: +    // +    b->deposit ()[0].amount (2000000); + +    // Serialize the modified transaction batch back to XML. +    // +    xml_schema::namespace_infomap map; + +    map[""].name = "http://www.codesynthesis.com/transactions"; +    map[""].schema = "transactions.xsd"; +    map["te"].name = "http://www.codesynthesis.com/transactions-extras"; + +    batch_ (std::cout, +            *b, +            map, +            "UTF-8", +            xml_schema::flags::dont_initialize); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } + +  XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/order/element/makefile b/xsd/examples/cxx/tree/order/element/makefile new file mode 100644 index 0000000..272c17f --- /dev/null +++ b/xsd/examples/cxx/tree/order/element/makefile @@ -0,0 +1,100 @@ +# file      : examples/cxx/tree/order/element/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := transactions.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +# Build. +# +$(driver): $(obj) $(xerces_c.l) -lnsl + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-serialization --generate-wildcard \ +--ordered-type batch +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/transactions.xsd,$(install_doc_dir)/xsd/$(path)/transactions.xsd) +	$(call install-data,$(src_base)/transactions.xml,$(install_doc_dir)/xsd/$(path)/transactions.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/transactions.xsd,$(dist_prefix)/$(path)/transactions.xsd) +	$(call install-data,$(src_base)/transactions.xml,$(dist_prefix)/$(path)/transactions.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/order/element/transactions.xml b/xsd/examples/cxx/tree/order/element/transactions.xml new file mode 100644 index 0000000..4c317c2 --- /dev/null +++ b/xsd/examples/cxx/tree/order/element/transactions.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/order/element/transactions.xml +copyright : not copyrighted - public domain + +--> + +<batch xmlns="http://www.codesynthesis.com/transactions" +       xmlns:te="http://www.codesynthesis.com/transactions-extras" +       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +       xsi:schemaLocation="http://www.codesynthesis.com/transactions transactions.xsd"> +  <deposit> +    <account>123456789</account> +    <amount>1000000</amount> +  </deposit> + +  <balance> +    <account>123456789</account> +  </balance> + +  <te:block> +    <account>123456789</account> +    <amount>500000</amount> +  </te:block> + +  <withdraw> +    <account>123456789</account> +    <amount>500000</amount> +  </withdraw> +</batch> diff --git a/xsd/examples/cxx/tree/order/element/transactions.xsd b/xsd/examples/cxx/tree/order/element/transactions.xsd new file mode 100644 index 0000000..053aac4 --- /dev/null +++ b/xsd/examples/cxx/tree/order/element/transactions.xsd @@ -0,0 +1,58 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/order/element/transactions.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:t="http://www.codesynthesis.com/transactions" +            targetNamespace="http://www.codesynthesis.com/transactions" +            elementFormDefault="qualified"> + +  <xsd:complexType name="transaction"> +    <xsd:sequence> +      <xsd:element name="account" type="xsd:unsignedInt"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="balance"> +    <xsd:complexContent> +      <xsd:extension base="t:transaction"/> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:complexType name="withdraw"> +    <xsd:complexContent> +      <xsd:extension base="t:transaction"> +        <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="t:transaction"> +        <xsd:sequence> +          <xsd:element name="amount" type="xsd:unsignedInt"/> +        </xsd:sequence> +      </xsd:extension> +    </xsd:complexContent> +  </xsd:complexType> + +  <xsd:complexType name="batch"> +    <xsd:choice minOccurs="0" maxOccurs="unbounded"> +      <xsd:element name="balance" type="t:balance"/> +      <xsd:element name="withdraw" type="t:withdraw"/> +      <xsd:element name="deposit" type="t:deposit"/> +      <xsd:any namespace="##other" processContents="lax"/> +    </xsd:choice> +  </xsd:complexType> + +  <xsd:element name="batch" type="t:batch"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/order/makefile b/xsd/examples/cxx/tree/order/makefile new file mode 100644 index 0000000..2424e2b --- /dev/null +++ b/xsd/examples/cxx/tree/order/makefile @@ -0,0 +1,44 @@ +# file      : examples/cxx/tree/order/makefile +# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +all_examples   := element mixed +build_examples := element mixed + +default  := $(out_base)/ +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Build. +# +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples))) + +# Install & Dist. +# +$(install) $(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base)) + +$(install): $(addprefix $(out_base)/,$(addsuffix /.install,$(all_examples))) +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) + +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples))) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples))) + +$(call include,$(bld_root)/install.make) + +ifneq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile)) +else +$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile)) +endif diff --git a/xsd/examples/cxx/tree/order/mixed/README b/xsd/examples/cxx/tree/order/mixed/README new file mode 100644 index 0000000..e66c1ad --- /dev/null +++ b/xsd/examples/cxx/tree/order/mixed/README @@ -0,0 +1,45 @@ +This example shows how to use ordered types to capture mixed content +text and to maintain order information between elements and text. + +In this example we use mixed content model to describe text with +embedded links in the form: + +  This paragraph talks about <a href="uri">time</a>. + +The example transforms such text into plain text with references in +the form: + +  This paragraph talks about time[uri]. + +It also saves the modified text back to XML in order to verify the +element and text order. + +The example consists of the following files: + +text.xsd +  XML Schema which describes "text with links" instance documents. + +text.xml +  Sample XML instance document. + +text.hxx +text.cxx +  C++ types that represent the given vocabulary as well as a set of +  parsing and serialization functions. These are generated by XSD +  from text.xsd. Note that the --ordered-type-mixed option is used +  to indicate to the XSD compiler that all types with mixed content +  should be automatically treated as ordered. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input XML file. It then +  iterates over the text and elements in the content order to convert +  the document to its plain text representation. The driver then adds +  another paragraph of text and a link to the object model while showing +  how to maintain the content order. Finally, it saves the modified +  text back to XML to verify that the content order is preserved in +  the output document. + +To run the example on the sample XML instance document simply execute: + +$ ./driver text.xml diff --git a/xsd/examples/cxx/tree/order/mixed/driver.cxx b/xsd/examples/cxx/tree/order/mixed/driver.cxx new file mode 100644 index 0000000..9606b67 --- /dev/null +++ b/xsd/examples/cxx/tree/order/mixed/driver.cxx @@ -0,0 +1,89 @@ +// file      : examples/cxx/tree/order/mixed/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <cassert> +#include <iostream> + +#include "text.hxx" + +using std::cerr; +using std::endl; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " text.xml" << endl; +    return 1; +  } + +  try +  { +    std::auto_ptr<text> t (text_ (argv[1])); + +    // Print what we've got in content order. +    // +    for (text::content_order_const_iterator i (t->content_order ().begin ()); +         i != t->content_order ().end (); +         ++i) +    { +      switch (i->id) +      { +      case text::a_id: +        { +          const anchor& a (t->a ()[i->index]); +          cerr << a << "[" << a.href () << "]"; +          break; +        } +      case text::text_content_id: +        { +          const xml_schema::string& s (t->text_content ()[i->index]); +          cerr << s; +          break; +        } +      default: +        { +          assert (false); // Unknown content id. +        } +      } +    } + +    cerr << endl; + +    // Modify the document. Note that we have to update both the content +    // itself and content order sequences. +    // +    typedef text::content_order_type order_type; + +    text::content_order_sequence& co (t->content_order ()); +    text::text_content_sequence& tc (t->text_content ()); + +    tc.push_back ("The last paragraph doesn't talk about "); +    co.push_back (order_type (text::text_content_id, tc.size () - 1)); + +    t->a ().push_back (anchor ("anything", "http://en.wikipedia.org")); +    co.push_back (order_type (text::a_id, t->a ().size () - 1)); + +    tc.push_back (" in particular.\n\n"); +    co.push_back (order_type (text::text_content_id, tc.size () - 1)); + +    // Serialize the modified document back to XML. +    // +    xml_schema::namespace_infomap map; + +    map[""].schema = "text.xsd"; + +    text_ (std::cout, +           *t, +           map, +           "UTF-8", +           xml_schema::flags::dont_pretty_print); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/order/mixed/makefile b/xsd/examples/cxx/tree/order/mixed/makefile new file mode 100644 index 0000000..311ce52 --- /dev/null +++ b/xsd/examples/cxx/tree/order/mixed/makefile @@ -0,0 +1,99 @@ +# file      : examples/cxx/tree/order/mixed/makefile +# copyright : Copyright (c) 2005-2014 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=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +# Build. +# +$(driver): $(obj) $(xerces_c.l) -lnsl + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-serialization --ordered-type-mixed +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/text.xsd,$(install_doc_dir)/xsd/$(path)/text.xsd) +	$(call install-data,$(src_base)/text.xml,$(install_doc_dir)/xsd/$(path)/text.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/text.xsd,$(dist_prefix)/$(path)/text.xsd) +	$(call install-data,$(src_base)/text.xml,$(dist_prefix)/$(path)/text.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/order/mixed/text.xml b/xsd/examples/cxx/tree/order/mixed/text.xml new file mode 100644 index 0000000..ac80159 --- /dev/null +++ b/xsd/examples/cxx/tree/order/mixed/text.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/order/mixed/text.xml +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/xsd/examples/cxx/tree/order/mixed/text.xsd b/xsd/examples/cxx/tree/order/mixed/text.xsd new file mode 100644 index 0000000..e45abcd --- /dev/null +++ b/xsd/examples/cxx/tree/order/mixed/text.xsd @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/order/mixed/text.xsd +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:anyURI" 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/xsd/examples/cxx/tree/performance/README b/xsd/examples/cxx/tree/performance/README new file mode 100644 index 0000000..cb79cc2 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/README @@ -0,0 +1,58 @@ +This example measures the performance of parsing and serialization in +the C++/Tree mapping. It also shows how to structure your code to  +achieve the maximum performance for these two operations. + +The example consists of the following files: + +test.xsd +  XML Schema which describes the test vocabulary. + +test-50k.xml +  Test XML document. + +gen.cxx +  Program to generate a test document of desired size. + +time.hxx +time.cxx +  Class definition that represents time. + +test.hxx +test.ixx +test.cxx +  C++ types that represent the given vocabulary, a set of parsing +  functions that convert XML documents to a tree-like in-memory object +  model, and a set of serialization functions that convert the object +  model back to XML. These are generated by the XSD compiler from  +  test.xsd. + +parsing.cxx +  Parsing performance test. It first reads the entire document into +  a memory buffer. It then creates a DOM parser and pre-parses and +  caches the schema if validation is enabled. Finally, it runs the +  performance measurement loop which on each iteration parses the +  XML document from the in-memory buffer into DOM and then DOM to  +  the object model. + +serialization.cxx +  Serialization performance test. It first parses the XML document +  into the object model. It then creates a memory buffer into which +  the document is serialized and a DOM serializer. Finally, it runs +  the performance measurement loop which on each iteration serializes +  the object model to DOM and DOM to XML. + +driver.cxx +  Driver for the example. It first parses the command line arguments. +  It then initializes the Xerces-C++ runtime and calls the parsing +  and serialization tests described above. + +To run the example on a test XML document simply execute: + +$ ./driver test-50k.xml + +The -v option can be used to turn on validation in the underlying XML +parser (off by default). The -i option can be used to specify the +number of parsing and serialization iterations (1000 by default). For +example: + +$ ./driver -v -i 100 test-50k.xml diff --git a/xsd/examples/cxx/tree/performance/driver.cxx b/xsd/examples/cxx/tree/performance/driver.cxx new file mode 100644 index 0000000..b626e4d --- /dev/null +++ b/xsd/examples/cxx/tree/performance/driver.cxx @@ -0,0 +1,90 @@ +// file      : examples/cxx/tree/performance/driver.cxx +// copyright : not copyrighted - public domain + +#include <string> +#include <sstream> +#include <iostream> + +#include <xercesc/util/PlatformUtils.hpp> + +using namespace std; + +// See parsing.cxx +// +bool +parsing (const char* file, unsigned long iter, bool validate); + +// See serialization.cxx +// +bool +serialization (const char* file, unsigned long iter); + +int +main (int argc, char* argv[]) +{ +  if (argc < 2) +  { +    cerr << "usage: " << argv[0] << " [-v] [-i <count>] test.xml" << endl +         << "\t -v turn on validation (default is off)" << endl +         << "\t -i number of iterations to perform (default is 1000)" << endl; +    return 1; +  } + +  bool validate (false); +  unsigned long iter (1000); +  const char* file (0); + +  // Parse command line arguments. +  // +  for (int i (1); i < argc; ++i) +  { +    std::string arg (argv[i]); + +    if (arg == "-v") +    { +      validate = true; +    } +    else if (arg == "-i") +    { +      if (++i == argc) +      { +        cerr << "argument expected for the -i option" << endl; +        return 1; +      } + +      iter = 0; +      istringstream is (argv[i]); +      is >> iter; + +      if (iter == 0) +      { +        cerr << "invalid argument for the -i option" << endl; +        return 1; +      } +    } +    else +    { +      file = argv[i]; +      break; +    } +  } + +  if (file == 0) +  { +    cerr << "no input file specified" << endl; +    return 1; +  } + +  int r (0); + +  xercesc::XMLPlatformUtils::Initialize (); + +  // Call parsing and serialization tests. +  // +  if (!parsing (file, iter, validate) || !serialization (file, iter)) +    r = 1; + +  xercesc::XMLPlatformUtils::Terminate (); + +  return r; +} diff --git a/xsd/examples/cxx/tree/performance/gen.cxx b/xsd/examples/cxx/tree/performance/gen.cxx new file mode 100644 index 0000000..b6392c0 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/gen.cxx @@ -0,0 +1,76 @@ +#include <fstream> +#include <sstream> +#include <iostream> + +using namespace std; + +static const char* enums[] = +{ +  "romance", +  "fiction", +  "horror", +  "history", +  "philosophy" +}; + +int +main (int argc, char* argv[]) +{ +  if (argc != 3) +  { +    cerr << "usage: " << argv[0] << " <count> <output-file>" << endl; +    return 1; +  } + +  unsigned long n (0); +  istringstream is (argv[1]); +  is >> n; + +  if (n == 0) +  { +    cerr << "record count argument should be a positive number" << endl; +    return 1; +  } + +  ofstream ofs (argv[2]); + +  if (!ofs.is_open ()) +  { +    cerr << "unable to open '" << argv[2] << "' in write mode" << endl; +    return 1; +  } + +  ofs << "<t:root xmlns:t='test' " << +    "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " << +    "xsi:schemaLocation='test test.xsd'>"; + +  unsigned short ch (1), en (0); + +  for (unsigned long i (0); i < n; ++i) +  { +    ofs << "<record orange=\"" << i << "\""; + +    if (i % 2 == 0) +      ofs << " apple=\"true\""; + +    ofs << ">" +        << "<int>42</int>" +        << "<double>42345.4232</double>" +        << "<name>name123_45</name>"; + +    if (i % 2 == 1) +      ofs << "<string>one two three</string>"; + +    ofs << "<choice" << ch << ">" << ch << " choice</choice" << ch << ">" +        << "<enum>" << enums[en] << "</enum>" +        << "</record>"; + +    if (++ch > 4) +      ch = 1; + +    if (++en > 4) +      en = 0; +  } + +  ofs << "</t:root>"; +} diff --git a/xsd/examples/cxx/tree/performance/makefile b/xsd/examples/cxx/tree/performance/makefile new file mode 100644 index 0000000..e6f4258 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/makefile @@ -0,0 +1,111 @@ +# file      : examples/cxx/tree/performance/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := test.xsd +cxx := driver.cxx parsing.cxx serialization.cxx time.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-inline --generate-serialization +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/parsing.cxx,$(install_doc_dir)/xsd/$(path)/parsing.cxx) +	$(call install-data,$(src_base)/serialization.cxx,$(install_doc_dir)/xsd/$(path)/serialization.cxx) +	$(call install-data,$(src_base)/test.xsd,$(install_doc_dir)/xsd/$(path)/test.xsd) +	$(call install-data,$(src_base)/test-50k.xml,$(install_doc_dir)/xsd/$(path)/test-50k.xml) +	$(call install-data,$(src_base)/time.hxx,$(install_doc_dir)/xsd/$(path)/time.hxx) +	$(call install-data,$(src_base)/time.cxx,$(install_doc_dir)/xsd/$(path)/time.cxx) +	$(call install-data,$(src_base)/gen.cxx,$(install_doc_dir)/xsd/$(path)/gen.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/parsing.cxx,$(dist_prefix)/$(path)/parsing.cxx) +	$(call install-data,$(src_base)/serialization.cxx,$(dist_prefix)/$(path)/serialization.cxx) +	$(call install-data,$(src_base)/test.xsd,$(dist_prefix)/$(path)/test.xsd) +	$(call install-data,$(src_base)/test-50k.xml,$(dist_prefix)/$(path)/test-50k.xml) +	$(call install-data,$(src_base)/time.hxx,$(dist_prefix)/$(path)/time.hxx) +	$(call install-data,$(src_base)/time.cxx,$(dist_prefix)/$(path)/time.cxx) +	$(call install-data,$(src_base)/gen.cxx,$(dist_prefix)/$(path)/gen.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/performance/parsing.cxx b/xsd/examples/cxx/tree/performance/parsing.cxx new file mode 100644 index 0000000..bf7f667 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/parsing.cxx @@ -0,0 +1,172 @@ +// file      : examples/cxx/tree/performance/parsing.cxx +// copyright : not copyrighted - public domain + +#include <memory>  // std::auto_ptr +#include <cstddef> // std::size_t +#include <fstream> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/dom/DOMLSParser.hpp> +#include <xercesc/dom/DOMImplementation.hpp> +#include <xercesc/dom/DOMImplementationRegistry.hpp> + +#include <xercesc/validators/common/Grammar.hpp> + +#include <xercesc/framework/MemBufInputSource.hpp> +#include <xercesc/framework/Wrapper4InputSource.hpp> + +#include <xercesc/util/XMLUniDefs.hpp> + +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +#include "time.hxx" +#include "test.hxx" + +using namespace std; + +bool +parsing (const char* file, unsigned long iter, bool validate) +{ +  try +  { +    cerr << "parsing:" << endl; + +    ifstream ifs; +    ifs.exceptions (ios_base::failbit); +    ifs.open (file, ios::in | ios::ate); + +    size_t size (ifs.tellg ()); +    ifs.seekg (0, ios::beg); + +    char* buf = new char[size]; +    ifs.read (buf, size); +    ifs.close (); + +    cerr << "  document size:  " << size << " bytes" << endl +         << "  iterations:     " << iter << endl; + +    // Create XML parser that we are going to use in all iterations. +    // +    using namespace xercesc; + +    const XMLCh ls_id[] = +      {xercesc::chLatin_L, xercesc::chLatin_S, xercesc::chNull}; + +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls_id)); + +    // Use the error handler implementation provided by the XSD runtime. +    // +    xsd::cxx::tree::error_handler<char> eh; +    xsd::cxx::xml::dom::bits::error_handler_proxy<char> ehp (eh); + +    xml_schema::dom::auto_ptr<DOMLSParser> parser ( +      impl->createLSParser (DOMImplementationLS::MODE_SYNCHRONOUS, 0)); + +    DOMConfiguration* conf (parser->getDomConfig ()); + +    conf->setParameter (XMLUni::fgDOMComments, false); +    conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); +    conf->setParameter (XMLUni::fgDOMEntities, false); +    conf->setParameter (XMLUni::fgDOMNamespaces, true); +    conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); + +    // Set error handler. +    // +    conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +    if (validate) +    { +      conf->setParameter (XMLUni::fgDOMValidate, true); +      conf->setParameter (XMLUni::fgXercesSchema, true); +      conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); + +      // Xerces-C++ 3.1.0 is the first version with working multi import +      // support. +      // +#if _XERCES_VERSION >= 30100 +      conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +      // If we are validating, pre-load and cache the schema. +      // +      if (!parser->loadGrammar ("test.xsd", Grammar::SchemaGrammarType, true)) +      { +        // In Xerces-C++ grammar loading failure results in just a warning. +        // Make it a fatal error. +        // +        eh.handle ("test.xsd", 0, 0, +                   xsd::cxx::tree::error_handler<char>::severity::fatal, +                   "unable to load schema"); +      } + +      eh.throw_if_failed<xml_schema::parsing> (); +      conf->setParameter (XMLUni::fgXercesUseCachedGrammarInParse, true); +      conf->setParameter (XMLUni::fgXercesLoadSchema, false); +    } +    else +    { +      conf->setParameter (XMLUni::fgDOMValidate, false); +      conf->setParameter (XMLUni::fgXercesSchema, false); +      conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); +    } + +    conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + +    // Create memory buffer input source. +    // +    MemBufInputSource is ( +      reinterpret_cast<XMLByte*> (buf), size, file, false); +    is.setCopyBufToStream (false); +    Wrapper4InputSource wis (&is, false); + +    // Parsing loop. +    // +    os::time start; + +    for (unsigned long i (0); i < iter; ++i) +    { +      // First parse XML to DOM reusing the parser we created above. +      // +      xml_schema::dom::auto_ptr<DOMDocument> doc (parser->parse (&wis)); +      eh.throw_if_failed<xml_schema::parsing> (); + +      // Then parse DOM to the object model. +      // +      auto_ptr<test::root> r (test::root_ (*doc)); +    } + +    os::time end; +    os::time time (end - start); + +    delete[] buf; + +    cerr << "  time:           " << time << " sec" << endl; + +    double ms (time.sec () * 1000000ULL + time.nsec () / 1000ULL); + +    // Calculate throughput in documents/sec. +    // +    double tpd ((iter / ms) * 1000000); +    cerr << "  throughput:     " << tpd << " documents/sec" << endl; + +    // Calculate throughput in MBytes/sec. +    // +    double tpb (((size * iter) / ms) * 1000000/(1024*1024)); +    cerr << "  throughput:     " << tpb << " MBytes/sec" << endl; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return false; +  } +  catch (std::ios_base::failure const&) +  { +    cerr << "io failure" << endl; +    return false; +  } + +  return true; +} diff --git a/xsd/examples/cxx/tree/performance/serialization.cxx b/xsd/examples/cxx/tree/performance/serialization.cxx new file mode 100644 index 0000000..08e5740 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/serialization.cxx @@ -0,0 +1,132 @@ +// file      : examples/cxx/tree/performance/serialization.cxx +// copyright : not copyrighted - public domain + +#include <memory>  // std::auto_ptr +#include <cstddef> // std::size_t +#include <sstream> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/dom/DOMLSOutput.hpp> +#include <xercesc/dom/DOMLSSerializer.hpp> +#include <xercesc/dom/DOMImplementation.hpp> +#include <xercesc/dom/DOMImplementationRegistry.hpp> + +#include <xercesc/framework/MemBufFormatTarget.hpp> + +#include <xercesc/util/XMLUniDefs.hpp> + +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +#include "time.hxx" +#include "test.hxx" + +using namespace std; + +bool +serialization (const char* file, unsigned long iter) +{ +  try +  { +    using namespace xercesc; + +    cerr << "serialization:" << endl; + +    // Get the object model using the standard parsing function. +    // +    auto_ptr<test::root> r ( +      test::root_ (file, +                   xml_schema::flags::dont_initialize | +                   xml_schema::flags::dont_validate)); + +    // Serialize it to the in-memory buffer. This makes sure the buffer +    // pre-allocates enough memory. +    // +    xml_schema::namespace_infomap map; +    map["t"].name = "test"; +    map["t"].schema = "test.xsd"; + +    MemBufFormatTarget ft (10240); +    test::root_ (ft, *r, map, "UTF-8", +                 xml_schema::flags::dont_initialize | +                 xml_schema::flags::dont_pretty_print | +                 xml_schema::flags::no_xml_declaration); + +    size_t size (ft.getLen ()); +    cerr << "  document size:  " << size << " bytes" << endl +         << "  iterations:     " << iter << endl; + +    // Create XML serializer that we are going to use in all iterations. +    // +    const XMLCh ls_id[] = +      {xercesc::chLatin_L, xercesc::chLatin_S, xercesc::chNull}; + +    DOMImplementation* impl ( +      DOMImplementationRegistry::getDOMImplementation (ls_id)); + +    // Use the error handler implementation provided by the XSD runtime. +    // +    xsd::cxx::tree::error_handler<char> eh; +    xsd::cxx::xml::dom::bits::error_handler_proxy<char> ehp (eh); + +    xml_schema::dom::auto_ptr<DOMLSSerializer> writer ( +      impl->createLSSerializer ()); + +    DOMConfiguration* conf (writer->getDomConfig ()); + +    conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); +    conf->setParameter (XMLUni::fgDOMXMLDeclaration, false); + +    xml_schema::dom::auto_ptr<DOMLSOutput> out (impl->createLSOutput ()); + +    out->setByteStream (&ft); + +    // Serialization loop. +    // +    os::time start; + +    for (unsigned long i (0); i < iter; ++i) +    { +      // First serialize the object model to DOM. +      // +      xml_schema::dom::auto_ptr<DOMDocument> doc (test::root_ (*r, map)); + +      ft.reset (); + +      // Then serialize DOM to XML reusing the serializer we created above. +      // +      writer->write (doc.get (), out.get ()); +      eh.throw_if_failed<xml_schema::serialization> (); +    } + +    os::time end; +    os::time time (end - start); + +    cerr << "  time:           " << time << " sec" << endl; + +    double ms (time.sec () * 1000000ULL + time.nsec () / 1000ULL); + +    // Calculate throughput in documents/sec. +    // +    double tpd ((iter / ms) * 1000000); +    cerr << "  throughput:     " << tpd << " documents/sec" << endl; + +    // Calculate throughput in MBytes/sec. +    // +    double tpb (((size * iter) / ms) * 1000000/(1024*1024)); +    cerr << "  throughput:     " << tpb << " MBytes/sec" << endl; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return false; +  } +  catch (std::ios_base::failure const&) +  { +    cerr << "io failure" << endl; +    return false; +  } + +  return true; +} diff --git a/xsd/examples/cxx/tree/performance/test-50k.xml b/xsd/examples/cxx/tree/performance/test-50k.xml new file mode 100644 index 0000000..42e22f3 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/test-50k.xml @@ -0,0 +1 @@ +<t:root xmlns:t='test' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='test test.xsd'><record orange="0" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="1"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="2" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="3"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="4" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="5"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="6" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="7"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="8" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="9"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="10" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="11"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="12" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="13"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="14" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="15"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="16" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="17"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="18" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="19"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="20" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="21"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="22" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="23"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="24" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="25"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="26" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="27"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="28" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="29"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="30" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="31"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="32" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="33"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="34" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="35"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="36" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="37"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="38" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="39"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="40" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="41"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="42" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="43"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="44" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="45"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="46" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="47"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="48" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="49"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="50" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="51"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="52" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="53"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="54" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="55"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="56" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="57"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="58" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="59"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="60" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="61"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="62" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="63"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="64" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="65"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="66" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="67"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="68" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="69"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="70" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="71"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="72" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="73"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="74" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="75"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="76" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="77"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="78" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="79"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="80" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="81"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="82" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="83"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="84" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="85"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="86" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="87"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="88" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="89"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="90" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="91"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="92" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="93"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="94" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="95"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="96" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="97"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="98" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="99"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="100" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="101"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="102" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="103"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="104" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="105"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="106" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="107"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="108" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="109"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="110" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="111"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="112" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="113"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="114" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="115"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="116" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="117"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="118" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="119"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="120" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="121"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="122" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="123"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="124" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="125"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="126" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="127"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="128" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="129"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="130" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="131"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="132" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="133"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="134" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="135"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="136" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="137"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="138" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="139"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="140" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="141"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="142" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="143"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="144" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="145"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="146" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="147"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="148" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="149"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="150" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="151"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="152" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="153"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="154" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="155"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="156" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="157"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="158" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="159"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="160" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="161"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="162" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="163"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="164" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="165"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="166" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="167"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="168" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="169"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="170" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="171"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="172" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="173"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="174" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="175"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="176" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="177"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="178" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="179"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="180" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="181"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="182" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="183"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="184" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="185"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="186" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="187"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="188" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="189"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="190" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="191"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="192" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="193"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="194" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="195"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="196" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="197"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="198" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="199"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="200" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="201"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="202" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="203"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="204" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="205"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="206" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="207"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="208" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="209"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="210" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="211"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="212" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="213"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="214" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="215"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="216" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="217"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="218" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="219"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="220" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="221"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="222" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="223"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="224" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="225"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="226" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="227"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="228" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="229"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="230" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="231"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="232" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="233"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="234" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="235"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="236" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="237"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="238" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="239"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="240" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="241"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="242" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="243"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="244" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="245"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="246" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="247"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="248" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="249"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="250" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="251"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="252" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="253"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="254" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="255"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="256" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="257"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="258" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="259"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="260" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="261"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="262" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="263"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="264" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="265"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="266" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="267"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="268" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="269"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="270" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="271"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="272" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="273"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="274" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="275"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="276" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="277"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="278" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="279"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="280" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="281"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="282" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="283"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="284" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="285"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="286" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="287"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="288" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="289"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="290" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="291"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="292" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="293"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="294" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="295"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="296" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record><record orange="297"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>horror</enum></record><record orange="298" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>history</enum></record><record orange="299"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>philosophy</enum></record><record orange="300" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>romance</enum></record><record orange="301"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>fiction</enum></record><record orange="302" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>horror</enum></record><record orange="303"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>history</enum></record><record orange="304" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>philosophy</enum></record><record orange="305"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>romance</enum></record><record orange="306" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>fiction</enum></record><record orange="307"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>horror</enum></record><record orange="308" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>history</enum></record><record orange="309"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>philosophy</enum></record><record orange="310" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>romance</enum></record><record orange="311"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>fiction</enum></record><record orange="312" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>horror</enum></record><record orange="313"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice2>2 choice</choice2><enum>history</enum></record><record orange="314" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice3>3 choice</choice3><enum>philosophy</enum></record><record orange="315"><int>42</int><double>42345.4232</double><name>name123_45</name><string>one two three</string><choice4>4 choice</choice4><enum>romance</enum></record><record orange="316" apple="true"><int>42</int><double>42345.4232</double><name>name123_45</name><choice1>1 choice</choice1><enum>fiction</enum></record></t:root>
\ No newline at end of file diff --git a/xsd/examples/cxx/tree/performance/test.xsd b/xsd/examples/cxx/tree/performance/test.xsd new file mode 100644 index 0000000..d9b5778 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/test.xsd @@ -0,0 +1,49 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/performance/test.xsd +copyright : not copyrighted - public domain + +--> + +<schema targetNamespace="test" xmlns:t="test" +        xmlns="http://www.w3.org/2001/XMLSchema"> + +  <simpleType name="enum"> +    <restriction base="string"> +      <enumeration value="romance"/> +      <enumeration value="fiction"/> +      <enumeration value="horror"/> +      <enumeration value="history"/> +      <enumeration value="philosophy"/> +    </restriction> +  </simpleType> + +  <complexType name="record"> +    <sequence> +      <element name="int" type="unsignedInt"/> +      <element name="double" type="double"/> +      <element name="name" type="NCName"/> +      <element name="string" type="string" minOccurs="0" maxOccurs="1"/> +      <choice> +        <element name="choice1" type="string"/> +        <element name="choice2" type="string"/> +        <element name="choice3" type="string"/> +        <element name="choice4" type="string"/> +      </choice> +      <element name="enum" type="t:enum"/> +    </sequence> +    <attribute name="apple" type="boolean"/> +    <attribute name="orange" type="unsignedLong" use="required"/> +  </complexType> + +  <complexType name="root"> +    <sequence> +      <element name="record" type="t:record" maxOccurs="unbounded"/> +    </sequence> +  </complexType> + +  <element name="root" type="t:root"/> + +</schema> diff --git a/xsd/examples/cxx/tree/performance/time.cxx b/xsd/examples/cxx/tree/performance/time.cxx new file mode 100644 index 0000000..6bec91b --- /dev/null +++ b/xsd/examples/cxx/tree/performance/time.cxx @@ -0,0 +1,46 @@ +// file      : examples/cxx/tree/performance/time.cxx +// copyright : not copyrighted - public domain + +#include "time.hxx" + +#if defined (WIN32) || defined (__WIN32__) +#  define WIN32_LEAN_AND_MEAN +#  include <windows.h>  // GetSystemTimeAsFileTime +#else +#  include <time.h>     // gettimeofday +#  include <sys/time.h> // timeval +#endif + +#include <ostream> // std::ostream +#include <iomanip> // std::setfill, std::setw + +namespace os +{ +  time:: +  time () +  { +#if defined (WIN32) || defined (__WIN32__) +    FILETIME ft; +    GetSystemTimeAsFileTime (&ft); +    unsigned long long v ( +      ((unsigned long long) (ft.dwHighDateTime) << 32) + ft.dwLowDateTime); + +    sec_  = static_cast<unsigned long> (v / 10000000ULL); +    nsec_ = static_cast<unsigned long> ((v % 10000000ULL) * 100); +#else +    timeval tv; +    if (gettimeofday(&tv, 0) != 0) +      throw failed (); + +    sec_  = static_cast<unsigned long> (tv.tv_sec); +    nsec_ = static_cast<unsigned long> (tv.tv_usec * 1000); +#endif +  } + +  std::ostream& +  operator<< (std::ostream& o, time const& t) +  { +    return o << t.sec () << '.' +             << std::setfill ('0') << std::setw (9) << t.nsec (); +  } +} diff --git a/xsd/examples/cxx/tree/performance/time.hxx b/xsd/examples/cxx/tree/performance/time.hxx new file mode 100644 index 0000000..ea71e83 --- /dev/null +++ b/xsd/examples/cxx/tree/performance/time.hxx @@ -0,0 +1,110 @@ +// file      : examples/cxx/tree/performance/time.hxx +// copyright : not copyrighted - public domain + +#ifndef TIME_HXX +#define TIME_HXX + +#include <iosfwd> // std::ostream& + +namespace os +{ +  class time +  { +  public: +    class failed {}; + +    // Create a time object representing the current time. +    // +    time (); + +    time (unsigned long long nsec) +    { +      sec_  = static_cast<unsigned long> (nsec / 1000000000ULL); +      nsec_ = static_cast<unsigned long> (nsec % 1000000000ULL); +    } + +    time (unsigned long sec, unsigned long nsec) +    { +      sec_  = sec; +      nsec_ = nsec; +    } + +  public: +    unsigned long +    sec () const +    { +      return sec_; +    } + +    unsigned long +    nsec () const +    { +      return nsec_; +    } + +  public: +    class overflow {}; +    class underflow {}; + +    time +    operator+= (time const& b) +    { +      unsigned long long tmp = 0ULL + nsec_ + b.nsec_; + +      sec_ += static_cast<unsigned long> (b.sec_ + tmp / 1000000000ULL); +      nsec_ = static_cast<unsigned long> (tmp % 1000000000ULL); + +      return *this; +    } + +    time +    operator-= (time const& b) +    { +      if (*this < b) +        throw underflow (); + +      sec_ -= b.sec_; + +      if (nsec_ < b.nsec_) +      { +        --sec_; +        nsec_ += 1000000000ULL - b.nsec_; +      } +      else +        nsec_ -= b.nsec_; + +      return *this; +    } + +    friend time +    operator+ (time const& a, time const& b) +    { +      time r (a); +      r += b; +      return r; +    } + +    friend time +    operator- (time const& a, time const& b) +    { +      time r (a); +      r -= b; +      return r; +    } + +    friend bool +    operator < (time const& a, time const& b) +    { +      return (a.sec_ < b.sec_) || (a.sec_ == b.sec_ && a.nsec_ < b.nsec_); +    } + +  private: +    unsigned long sec_; +    unsigned long nsec_; +  }; + +  std::ostream& +  operator<< (std::ostream&, time const&); +} + +#endif // TIME_HXX diff --git a/xsd/examples/cxx/tree/polymorphism/README b/xsd/examples/cxx/tree/polymorphism/README new file mode 100644 index 0000000..6e54e49 --- /dev/null +++ b/xsd/examples/cxx/tree/polymorphism/README @@ -0,0 +1,32 @@ +This example shows how to use XML Schema polymorphism features such as +xsi:type attributes and substitution groups in the C++/Tree mapping. + +The example consists of the following files: + +supermen.xsd +  XML Schema which describes the "supermen" instance documents. + +supermen.xml +  Sample XML instance document. + +supermen.hxx +supermen.cxx +  C++ types that represent the given vocabulary, a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model, and a set of serialization functions that convert the +  object model back to XML. These are generated by XSD from supermen.xsd. +  Note also that we use the --generate-polymorphic command line option +  and that we don't need to use --polymorphic-type to explicitly mark  +  types as polymorphic because this is automatically deduced by the +  XSD compiler from the substitution groups used in the supermen.xsd +  schema. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the content of the object model to STDERR. Finally, the driver serializes +  the object model back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver instance.xml diff --git a/xsd/examples/cxx/tree/polymorphism/driver.cxx b/xsd/examples/cxx/tree/polymorphism/driver.cxx new file mode 100644 index 0000000..3f1598f --- /dev/null +++ b/xsd/examples/cxx/tree/polymorphism/driver.cxx @@ -0,0 +1,59 @@ +// file      : examples/cxx/tree/polymorphism/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <iostream> + +#include "supermen.hxx" + +using std::cerr; +using std::endl; +using std::auto_ptr; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " supermen.xml" << endl; +    return 1; +  } + +  try +  { +    auto_ptr<supermen> sm (supermen_ (argv[1])); + +    supermen copy (*sm); // Dynamic types are preserved in copies. + +    // Print what we've got. +    // +    for (supermen::person_const_iterator i (copy.person ().begin ()); +         i != copy.person ().end (); +         ++i) +    { +      cerr << i->name (); + +      if (const superman* s = dynamic_cast<const superman*> (&*i)) +      { +        if (s->can_fly ()) +          cerr << ", flying superman"; +        else +          cerr << ", superman"; +      } + +      cerr << endl; +    } + +    // Serialize back to XML. +    // +    xml_schema::namespace_infomap map; +    map[""].schema = "supermen.xsd"; + +    supermen_ (std::cout, copy, map); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    return 1; +  } +} diff --git a/xsd/examples/cxx/tree/polymorphism/makefile b/xsd/examples/cxx/tree/polymorphism/makefile new file mode 100644 index 0000000..2ee16e7 --- /dev/null +++ b/xsd/examples/cxx/tree/polymorphism/makefile @@ -0,0 +1,104 @@ +# file      : examples/cxx/tree/polymorphism/makefile +# copyright : Copyright (c) 2005-2014 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 + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-polymorphic --generate-serialization \ +--root-element-last +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/supermen.xsd,$(install_doc_dir)/xsd/$(path)/supermen.xsd) +	$(call install-data,$(src_base)/supermen.xml,$(install_doc_dir)/xsd/$(path)/supermen.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/supermen.xsd,$(dist_prefix)/$(path)/supermen.xsd) +	$(call install-data,$(src_base)/supermen.xml,$(dist_prefix)/$(path)/supermen.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/polymorphism/supermen.xml b/xsd/examples/cxx/tree/polymorphism/supermen.xml new file mode 100644 index 0000000..1b5b1df --- /dev/null +++ b/xsd/examples/cxx/tree/polymorphism/supermen.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/polymorphism/supermen.xml +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/xsd/examples/cxx/tree/polymorphism/supermen.xsd b/xsd/examples/cxx/tree/polymorphism/supermen.xsd new file mode 100644 index 0000000..0d37e3d --- /dev/null +++ b/xsd/examples/cxx/tree/polymorphism/supermen.xsd @@ -0,0 +1,48 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/polymorphism/supermen.xsd +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/xsd/examples/cxx/tree/streaming/README b/xsd/examples/cxx/tree/streaming/README new file mode 100644 index 0000000..5a467e0 --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/README @@ -0,0 +1,51 @@ +This example shows how to perform stream-oriented, partially in-memory +XML processing using the C++/Tree mapping. With the partially in-memory +parsing and serialization only a part of the object model is in memory at +any given time. With this approach we can process parts of the document +as they become available as well as handle documents that are too large +to fit into memory. + +The example consists of the following files: + +position.xsd +  XML Schema which describes a simple object position vocabulary. The +  position is represented as a potentially large series of latitude and +  longitude measurements. + +position.xml +  Sample object position document. + +position.hxx +position.cxx +  C++ types that represent the position vocabulary as well as parsing +  and serialization functions. These are generated by XSD from +  position.xsd. + +parser.hxx +parser.cxx +  Stream-oriented DOM parser implementation that is built on top of the +  Xerces-C++ SAX2 parser in the progressive parsing mode. This parser +  allows us to parse an XML document as a series of DOM fragments. + +serializer.hxx +serializer.cxx +  Stream-oriented DOM serializer implementation that allows us to +  serialize an XML Document as a series of object model fragments. + +grammar-input-stream.hxx +grammar-input-stream.cxx +  Input stream implementation with the special-purpose schema grammar +  decompression algorithm. It is used internally by the streaming parser. + +driver.cxx +  Driver for the example. It parses the input file into a series of DOM +  fragments which are then parsed into the object model fragments. The +  driver prints the information from the document as it becomes available. +  It also serializes the object model fragments into a new XML document +  (out.xml). + +To run the example simply execute: + +$ ./driver position.xml + +The serialization results are written to the out.xml file. diff --git a/xsd/examples/cxx/tree/streaming/driver.cxx b/xsd/examples/cxx/tree/streaming/driver.cxx new file mode 100644 index 0000000..eb7026a --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/driver.cxx @@ -0,0 +1,139 @@ +// file      : examples/cxx/tree/streaming/driver.cxx +// copyright : not copyrighted - public domain + +#include <iostream> +#include <fstream> + +#include <xercesc/dom/DOM.hpp> + +#include <xsd/cxx/xml/string.hxx>  // xml::string + +#include "parser.hxx" +#include "serializer.hxx" +#include "position.hxx" + +using namespace std; +using namespace xercesc; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " position.xml" << endl; +    return 1; +  } + +  int r (0); + +  // We need to initialize the Xerces-C++ runtime because we are doing +  // the XML-to-DOM parsing ourselves. +  // +  xercesc::XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace op; +    namespace xml = xsd::cxx::xml; + +    // Parse and serialize at the same time, in the streaming mode. +    // + +    ifstream ifs; +    ifs.exceptions (ifstream::badbit | ifstream::failbit); +    ifs.open (argv[1]); + +    ofstream ofs; +    ofs.exceptions (ios_base::badbit | ios_base::failbit); +    ofs.open ("out.xml"); + +    xml_schema::namespace_infomap ns_map; +    ns_map["op"].name = "http://www.codesynthesis.com/op"; +    ns_map["op"].schema = "position.xsd"; + +    parser p; +    serializer s; + +    p.start (ifs, argv[1], true); +    s.start (ofs); + +    typedef xml_schema::dom::auto_ptr<DOMDocument> document_ptr; + +    // Peek at the root element. This way we only get the "carcase" +    // of the document, that is, the root element with its name, all +    // the attributes, and namespace declarations but without any of +    // the nested elements. +    // +    document_ptr docr (p.peek ()); +    bool parsed (false); + +    // Parse first-level elements. +    // +    for (document_ptr doc1 (p.peek ()); doc1.get () != 0; doc1 = p.peek ()) +    { +      // Check whether it is an element that we should stream (position) or +      // just add to the root (header). +      // +      string n1 (xml::transcode<char> ( +                   doc1->getDocumentElement ()->getLocalName ())); + +      // If we see the first streaming element, then parse the root carcase. +      // +      if (!parsed && n1 == "position") +      { +        object o (*docr->getDocumentElement ()); + +        cerr << "id:   " << o.id () << endl +             << "name: " << o.header ().name () << endl +             << "type: " << o.header ().type () << endl; + +        // Start serializing the document by writing out the root carcase. +        // Note that we leave it open so that we can serialize more elements. +        // +        s.next_open (ns_map["op"].name, "op:object", ns_map, o); +        parsed = true; +      } + +      // Handle elements that need streaming. +      // +      if (n1 == "position") +      { +        // Position has no nested elements that we need to stream so we +        // finish parsing it in one go. +        // +        doc1 = p.next (doc1); +        position pos (*doc1->getDocumentElement ()); + +        cerr << "lat: " << pos.lat () << " lon: " << pos.lon () << endl; + +        // Serialize it (append) to the root element. +        // +        s.next ("position", pos); +      } +      else +      { +        // Element that doesn't require streaming (header in our case). Add +        // to the root element and finish parsing. +        // +        docr = p.next (doc1, docr); +      } +    } + +    // Close the root element in serializer. +    // +    s.next_close ("op:object"); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const ios_base::failure&) +  { +    cerr << "io failure" << endl; +    r = 1; +  } + +  xercesc::XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/streaming/grammar-input-stream.cxx b/xsd/examples/cxx/tree/streaming/grammar-input-stream.cxx new file mode 100644 index 0000000..ffdb5b4 --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/grammar-input-stream.cxx @@ -0,0 +1,96 @@ +// file      : examples/cxx/tree/streaming/grammar-input-stream.cxx +// author    : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <cassert> +#include "grammar-input-stream.hxx" + +grammar_input_stream:: +grammar_input_stream (const XMLByte* data, std::size_t size) +      : data_ (data), +        size_ (size), +        pos_ (0), +        vpos_ (0), +        cseq_ (0), +        add_zero_ (false) +{ +} + +XMLFilePos grammar_input_stream:: +curPos () const +{ +  return static_cast<XMLFilePos> (vpos_); +} + +XMLSize_t grammar_input_stream:: +readBytes (XMLByte* const buf, const XMLSize_t size) +{ +  std::size_t i (0); + +  // Add a zero from the alternating sequence if it didn't +  // fit on the previous read. +  // +  if (add_zero_) +  { +    buf[i++] = 0; +    add_zero_ = false; +  } + +  // If have an unfinished sequential sequence, output it now. +  // +  if (cseq_ != 0 && !alt_) +  { +    for (; cseq_ != 0 && i < size; --cseq_) +      buf[i++] = 0; +  } + +  for (; i < size && pos_ < size_;) +  { +    XMLByte b = buf[i++] = data_[pos_++]; + +    // See if we are in a compression sequence. +    // +    if (cseq_ != 0) +    { +      if (i < size) +        buf[i++] = 0; +      else +        add_zero_ = true; // Add it on the next read. + +      cseq_--; +      continue; +    } + +    // If we are not in a compression sequence and this byte is +    // not zero then we are done. +    // +    if (b != 0) +      continue; + +    // We have a zero. +    // +    assert (pos_ < size_); // There has to be another byte. +    unsigned char v (static_cast<unsigned char> (data_[pos_++])); +    alt_ = (v & 128) != 0; +    cseq_ = v & 127; + +    // If it is a sequential sequence, output as many zeros as +    // we can. +    // +    if (!alt_) +    { +      for (; cseq_ != 0 && i < size; --cseq_) +        buf[i++] = 0; +    } +  } + +  vpos_ += i; + +  return static_cast<XMLSize_t> (i); +} + +const XMLCh* grammar_input_stream:: +getContentType () const +{ +  return 0; +} diff --git a/xsd/examples/cxx/tree/streaming/grammar-input-stream.hxx b/xsd/examples/cxx/tree/streaming/grammar-input-stream.hxx new file mode 100644 index 0000000..36ef74c --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/grammar-input-stream.hxx @@ -0,0 +1,41 @@ +// file      : examples/cxx/tree/streaming/grammar-input-stream.hxx +// author    : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef GRAMMAR_INPUT_STREAM_HXX +#define GRAMMAR_INPUT_STREAM_HXX + +#include <cstddef> +#include <xercesc/util/BinInputStream.hpp> + +// Memory buffer input stream with the special-purpose schema +// grammar decompression. +// +class grammar_input_stream: public xercesc::BinInputStream +{ +public : +  grammar_input_stream (const XMLByte* data, std::size_t size); + +  virtual XMLFilePos +  curPos () const; + +  virtual XMLSize_t +  readBytes (XMLByte* const buf, const XMLSize_t size); + +  virtual const XMLCh* +  getContentType () const; + +private : +  const XMLByte* data_; +  std::size_t size_; +  std::size_t pos_; +  std::size_t vpos_; + +  // Compression data. +  // +  size_t cseq_;   // Number of bytes left in a compression sequence. +  bool alt_;      // Alternating or sequential sequence. +  bool add_zero_; // Add a zero on the next read. +}; + +#endif // GRAMMAR_INPUT_STREAM_HXX diff --git a/xsd/examples/cxx/tree/streaming/makefile b/xsd/examples/cxx/tree/streaming/makefile new file mode 100644 index 0000000..f6db5c0 --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/makefile @@ -0,0 +1,115 @@ +# file      : examples/cxx/tree/streaming/makefile +# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := position.xsd +cxx := driver.cxx parser.cxx serializer.cxx grammar-input-stream.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-serialization +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/parser.cxx,$(install_doc_dir)/xsd/$(path)/parser.cxx) +	$(call install-data,$(src_base)/parser.hxx,$(install_doc_dir)/xsd/$(path)/parser.hxx) +	$(call install-data,$(src_base)/serializer.cxx,$(install_doc_dir)/xsd/$(path)/serializer.cxx) +	$(call install-data,$(src_base)/serializer.hxx,$(install_doc_dir)/xsd/$(path)/serializer.hxx) +	$(call install-data,$(src_base)/grammar-input-stream.cxx,$(install_doc_dir)/xsd/$(path)/grammar-input-stream.cxx) +	$(call install-data,$(src_base)/grammar-input-stream.hxx,$(install_doc_dir)/xsd/$(path)/grammar-input-stream.hxx) +	$(call install-data,$(src_base)/position.xsd,$(install_doc_dir)/xsd/$(path)/position.xsd) +	$(call install-data,$(src_base)/position.xml,$(install_doc_dir)/xsd/$(path)/position.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/parser.cxx,$(dist_prefix)/$(path)/parser.cxx) +	$(call install-data,$(src_base)/parser.hxx,$(dist_prefix)/$(path)/parser.hxx) +	$(call install-data,$(src_base)/serializer.cxx,$(dist_prefix)/$(path)/serializer.cxx) +	$(call install-data,$(src_base)/serializer.hxx,$(dist_prefix)/$(path)/serializer.hxx) +	$(call install-data,$(src_base)/grammar-input-stream.cxx,$(dist_prefix)/$(path)/grammar-input-stream.cxx) +	$(call install-data,$(src_base)/grammar-input-stream.hxx,$(dist_prefix)/$(path)/grammar-input-stream.hxx) +	$(call install-data,$(src_base)/position.xsd,$(dist_prefix)/$(path)/position.xsd) +	$(call install-data,$(src_base)/position.xml,$(dist_prefix)/$(path)/position.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) +	$(call message,rm $$1,rm -f $$1,$(out_base)/out.xml) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver out.xml $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/streaming/parser.cxx b/xsd/examples/cxx/tree/streaming/parser.cxx new file mode 100644 index 0000000..41ad7af --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/parser.cxx @@ -0,0 +1,372 @@ +#include <cassert> + +#include <xercesc/util/XMLUni.hpp> +#include <xercesc/util/XMLString.hpp> + +#include <xercesc/sax2/Attributes.hpp> +#include <xercesc/sax2/DefaultHandler.hpp> +#include <xercesc/sax2/SAX2XMLReader.hpp> +#include <xercesc/sax2/XMLReaderFactory.hpp> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/dom/impl/DOMTextImpl.hpp> + +#include <xercesc/validators/common/Grammar.hpp> // xercesc::Grammar +#include <xercesc/framework/XMLGrammarPoolImpl.hpp> + +#include <xsd/cxx/auto-array.hxx> + +#include <xsd/cxx/xml/sax/std-input-source.hxx> +#include <xsd/cxx/xml/sax/bits/error-handler-proxy.hxx> + +#include <xsd/cxx/tree/exceptions.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +#include "parser.hxx" +#include "grammar-input-stream.hxx" + +using namespace std; +using namespace xercesc; + +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +typedef parser::document_ptr document_ptr; + +class parser_impl: public DefaultHandler +{ +public: +  parser_impl (const XMLByte* grammar, size_t grammar_size); + +  void +  start (istream& is, const string& id, bool validate); + +  document_ptr +  peek (); + +  document_ptr +  next (document_ptr doc = document_ptr (), +        document_ptr outer_doc = document_ptr ()); + +  // SAX event handlers. +  // +private: +  virtual void +  startElement (const XMLCh* const uri, +                const XMLCh* const lname, +                const XMLCh* const qname, +                const Attributes& attributes); + +  virtual void +  endElement (const XMLCh* const uri, +              const XMLCh* const lname, +              const XMLCh* const qname); + +  virtual void +  characters (const XMLCh* const s, +              const XMLSize_t length); + +private: +  // SAX parser. +  // +  bool clean_; +  auto_ptr<XMLGrammarPool> grammar_pool_; +  auto_ptr<SAX2XMLReader> parser_; +  XMLPScanToken token_; +  tree::error_handler<char> error_handler_; +  xml::sax::bits::error_handler_proxy<char> error_proxy_; +  auto_ptr<xml::sax::std_input_source> isrc_; + +  size_t depth_; +  size_t whitespace_depth_; // Depth at which to ignore whitespaces. + +  bool peek_; +  size_t next_depth_; // Depth at which next() should work. + +  // DOM document being built. +  // +  DOMImplementation& dom_impl_; +  document_ptr doc_; +  DOMElement* cur_; +}; + +const XMLCh ls[] = {chLatin_L, chLatin_S, chNull}; + +parser_impl:: +parser_impl (const XMLByte* grammar, size_t grammar_size) +    : clean_ (true), +      error_proxy_ (error_handler_), +      dom_impl_ (*DOMImplementationRegistry::getDOMImplementation (ls)) +{ +  MemoryManager* mm (XMLPlatformUtils::fgMemoryManager); + +  if (grammar != 0) +  { +    assert (grammar_size != 0); +    grammar_pool_.reset (new XMLGrammarPoolImpl (mm)); + +    grammar_input_stream is (grammar, grammar_size); +    grammar_pool_->deserializeGrammars(&is); +    grammar_pool_->lockPool (); +  } + +  parser_.reset (XMLReaderFactory::createXMLReader (mm, grammar_pool_.get ())); + +  parser_->setFeature (XMLUni::fgSAX2CoreNameSpaces, true); +  parser_->setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes, true); +  parser_->setFeature (XMLUni::fgXercesValidationErrorAsFatal, true); +  parser_->setFeature (XMLUni::fgXercesSchemaFullChecking, false); + +  // Xerces-C++ 3.1.0 is the first version with working multi import +  // support. It also allows us to disable buffering in the parser +  // so that the data is parsed and returned as soon as it is +  // available. +  // +#if _XERCES_VERSION >= 30100 +  parser_->setFeature (XMLUni::fgXercesHandleMultipleImports, true); + +  XMLSize_t lwm = 0; +  parser_->setProperty (XMLUni::fgXercesLowWaterMark, &lwm); +#endif + +  parser_->setErrorHandler (&error_proxy_); +  parser_->setContentHandler (this); +} + +void parser_impl:: +start (istream& is, const string& id, bool val) +{ +  // Reset our state. +  // +  depth_ = 0; +  peek_ = false; +  doc_.reset (); +  error_handler_.reset (); + +  if (!clean_) +    parser_->parseReset (token_); +  else +    clean_ = false; + +  isrc_.reset (new xml::sax::std_input_source (is, id)); + +  parser_->setFeature (XMLUni::fgSAX2CoreValidation, val); +  parser_->setFeature (XMLUni::fgXercesSchema, val); + +  if (val && grammar_pool_.get () != 0) +  { +    // Use the loaded grammar during parsing. +    // +    parser_->setFeature (XMLUni::fgXercesUseCachedGrammarInParse, true); + +    // Disable loading schemas via other means (e.g., schemaLocation). +    // +    parser_->setFeature (XMLUni::fgXercesLoadSchema, false); +  } + +  parser_->parseFirst (*isrc_, token_); +  error_handler_.throw_if_failed<tree::parsing<char> > (); +} + +document_ptr parser_impl:: +peek () +{ +  bool r (true); + +  size_t d (depth_); +  whitespace_depth_ = d; + +  peek_ = true; + +  // Parse (skip whitespace content) until the depth increases or we get +  // a document. The latter test covers <element/> cases where both start +  // and end events will trigger and therefore leave the depth unchanged. +  // +  while (r && depth_ == d && doc_.get () == 0) +  { +    r = parser_->parseNext (token_); +    error_handler_.throw_if_failed<tree::parsing<char> > (); +  } + +  if (!r) +    return document_ptr (0); + +  return doc_; +} + +document_ptr parser_impl:: +next (document_ptr doc, document_ptr outer_doc) +{ +  assert (peek_ == (doc.get () != 0)); + +  // Install doc/outer_doc as the document we are parsing. +  // +  if (doc.get () != 0) +  { +    if (outer_doc.get () != 0) +    { +      // Copy doc to outer_doc. +      // +      doc_ = outer_doc; +      cur_ = static_cast<DOMElement*> ( +        doc_->importNode (doc->getDocumentElement (), true)); +      doc_->getDocumentElement ()->appendChild (cur_); +    } +    else +    { +      doc_ = doc; +      cur_ = doc_->getDocumentElement (); +    } + +    // This handles the <element/> case where we get both start and +    // end events in peek(). In this case the element is fully parsed +    // and next() has nothing to do. +    // +    if (depth_ != next_depth_) +    { +      peek_ = false; +      return doc_; +    } +  } + +  bool r (true); + +  // If we peeked, then we have already seen the start tag and our +  // return depth is one above the current depth. +  // +  size_t d (peek_ ? depth_ - 1 : depth_); +  whitespace_depth_ = d; + +  peek_ = false; + +  // Keep calling parseNext() until we either move to a greater depth or +  // get a document. This way we skip the text (presumably whitespaces) +  // that may be preceding this chunk. +  // +  while (r && depth_ == d && doc_.get () == 0) +  { +    parser_->parseNext (token_); +    error_handler_.throw_if_failed<tree::parsing<char> > (); +  } + +  if (!r) +    return document_ptr (0); + +  // If we are not at our start depth, keep calling parseNext() until we +  // get there again. +  // +  while (r && depth_ != d) +  { +    r = parser_->parseNext (token_); +    error_handler_.throw_if_failed<tree::parsing<char> > (); +  } + +  if (!r) +    return document_ptr (0); + +  return doc_; +} + +// DOM builder. +// + +void parser_impl:: +startElement (const XMLCh* const uri, +              const XMLCh* const /*lname*/, +              const XMLCh* const qname, +              const Attributes& attr) +{ +  if (doc_.get () == 0) +  { +    doc_.reset (dom_impl_.createDocument (uri, qname, 0)); +    cur_ = doc_->getDocumentElement (); +  } +  else +  { +    DOMElement* e = doc_->createElementNS (uri, qname); +    cur_->appendChild (e); +    cur_ = e; +  } + +  // Set attributes. +  // +  for (XMLSize_t i (0), end (attr.getLength()); i < end; ++i) +  { +    const XMLCh* qn (attr.getQName (i)); +    const XMLCh* ns (attr.getURI (i)); + +    // When SAX2 reports the xmlns attribute, it does not include +    // the proper attribute namespace. So we have to detect and +    // handle this case. +    // +    if (XMLString::equals (qn, XMLUni::fgXMLNSString)) +      ns = XMLUni::fgXMLNSURIName; + +    cur_->setAttributeNS (ns, qn, attr.getValue (i)); +  } + +  depth_++; + +  if (peek_) +    next_depth_ = depth_; +} + +void parser_impl:: +endElement (const XMLCh* const /*uri*/, +            const XMLCh* const /*lname*/, +            const XMLCh* const /*qname*/) +{ +  // We have an element parent only on depth 2 or greater. +  // +  if (--depth_ > 1) +    cur_ = static_cast<DOMElement*> (cur_->getParentNode ()); +} + +void parser_impl:: +characters (const XMLCh* const s, const XMLSize_t length) +{ +  const XMLCh empty[] = {chNull}; + +  // Ignore text content (presumably whitespaces) while looking for +  // the next element. +  // +  if (depth_ > whitespace_depth_) +  { +    DOMText* t = doc_->createTextNode (empty); +    static_cast<DOMTextImpl*> (t)->appendData (s, length); +    cur_->appendChild (t); +  } +} + +// +// parser +// + +parser:: +~parser () +{ +} + +parser:: +parser (const XMLByte* grammar, size_t grammar_size) +    : impl_ (new parser_impl (grammar, grammar_size)) +{ +} + +void parser:: +start (istream& is, const string& id, bool val) +{ +  return impl_->start (is, id, val); +} + +document_ptr parser:: +peek () +{ +  return impl_->peek (); +} + +document_ptr parser:: +next (document_ptr doc, document_ptr outer_doc) +{ +  return impl_->next (doc, outer_doc); +} diff --git a/xsd/examples/cxx/tree/streaming/parser.hxx b/xsd/examples/cxx/tree/streaming/parser.hxx new file mode 100644 index 0000000..cb34f92 --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/parser.hxx @@ -0,0 +1,67 @@ +#ifndef PARSER_HXX +#define PARSER_HXX + +#include <string> +#include <iosfwd> +#include <cstddef> // std::size_t +#include <memory>  // std::auto_ptr + +#include <xercesc/dom/DOMDocument.hpp> + +#include <xsd/cxx/xml/dom/auto-ptr.hxx> + +class parser_impl; + +class parser +{ +public: +  // We can specify embedded XML Schema grammar to be used by the parser +  // that was created by the xsdbin utility from the 'embedded' example. +  // +  parser (const XMLByte* grammar = 0, std::size_t grammar_size = 0); +  ~parser (); + +  // The start function prepares everything for parsing a new document. +  // +  void +  start (std::istream& is, const std::string& id, bool validate); + +  typedef xsd::cxx::xml::dom::auto_ptr<xercesc::DOMDocument> document_ptr; + +  // The peek function parses just the next element (ignoring any +  // preceding content assuming it is whitespace) without parsing +  // any of its nested content (but it includes the element's +  // attributes). It returns NULL if there are no more elements +  // at this level (there could still be on outer levels in case +  // of nested streaming). +  // +  document_ptr +  peek (); + +  // The next function parses (or finishes parsing after peek) the +  // next element including its nested content. It returns NULL if +  // there are no more elements at this level (there could still +  // be on outer levels in case of nested streaming). +  // +  // If doc is not NULL, then it should be the document returned +  // by peek(). That is, a document with only the root element. +  // In this case next() finishes parsing this element. +  // +  // If outer_doc is not NULL, then next() will first add doc to +  // outer_doc as a child of the document root. +  // +  document_ptr +  next (document_ptr doc = document_ptr (), +        document_ptr outer_doc = document_ptr ()); + +private: +  parser (const parser&); + +  parser& +  operator= (const parser&); + +private: +  std::auto_ptr<parser_impl> impl_; +}; + +#endif // PARSER_HXX diff --git a/xsd/examples/cxx/tree/streaming/position.xml b/xsd/examples/cxx/tree/streaming/position.xml new file mode 100644 index 0000000..a3428bf --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/position.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/streaming/position.xml +copyright : not copyrighted - public domain + +--> + +<op:object xmlns:op="http://www.codesynthesis.com/op" +	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	   xsi:schemaLocation="http://www.codesynthesis.com/op position.xsd" +           id="123"> + +  <header> +    <name>Lion's Head</name> +    <type>rock</type> +  </header> + +  <position lat="-33.8569" lon="18.5083"/> +  <position lat="-33.8568" lon="18.5083"/> +  <position lat="-33.8568" lon="18.5082"/> +  <position lat="-33.8570" lon="18.5083"/> +  <position lat="-33.8569" lon="18.5084"/> +  <position lat="-33.8570" lon="18.5084"/> +  <position lat="-33.8570" lon="18.5082"/> +  <position lat="-33.8569" lon="18.5082"/> + +</op:object> diff --git a/xsd/examples/cxx/tree/streaming/position.xsd b/xsd/examples/cxx/tree/streaming/position.xsd new file mode 100644 index 0000000..18dda94 --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/position.xsd @@ -0,0 +1,37 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/streaming/position.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +	    xmlns:op="http://www.codesynthesis.com/op" +            targetNamespace="http://www.codesynthesis.com/op"> + + +  <xsd:complexType name="header"> +    <xsd:sequence> +      <xsd:element name="name" type="xsd:string"/> +      <xsd:element name="type" type="xsd:string"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="position"> +    <xsd:attribute name="lat" type="xsd:float" use="required"/> +    <xsd:attribute name="lon" type="xsd:float" use="required"/> +  </xsd:complexType> + +  <xsd:complexType name="object"> +    <xsd:sequence> +      <xsd:element name="header" type="op:header"/> +      <xsd:element name="position" type="op:position" maxOccurs="unbounded"/> +    </xsd:sequence> +    <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> +  </xsd:complexType> + +  <xsd:element name="object" type="op:object"/> + +</xsd:schema> diff --git a/xsd/examples/cxx/tree/streaming/serializer.cxx b/xsd/examples/cxx/tree/streaming/serializer.cxx new file mode 100644 index 0000000..0ce8156 --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/serializer.cxx @@ -0,0 +1,607 @@ +#include <vector> +#include <cassert> +#include <cstddef> + +#include <xercesc/util/XMLUni.hpp> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/dom/impl/DOMLSSerializerImpl.hpp> + +#include <xsd/cxx/xml/string.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> +#include <xsd/cxx/xml/dom/serialization-source.hxx> + +#include <xsd/cxx/tree/exceptions.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +#include "serializer.hxx" + +using namespace std; +using namespace xercesc; + +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +static const XMLCh  gEOLSeq[] = +{ +  chLF, chNull +}; + +static const XMLCh  gUTF8[] = +{ +  chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull +}; + +static const XMLCh  gEndElement[] = +{ +  chOpenAngle, chForwardSlash, chNull +}; + +static const int DISCARD_DEFAULT_CONTENT_ID       = 0x1; +static const int ENTITIES_ID                      = 0x2; +static const int FORMAT_PRETTY_PRINT_1ST_LEVEL_ID = 0xA; + +class StreamingDOMSerializer: public DOMLSSerializerImpl +{ +public: +  StreamingDOMSerializer (MemoryManager* manager) +    : DOMLSSerializerImpl (manager) +  { +  } + +  bool +  startOpen (const DOMElement* e, DOMLSOutput* const destination) +  { +    const DOMDocument* docu (e->getOwnerDocument ()); +    assert (docu != 0); + +    // Code adapted from DOMLSSerializerImpl::write(). +    // +    target_ = destination->getByteStream(); + +    fEncodingUsed = gUTF8; + +    const XMLCh* lsEncoding=destination->getEncoding(); +    if (lsEncoding && *lsEncoding) +    { +      fEncodingUsed = lsEncoding; +    } +    else if (docu) +    { +      const XMLCh* tmpEncoding = docu->getInputEncoding(); + +      if ( tmpEncoding && *tmpEncoding) +      { +        fEncodingUsed = tmpEncoding; +      } +      else +      { +        tmpEncoding = docu->getXmlEncoding(); + +        if ( tmpEncoding && *tmpEncoding) +        { +          fEncodingUsed = tmpEncoding; +        } +      } +    } + +    fNewLineUsed = (fNewLine && *fNewLine)? fNewLine : gEOLSeq; + +    fDocumentVersion = (docu->getXmlVersion() && *(docu->getXmlVersion())) +      ? docu->getXmlVersion() +      : XMLUni::fgVersion1_0; + +    fErrorCount = 0; + +    fLineFeedInTextNodePrinted = false; +    fLastWhiteSpaceInTextNode = 0; + +    level_ = 0; +    namespace_map_.clear (); + +    fFormatter = new (fMemoryManager) XMLFormatter( fEncodingUsed +                                                    ,fDocumentVersion +                                                    ,target_ +                                                    ,XMLFormatter::NoEscapes +                                                    ,XMLFormatter::UnRep_CharRef +                                                    ,fMemoryManager); +    formatter_.reset (fFormatter); + +    // Write out the XML declaration, etc. Here we assume that the document +    // has no children (i.e., no root element). +    // +    processNode (docu, 0); +    fLineFeedInTextNodePrinted = true; + +    return writeOpen (e); +  } + +  bool +  writeOpen (const DOMElement* e) +  { +    // Code adapted from the first part of ELEMENT_NODE case in +    // DOMLSSerializerImpl::processNode(). +    // + +    if (!fLineFeedInTextNodePrinted) +    { +      if(level_ == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID)) +        printNewLine(); + +      printNewLine(); +    } +    else +    { +      fLineFeedInTextNodePrinted = false; +    } + +    printIndent(level_); + +    RefHashTableOf<XMLCh>* namespaceMap = NULL; + +    *fFormatter  << XMLFormatter::NoEscapes << chOpenAngle << +      e->getNodeName (); + +    setURCharRef(); +    DOMNamedNodeMap *attributes = e->getAttributes(); +    XMLSize_t attrCount = attributes->getLength(); + +    const XMLCh* prefix = e->getPrefix(); +    const XMLCh* uri = e->getNamespaceURI(); +    if((uri && uri[0]) || +       ((prefix==0 || prefix[0]==0) && isDefaultNamespacePrefixDeclared())) +    { +      if(prefix==0 || prefix[0]==0) +        prefix=XMLUni::fgZeroLenString; +      if(!isNamespaceBindingActive(prefix, uri)) +      { +        if(namespaceMap==NULL) +        { +          namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager); +          fNamespaceStack->addElement(namespaceMap); +        } +        namespaceMap->put((void*)prefix,(XMLCh*)uri); +        *fFormatter  << XMLFormatter::NoEscapes +                     << chSpace << XMLUni::fgXMLNSString; + +        if(!XMLString::equals(prefix,XMLUni::fgZeroLenString)) +          *fFormatter  << chColon << prefix; + +        *fFormatter  << chEqual << chDoubleQuote +                     << XMLFormatter::AttrEscapes +                     << uri +                     << XMLFormatter::NoEscapes +                     << chDoubleQuote; +      } +    } + +    bool discard = getFeature(DISCARD_DEFAULT_CONTENT_ID); +    for (XMLSize_t i = 0; i < attrCount; i++) +    { +      DOMAttr*  attribute = (DOMAttr*)attributes->item(i); + +      if (discard && !((DOMAttr*)attribute )->getSpecified()) +        continue; + +      // if this attribute is a namespace declaration, add it to the namespace map for the current level +      const XMLCh* ns = attribute->getNamespaceURI(); +      if (ns != 0 ) +      { +        if(XMLString::equals(ns, XMLUni::fgXMLNSURIName)) +        { +          if(namespaceMap==NULL) +          { +            namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager); +            fNamespaceStack->addElement(namespaceMap); +          } +          const XMLCh* nsPrefix = attribute->getLocalName(); +          if(XMLString::equals(attribute->getNodeName(),XMLUni::fgXMLNSString)) +            nsPrefix = XMLUni::fgZeroLenString; +          if(namespaceMap->containsKey((void*)nsPrefix)) +            continue; +          namespaceMap->put((void*)attribute->getLocalName(),(XMLCh*)attribute->getNodeValue()); +        } +        else if(!XMLString::equals(ns, XMLUni::fgXMLURIName)) +        { +          // check if the namespace for the current node is already defined +          const XMLCh* prefix = attribute->getPrefix(); +          if(prefix && prefix[0]) +          { +            const XMLCh* uri = attribute->getNamespaceURI(); +            if(!isNamespaceBindingActive(prefix, uri)) +            { +              if(namespaceMap==NULL) +              { +                namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager); +                fNamespaceStack->addElement(namespaceMap); +              } +              namespaceMap->put((void*)prefix,(XMLCh*)uri); +              *fFormatter  << XMLFormatter::NoEscapes +                           << chSpace << XMLUni::fgXMLNSString << chColon << prefix +                           << chEqual << chDoubleQuote +                           << XMLFormatter::AttrEscapes +                           << uri +                           << XMLFormatter::NoEscapes +                           << chDoubleQuote; +            } +          } +        } +      } + +      if (XMLString::equals(ns, XMLUni::fgXMLNSURIName) || checkFilter(attribute) == DOMNodeFilter::FILTER_ACCEPT) +      { +        *fFormatter  << XMLFormatter::NoEscapes +                     << chSpace << attribute->getNodeName() +                     << chEqual << chDoubleQuote +                     << XMLFormatter::AttrEscapes; + +        if (getFeature(ENTITIES_ID)) +        { +          DOMNode* child = attribute->getFirstChild(); +          while( child != 0) +          { +            if(child->getNodeType()==DOMNode::TEXT_NODE) +              *fFormatter  << child->getNodeValue(); +            else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE) +              *fFormatter << XMLFormatter::NoEscapes +                          << chAmpersand << child->getNodeName() << chSemiColon +                          << XMLFormatter::AttrEscapes; +            child = child->getNextSibling(); +          } +        } +        else +          *fFormatter  << attribute->getNodeValue(); + +        *fFormatter  << XMLFormatter::NoEscapes << chDoubleQuote; +      } +    } + +    *fFormatter << XMLFormatter::NoEscapes << chCloseAngle; + +    // Keep track of whether we have added a namespace map for this +    // element. Used to pop it in writeClose(). +    // +    namespace_map_.push_back (namespaceMap != 0); + +    level_++; + +    DOMNode* child = e->getFirstChild(); +    while (child != 0) +    { +      processNode (child, level_); +      child = child->getNextSibling(); +    } + +    return fErrorCount == 0; +  } + +  bool +  writeClose (const XMLCh* name) +  { +    // Code adapted from the second part of ELEMENT_NODE case in +    // DOMLSSerializerImpl::processNode(). +    // +    level_--; + +    // Assume we are not on the same line (nodeLine != fCurrentLine). +    // +    { +      if (!fLineFeedInTextNodePrinted) +      { +        printNewLine(); +      } +      else +      { +        fLineFeedInTextNodePrinted = false; +      } + +      if(level_ == 0 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID)) +        printNewLine(); + +      printIndent(level_); +    } + +    *fFormatter << XMLFormatter::NoEscapes << gEndElement << +      name << chCloseAngle; + +    if (namespace_map_.back ()) +      fNamespaceStack->removeLastElement(); + +    namespace_map_.pop_back (); + +    if (level_ == 0) +    { +      printNewLine(); +      target_->flush (); +    } + +    return fErrorCount == 0; +  } + +  bool +  write (const DOMElement* e) +  { +    processNode (e, level_); +    return fErrorCount == 0; +  } + +  using DOMLSSerializerImpl::write; // Whole document. + +private: +  XMLFormatTarget* target_; +  std::auto_ptr<XMLFormatter> formatter_; +  int level_; + +  std::vector<bool> namespace_map_; +}; + +class serializer_impl +{ +public: +  typedef serializer::namespace_infomap namespace_infomap; + +  serializer_impl (); + +  void +  start (ostream& os, const string& encoding); + +  DOMElement* +  create (const string& name, const namespace_infomap&); + +  DOMElement* +  create (const string& ns, const string& qname, const namespace_infomap&); + +  void +  serialize (xml::dom::auto_ptr<DOMElement>); + +  void +  serialize_open (xml::dom::auto_ptr<DOMElement>); + +  void +  serialize_close (const string&); + +private: +  void +  clear_document (); + +private: +  bool start_; + +  // Serializer. +  // +  xml::dom::auto_ptr<DOMLSOutput> out_; +  xml::dom::auto_ptr<StreamingDOMSerializer> serializer_; + +  auto_ptr<xml::dom::ostream_format_target> oft_; + +  tree::error_handler<char> error_handler_; +  xml::dom::bits::error_handler_proxy<char> error_proxy_; + +  // DOM document that we use to create the elements. +  // +  DOMImplementation& dom_impl_; +  xml::dom::auto_ptr<DOMDocument> doc_; +  vector<DOMElement*> element_stack_; + +  size_t element_count_; // Number of elements serialized using current doc. +  static const size_t element_count_limit_ = 500; +}; + +const XMLCh ls[] = {chLatin_L, chLatin_S, chNull}; + +serializer_impl:: +serializer_impl () +    : error_proxy_ (error_handler_), +      dom_impl_ (*DOMImplementationRegistry::getDOMImplementation (ls)) +{ +  serializer_.reset ( +    new (XMLPlatformUtils::fgMemoryManager) +    StreamingDOMSerializer (XMLPlatformUtils::fgMemoryManager)); + +  DOMConfiguration* conf (serializer_->getDomConfig ()); +  conf->setParameter (XMLUni::fgDOMErrorHandler, &error_proxy_); +  conf->setParameter (XMLUni::fgDOMXMLDeclaration, true); +  conf->setParameter (XMLUni::fgDOMWRTDiscardDefaultContent, true); +  conf->setParameter (XMLUni::fgDOMWRTFormatPrettyPrint, true); +  conf->setParameter (XMLUni::fgDOMWRTXercesPrettyPrint, false); +} + +void serializer_impl:: +start (ostream& os, const string& encoding) +{ +  element_stack_.clear (); +  doc_.reset (dom_impl_.createDocument ()); +  element_count_ = 0; + +  error_handler_.reset (); +  oft_.reset (new xml::dom::ostream_format_target (os)); + +  out_.reset (dom_impl_.createLSOutput ()); +  out_->setEncoding (xml::string (encoding).c_str ()); +  out_->setByteStream (oft_.get ()); + +  start_ = true; +} + +DOMElement* serializer_impl:: +create (const string& name, const namespace_infomap& map) +{ +  DOMElement* r (doc_->createElement (xml::string (name).c_str ())); + +  if (!map.empty ()) +    xml::dom::add_namespaces<char> (*r, map); + +  // Add the element as the child of the stack "tip" so that it +  // "sees" all the namespace declarations active from this point. +  // +  if (!element_stack_.empty ()) +    element_stack_.back ()->appendChild (r); + +  return r; +} + +DOMElement* serializer_impl:: +create (const string& ns, const string& qname, const namespace_infomap& map) +{ +  DOMElement* r ( +    doc_->createElementNS ( +      xml::string (ns).c_str (), xml::string (qname).c_str ())); + +  if (!map.empty ()) +    xml::dom::add_namespaces<char> (*r, map); + +  // Add the element as the child of the stack "tip" so that it +  // "sees" all the namespace declarations active from this point. +  // +  if (!element_stack_.empty ()) +    element_stack_.back ()->appendChild (r); + +  return r; +} + +void serializer_impl:: +serialize (xml::dom::auto_ptr<DOMElement> p) +{ +  DOMElement* e (p.get ()); + +  if (start_) +  { +    serializer_->write (e, out_.get ()); +    start_ = false; +  } +  else +    serializer_->write (e); + +  error_handler_.throw_if_failed<tree::serialization<char> > (); + +  // Remove this element from its parent before we release. +  // +  if (!element_stack_.empty ()) +    element_stack_.back ()->removeChild (e); + +  p.reset (); // Release it before we may clear the document below. + +  if (element_count_++ > element_count_limit_) +    clear_document (); +} + +void serializer_impl:: +serialize_open (xml::dom::auto_ptr<DOMElement> p) +{ +  DOMElement* e (p.get ()); + +  if (start_) +  { +    serializer_->startOpen (e, out_.get ()); +    start_ = false; +  } +  else +    serializer_->writeOpen (e); + +  error_handler_.throw_if_failed<tree::serialization<char> > (); + +  // Add this element to the element stack. serialize_close() is +  // responsible for its removal and releasing. +  // +  element_stack_.push_back (e); +  p.release (); +} + +void serializer_impl:: +serialize_close (const string& name) +{ +  serializer_->writeClose (xml::string (name).c_str ()); +  error_handler_.throw_if_failed<tree::serialization<char> > (); + +  // Release the element. +  // +  DOMElement* e (element_stack_.back ()); +  element_stack_.pop_back (); + +  if (!element_stack_.empty ()) +    element_stack_.back ()->removeChild (e); + +  e->release (); + +  if (element_count_++ > element_count_limit_) +    clear_document (); +} + +void serializer_impl:: +clear_document () +{ +  // Re-create the document in order to force deallocation of its +  // internal heap. While Xerces-C++ DOM tries to re-use memory, +  // it still accumulates no longer used memory blocks. +  // +  xml::dom::auto_ptr<DOMDocument> doc (dom_impl_.createDocument ()); + +  if (!element_stack_.empty ()) +  { +    DOMElement* e ( +      static_cast<DOMElement*> ( +        doc->importNode (element_stack_.front (), true))); + +    for (vector<DOMElement*>::iterator i (element_stack_.begin ()); +         i != element_stack_.end (); +         ++i) +    { +      *i = e; +      e = static_cast<DOMElement*> (e->getFirstChild ()); +    } +  } + +  doc_ = doc; +  element_count_ = 0; +} + +// +// serializer +// + +serializer:: +~serializer () +{ +} + +serializer:: +serializer () +    : impl_ (new serializer_impl) +{ +} + +void serializer:: +start (ostream& os, const string& encoding) +{ +  impl_->start (os, encoding); +} + +DOMElement* serializer:: +create (const string& name, const namespace_infomap& map) +{ +  return impl_->create (name, map); +} + +DOMElement* serializer:: +create (const string& ns, const string& qname, const namespace_infomap& map) +{ +  return impl_->create (ns, qname, map); +} + +void serializer:: +serialize (xml::dom::auto_ptr<DOMElement> e) +{ +  impl_->serialize (e); +} + +void serializer:: +serialize_open (xml::dom::auto_ptr<DOMElement> e) +{ +  impl_->serialize_open (e); +} + +void serializer:: +serialize_close (const string& name) +{ +  impl_->serialize_close (name); +} diff --git a/xsd/examples/cxx/tree/streaming/serializer.hxx b/xsd/examples/cxx/tree/streaming/serializer.hxx new file mode 100644 index 0000000..43fab69 --- /dev/null +++ b/xsd/examples/cxx/tree/streaming/serializer.hxx @@ -0,0 +1,205 @@ +// file      : examples/cxx/tree/streaming/serializer.hxx +// author    : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef SERIALIZER_HXX +#define SERIALIZER_HXX + +#include <string> +#include <iosfwd> +#include <memory> // std::auto_ptr + +#include <xercesc/dom/DOMElement.hpp> + +#include <xsd/cxx/xml/dom/auto-ptr.hxx> +#include <xsd/cxx/xml/dom/serialization-header.hxx> // namespace_infomap + +class serializer_impl; + +class serializer +{ +public: +  typedef xsd::cxx::xml::dom::namespace_infomap<char> namespace_infomap; + +  ~serializer (); +  serializer (); + +  // Start the serialization process. +  // +  void +  start (std::ostream& is, const std::string& encoding = "UTF-8"); + +  // Serialize next object model fragment into an element with the specified +  // name. +  // +  template <typename T> +  void +  next (const std::string& name, const T& x); + +  // Serialize next object model fragment into an element with the specified +  // name and namespace declarations. +  // +  template <typename T> +  void +  next (const std::string& name, const namespace_infomap&, const T& x); + +  // Serialize next object model fragment into an element with the specified +  // namespace and qualified name. +  // +  template <typename T> +  void +  next (const std::string& ns, const std::string& name, const T& x); + +  // Serialize next object model fragment into an element with the specified +  // namespace and qualified name as well as namespace declarations. +  // +  template <typename T> +  void +  next (const std::string& ns, +        const std::string& name, +        const namespace_infomap&, +        const T& x); + +  // The next_open/close functions are like next() but split into two steps. +  // next_open() serializes the object model fragment into an element leaving +  // it open while next_close() closes the element. +  // +  template <typename T> +  void +  next_open (const std::string& name, const T& x); + +  template <typename T> +  void +  next_open (const std::string& name, const namespace_infomap&, const T& x); + +  template <typename T> +  void +  next_open (const std::string& ns, const std::string& name, const T& x); + +  template <typename T> +  void +  next_open (const std::string& ns, +        const std::string& name, +        const namespace_infomap&, +        const T& x); + +  void +  next_close (const std::string& name); + +private: +  serializer (const serializer&); + +  serializer& +  operator= (const serializer&); + +private: +  xercesc::DOMElement* +  create (const std::string& name, const namespace_infomap&); + +  xercesc::DOMElement* +  create (const std::string& ns, +          const std::string& name, +          const namespace_infomap&); + +  void +  serialize (xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement>); + +  void +  serialize_open (xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement>); + +  void +  serialize_close (const std::string& name); + +private: +  std::auto_ptr<serializer_impl> impl_; +}; + +template <typename T> +inline void serializer:: +next (const std::string& name, const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e ( +    create (name, namespace_infomap ())); +  *e << x; +  serialize (e); +} + +template <typename T> +inline void serializer:: +next (const std::string& name, const namespace_infomap& map, const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e (create (name, map)); +  *e << x; +  serialize (e); +} + +template <typename T> +inline void serializer:: +next (const std::string& ns, const std::string& name, const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e ( +    create (ns, name, namespace_infomap ())); +  *e << x; +  serialize (e); +} + +template <typename T> +inline void serializer:: +next (const std::string& ns, +      const std::string& name, +      const namespace_infomap& map, +      const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e (create (ns, name, map)); +  *e << x; +  serialize (e); +} + +template <typename T> +inline void serializer:: +next_open (const std::string& name, const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e ( +    create (name, namespace_infomap ())); +  *e << x; +  serialize_open (e); +} + +template <typename T> +inline void serializer:: +next_open (const std::string& name, const namespace_infomap& map, const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e (create (name, map)); +  *e << x; +  serialize_open (e); +} + +template <typename T> +inline void serializer:: +next_open (const std::string& ns, const std::string& name, const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e ( +    create (ns, name, namespace_infomap ())); +  *e << x; +  serialize_open (e); +} + +template <typename T> +inline void serializer:: +next_open (const std::string& ns, +      const std::string& name, +      const namespace_infomap& map, +      const T& x) +{ +  xsd::cxx::xml::dom::auto_ptr<xercesc::DOMElement> e (create (ns, name, map)); +  *e << x; +  serialize_open (e); +} + +inline void serializer:: +next_close (const std::string& name) +{ +  serialize_close (name); +} + +#endif // SERIALIZER_HXX diff --git a/xsd/examples/cxx/tree/wildcard/README b/xsd/examples/cxx/tree/wildcard/README new file mode 100644 index 0000000..d451509 --- /dev/null +++ b/xsd/examples/cxx/tree/wildcard/README @@ -0,0 +1,34 @@ +This example shows how to use the optional wildcard mapping provided +by C++/Tree to parse, access, modify, and serialize the XML data +matched by XML Schema wildcards (any and anyAttribute). For an +alternative approach that employes type customization see the +custom/wildcard example. + +The example consists of the following files: + +email.xsd +  XML Schema which describes a simple email format with the +  extensible envelope type. + +email.xml +  Sample email message. + +email.hxx +email.ixx +email.cxx +  C++ types that represent the given vocabulary, a set of parsing +  functions that convert XML instance documents to a tree-like in-memory +  object model, and a set of serialization functions that convert the +  object model back to XML. These are generated by XSD from email.xsd. +  Note that the --generate-wildcard option is used to request the +  wildcard mapping. + +driver.cxx +  Driver for the example. It first calls one of the parsing functions +  that constructs the object model from the input file. It then prints +  the content of the object model to STDERR. Next the driver creates a +  reply email which is then serialized to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver email.xml diff --git a/xsd/examples/cxx/tree/wildcard/driver.cxx b/xsd/examples/cxx/tree/wildcard/driver.cxx new file mode 100644 index 0000000..64acfce --- /dev/null +++ b/xsd/examples/cxx/tree/wildcard/driver.cxx @@ -0,0 +1,159 @@ +// file      : examples/cxx/tree/wildcard/driver.cxx +// copyright : not copyrighted - public domain + +#include <string> +#include <memory>   // std::auto_ptr +#include <cstring>  // std::memcpy +#include <iostream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/util/PlatformUtils.hpp> + +#include "email.hxx" + +// The following string class keeps us sane when working with Xerces. +// Include it after the generated header in order to get only char or +// wchar_t version depending on how you compiled your schemas. +// +#include <xsd/cxx/xml/string.hxx> + +using std::cerr; +using std::endl; +using std::string; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " email.xml" << endl; +    return 1; +  } + +  using namespace xercesc; + +  int r (0); + +  // The Xerces-C++ DOM objects that will be used to store the +  // content matched by wildcards "out-live" the call to the +  // parsing function. Therefore we need to initialize the +  // Xerces-C++ runtime ourselves. +  // +  XMLPlatformUtils::Initialize (); + +  try +  { +    using namespace email; +    namespace xml = xsd::cxx::xml; + +    // Read in the message. +    // +    std::auto_ptr<envelope> msg ( +      message (argv[1], xml_schema::flags::dont_initialize)); + +    // Print what we've got. +    // +    cerr << "To:      " << msg->to () << endl +         << "From:    " << msg->from () << endl +         << "Subject: " << msg->subject () << endl; + +    envelope::any_sequence& body (msg->any ()); + +    for (envelope::any_iterator i (body.begin ()); i != body.end (); ++i) +    { +      DOMElement& e (*i); +      string name (xml::transcode<char> (e.getLocalName ())); + +      if (name == "text") +      { +        // Create object representation for the text element. +        // +        xml_schema::string text (e); + +        cerr << text << endl +             << endl; +      } +      else if (name == "binary") +      { +        // Create object representation for the binary element. +        // +        binary bin (e); + +        cerr << "binary: " << bin.name () << " type: " << bin.mime () << endl +             << endl; +      } +      else +      { +        cerr << "unknown body type: " << name << endl; +      } +    } + +    // Create a reply message. +    // +    envelope reply (msg->from (), msg->to (), "Re: " + msg->subject ()); + +    // Copy the thread-id attribute from the original message if any. +    // +    envelope::any_attribute_set& as (msg->any_attribute ()); +    envelope::any_attribute_iterator ti ( +      as.find ("http://www.codesynthesis.com/email", "thread-id")); + +    if (ti != as.end ()) +      reply.any_attribute ().insert (*ti); + +    // Add a text body. +    // +    DOMDocument& doc (reply.dom_document ()); +    envelope::any_sequence& rbody (reply.any ()); + +    xml_schema::string text ("Hi!\n\n" +                             "Indeed nice pictures. Check out mine.\n\n" +                             "Jane"); + +    DOMElement* e ( +      doc.createElementNS ( +        xml::string ("http://www.codesynthesis.com/email").c_str (), +        xml::string ("eml:text").c_str ())); + +    *e << text; +    rbody.push_back (e); + +    // Add a (fake) image. +    // +    binary pic ("pic.jpg", "image/jpeg"); +    pic.size (3); +    std::memcpy (pic.data (), "123", 3); + +    e = doc.createElementNS ( +      xml::string ("http://www.codesynthesis.com/email").c_str (), +      xml::string ("eml:binary").c_str ()); + +    *e << pic; +    rbody.push_back (e); + + +    // Prepare namespace mapping and schema location information for +    // serialization. +    // +    xml_schema::namespace_infomap map; + +    map["eml"].name = "http://www.codesynthesis.com/email"; +    map["eml"].schema = "email.xsd"; + +    // Write it out. +    // +    message (std::cout, +             reply, +             map, +             "UTF-8", +             xml_schema::flags::dont_initialize); +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } + +  XMLPlatformUtils::Terminate (); +  return r; +} diff --git a/xsd/examples/cxx/tree/wildcard/email.xml b/xsd/examples/cxx/tree/wildcard/email.xml new file mode 100644 index 0000000..9272d5c --- /dev/null +++ b/xsd/examples/cxx/tree/wildcard/email.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/wildcard/email.xml +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/xsd/examples/cxx/tree/wildcard/email.xsd b/xsd/examples/cxx/tree/wildcard/email.xsd new file mode 100644 index 0000000..239cb9d --- /dev/null +++ b/xsd/examples/cxx/tree/wildcard/email.xsd @@ -0,0 +1,50 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/wildcard/email.xsd +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/xsd/examples/cxx/tree/wildcard/makefile b/xsd/examples/cxx/tree/wildcard/makefile new file mode 100644 index 0000000..8c6fe52 --- /dev/null +++ b/xsd/examples/cxx/tree/wildcard/makefile @@ -0,0 +1,102 @@ +# file      : examples/cxx/tree/wildcard/makefile +# copyright : Copyright (c) 2005-2014 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=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + + +# Build. +# +$(driver): $(obj) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): xsd_options += --generate-inline --generate-wildcard \ +--generate-serialization --root-element message +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/email.xsd,$(install_doc_dir)/xsd/$(path)/email.xsd) +	$(call install-data,$(src_base)/email.xml,$(install_doc_dir)/xsd/$(path)/email.xml) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/email.xsd,$(dist_prefix)/$(path)/email.xsd) +	$(call install-data,$(src_base)/email.xml,$(dist_prefix)/$(path)/email.xml) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/xpath/README b/xsd/examples/cxx/tree/xpath/README new file mode 100644 index 0000000..1187743 --- /dev/null +++ b/xsd/examples/cxx/tree/xpath/README @@ -0,0 +1,43 @@ +This example shows how to use the C++/Tree mapping together with XPath. +In particular, it shows how to execute an XPath query on the underlying +DOM document and then handle the result using the more convenient object +model representation. For more information on maintaining association +with the underlying DOM document, refer to Section 5.1, "DOM Association" +in the C++/Tree Mapping User Manual. + +You will need the XQilla library[1] which provides XQuery and XPath 2 +support on top of Xerces-C++ in order to build and run this example. + +[1] http://xqilla.sourceforge.net + +The example consists of the following files: + +people.xsd +  XML Schema definition for a simple person record vocabulary. + +people.xml +  Sample XML instance document. + +people.hxx +people.cxx +  C++ types that represent the person record vocabulary and a set of +  parsing functions that convert XML instance documents to a tree-like +  in-memory object model. These are generated by XSD from people.xsd. + +dom-parse.hxx +dom-parse.cxx +  Definition and implementation of the parse() function that parses an +  XML document to a DOM document. + +driver.cxx +  Driver for the example. It first calls the above parse() function to +  parse the input file to a DOM document using XQilla-provided DOM +  Implementation with support for XPath 2. It then parses the DOM +  document to the object model. Finally, it prepares and executes +  an XPath query on the underlying DOM document and then handles +  the result by getting back from the returned DOM nodes to object +  model nodes. + +To run the example on the sample XML document simply execute: + +$ ./driver people.xml diff --git a/xsd/examples/cxx/tree/xpath/dom-parse.cxx b/xsd/examples/cxx/tree/xpath/dom-parse.cxx new file mode 100644 index 0000000..0282780 --- /dev/null +++ b/xsd/examples/cxx/tree/xpath/dom-parse.cxx @@ -0,0 +1,88 @@ +// file      : examples/cxx/tree/xpath/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include <istream> + +#include <xercesc/dom/DOM.hpp> +#include <xercesc/framework/Wrapper4InputSource.hpp> + +#include <xsd/cxx/xml/sax/std-input-source.hxx> +#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx> + +#include <xsd/cxx/tree/exceptions.hxx> +#include <xsd/cxx/tree/error-handler.hxx> + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::auto_ptr<DOMDocument> +parse (std::istream& is, +       const std::string& id, +       bool validate, +       DOMImplementation* impl) +{ +  xml::dom::auto_ptr<DOMLSParser> parser ( +    impl->createLSParser (DOMImplementationLS::MODE_SYNCHRONOUS, 0)); + +  DOMConfiguration* conf (parser->getDomConfig ()); + +  // Discard comment nodes in the document. +  // +  conf->setParameter (XMLUni::fgDOMComments, false); + +  // Enable datatype normalization. +  // +  conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); + +  // Do not create EntityReference nodes in the DOM tree. No +  // EntityReference nodes will be created, only the nodes +  // corresponding to their fully expanded substitution text +  // will be created. +  // +  conf->setParameter (XMLUni::fgDOMEntities, false); + +  // Perform namespace processing. +  // +  conf->setParameter (XMLUni::fgDOMNamespaces, true); + +  // Do not include ignorable whitespace in the DOM tree. +  // +  conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); + +  // Enable/Disable validation. +  // +  conf->setParameter (XMLUni::fgDOMValidate, validate); +  conf->setParameter (XMLUni::fgXercesSchema, validate); +  conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); + +  // Xerces-C++ 3.1.0 is the first version with working multi import +  // support. +  // +#if _XERCES_VERSION >= 30100 +  conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); +#endif + +  // We will release the DOM document ourselves. +  // +  conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + +  // Set error handler. +  // +  tree::error_handler<char> eh; +  xml::dom::bits::error_handler_proxy<char> ehp (eh); +  conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + +  // Prepare input stream. +  // +  xml::sax::std_input_source isrc (is, id); +  Wrapper4InputSource wrap (&isrc, false); + +  xml::dom::auto_ptr<DOMDocument> doc (parser->parse (&wrap)); + +  eh.throw_if_failed<tree::parsing<char> > (); + +  return doc; +} diff --git a/xsd/examples/cxx/tree/xpath/dom-parse.hxx b/xsd/examples/cxx/tree/xpath/dom-parse.hxx new file mode 100644 index 0000000..9fa0eb9 --- /dev/null +++ b/xsd/examples/cxx/tree/xpath/dom-parse.hxx @@ -0,0 +1,25 @@ +// file      : examples/cxx/tree/xpath/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include <string> +#include <iosfwd> + +#include <xercesc/dom/DOMDocument.hpp> +#include <xercesc/dom/DOMImplementation.hpp> + +#include <xsd/cxx/xml/dom/auto-ptr.hxx> + +// Parse an XML document from the standard input stream with an +// optional resource id. Resource id is used in diagnostics as +// well as to locate schemas referenced from inside the document. +// +xsd::cxx::xml::dom::auto_ptr<xercesc::DOMDocument> +parse (std::istream& is, +       const std::string& id, +       bool validate, +       xercesc::DOMImplementation*); + +#endif // DOM_PARSE diff --git a/xsd/examples/cxx/tree/xpath/driver.cxx b/xsd/examples/cxx/tree/xpath/driver.cxx new file mode 100644 index 0000000..f9bd040 --- /dev/null +++ b/xsd/examples/cxx/tree/xpath/driver.cxx @@ -0,0 +1,136 @@ +// file      : examples/cxx/tree/xpath/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory>   // std::auto_ptr +#include <string> +#include <fstream> +#include <iostream> + +#include <xercesc/dom/DOM.hpp> + +#include <xqilla/xqilla-dom3.hpp> + +#include <xsd/cxx/xml/string.hxx>       // xml::string, xml::transcode + +#include "dom-parse.hxx" + +#include "people.hxx" + +using namespace std; +using namespace xercesc; +namespace xml = xsd::cxx::xml; + +int +main (int argc, char* argv[]) +{ +  if (argc != 2) +  { +    cerr << "usage: " << argv[0] << " people.xml" << endl; +    return 1; +  } + +  int r (0); + +  // Initialise Xerces-C++ and XQilla. +  // +  XQillaPlatformUtils::initialize(); + +  // Get the XQilla DOMImplementation object with support for XPath. +  // +  DOMImplementation* impl ( +    DOMImplementationRegistry::getDOMImplementation( +      xml::string ("XPath2 3.0").c_str ())); + +  try +  { +    using namespace people; + +    ifstream ifs; +    ifs.exceptions (ifstream::badbit | ifstream::failbit); +    ifs.open (argv[1]); + +    // Parse the XML file to DOM using the XQilla DOMImplementation. +    // +    xml_schema::dom::auto_ptr<xercesc::DOMDocument> dom ( +      parse (ifs, argv[1], true, impl)); + +    // Parse the DOM document to the object model. We also request that +    // the DOM document to be associated with the object model. +    // +    std::auto_ptr<directory> d ( +      directory_ (dom, +                  xml_schema::flags::keep_dom | xml_schema::flags::own_dom)); + +    // Obtain the root element and document corresponding to the +    // directory object. +    // +    DOMElement* root (static_cast<DOMElement*> (d->_node ())); +    DOMDocument* doc (root->getOwnerDocument ()); + +    // Obtain namespace resolver. +    // +    xml_schema::dom::auto_ptr<DOMXPathNSResolver> resolver ( +      doc->createNSResolver (root)); + +    // Set the namespace prefix for the people namespace that we can +    // use reliably in XPath expressions regardless of what is used +    // in XML documents. +    // +    resolver->addNamespaceBinding ( +      xml::string ("p").c_str (), +      xml::string ("http://www.codesynthesis.com/people").c_str ()); + +    // Create XPath expression. +    // +    xml_schema::dom::auto_ptr<DOMXPathExpression> expr ( +      doc->createExpression ( +        xml::string ("p:directory/person[age > 30]").c_str (), +        resolver.get ())); + +    // Execute the query. +    // +    xml_schema::dom::auto_ptr<DOMXPathResult> r ( +      expr->evaluate (doc, DOMXPathResult::ITERATOR_RESULT_TYPE, 0)); + +    // Iterate over the result. +    // +    cerr << "Records matching the query:" << endl; + +    while (r->iterateNext ()) +    { +      DOMNode* n (r->getNodeValue ()); + +      // Obtain the object model node corresponding to this DOM node. +      // +      person* p ( +        static_cast<person*> ( +          n->getUserData (xml_schema::dom::tree_node_key))); + +      // Print the data using the object model. +      // +      cerr << endl +           << "First  : " << p->first_name () << endl +           << "Last   : " << p->last_name () << endl +           << "Gender : " << p->gender () << endl +           << "Age    : " << p->age () << endl; +    } +  } +  catch(const DOMException& e) +  { +    cerr << xml::transcode<char> (e.getMessage ()) << std::endl; +    r = 1; +  } +  catch (const xml_schema::exception& e) +  { +    cerr << e << endl; +    r = 1; +  } +  catch (const std::ios_base::failure&) +  { +    cerr << argv[1] << ": unable to open or read failure" << endl; +    r = 1; +  } + +  XQillaPlatformUtils::terminate(); +  return r; +} diff --git a/xsd/examples/cxx/tree/xpath/makefile b/xsd/examples/cxx/tree/xpath/makefile new file mode 100644 index 0000000..693c6b2 --- /dev/null +++ b/xsd/examples/cxx/tree/xpath/makefile @@ -0,0 +1,123 @@ +# file      : examples/cxx/tree/xpath/makefile +# copyright : Copyright (c) 2005-2014 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 dom-parse.cxx + +obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o)) +dep := $(obj:.o=.o.d) + +driver   := $(out_base)/driver +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + + +# Import. +# +$(call import,\ +  $(scf_root)/import/libxerces-c/stub.make,\ +  l: xerces_c.l,cpp-options: xerces_c.l.cpp-options) + +ifeq ($(filter $(MAKECMDGOALS),dist dist-win install),) +$(call import,\ +  $(scf_root)/import/libxqilla/stub.make,\ +  l: xqilla.l,cpp-options: xqilla.l.cpp-options) +endif + + +# Build. +# +$(driver): $(obj) $(xqilla.l) $(xerces_c.l) + +$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd +$(obj) $(dep): $(xqilla.l.cpp-options) $(xerces_c.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx) +gen  := $(addprefix $(out_base)/,$(genf)) + +$(gen): xsd := $(out_root)/xsd/xsd +$(gen): $(out_root)/xsd/xsd + +$(call include-dep,$(dep),$(obj),$(gen)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + +# Install & Dist. +# +dist-common := $(out_base)/.dist-common + +$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(install): +	$(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README) +	$(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(install_doc_dir)/xsd/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(install_doc_dir)/xsd/$(path)/people.xml) +	$(call install-data,$(src_base)/dom-parse.hxx,$(install_doc_dir)/xsd/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(install_doc_dir)/xsd/$(path)/dom-parse.cxx) + +$(dist-common): +	$(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) +	$(call install-data,$(src_base)/people.xsd,$(dist_prefix)/$(path)/people.xsd) +	$(call install-data,$(src_base)/people.xml,$(dist_prefix)/$(path)/people.xml) +	$(call install-data,$(src_base)/dom-parse.hxx,$(dist_prefix)/$(path)/dom-parse.hxx) +	$(call install-data,$(src_base)/dom-parse.cxx,$(dist_prefix)/$(path)/dom-parse.cxx) + +$(dist): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): |$(out_root)/.dist-pre +$(dist-win): $(dist-common) +	$(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) +	$(call message,,todos $(dist_prefix)/$(path)/README.txt) +	$(call meta-vc8sln,$(src_root)/dist/template-vc8.sln,xpath-vc8.sln) +	$(call meta-vc9sln,$(src_root)/dist/template-vc9.sln,xpath-vc9.sln) +	$(call meta-vc10sln,$(src_root)/dist/template-vc10.sln,xpath-vc10.sln) +	$(call meta-vc11sln,$(src_root)/dist/template-vc11.sln,xpath-vc11.sln) +	$(call meta-vc12sln,$(src_root)/dist/template-vc12.sln,xpath-vc12.sln) + + +# Clean. +# +$(clean): $(driver).o.clean                            \ +  $(addsuffix .cxx.clean,$(obj))                       \ +  $(addsuffix .cxx.clean,$(dep))                       \ +  $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsd/tree/xsd-cxx.make) + +$(call include,$(bld_root)/install.make) +$(call include,$(bld_root)/meta/vc8sln.make) +$(call include,$(bld_root)/meta/vc9sln.make) +$(call include,$(bld_root)/meta/vc10sln.make) +$(call include,$(bld_root)/meta/vc11sln.make) +$(call include,$(bld_root)/meta/vc12sln.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsd/makefile) diff --git a/xsd/examples/cxx/tree/xpath/people.xml b/xsd/examples/cxx/tree/xpath/people.xml new file mode 100644 index 0000000..9ad9ab6 --- /dev/null +++ b/xsd/examples/cxx/tree/xpath/people.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/xpath/people.xml +copyright : not copyrighted - public domain + +--> + +<ppl:directory xmlns:ppl="http://www.codesynthesis.com/people" +               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +               xsi:schemaLocation="http://www.codesynthesis.com/people 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> + +</ppl:directory> diff --git a/xsd/examples/cxx/tree/xpath/people.xsd b/xsd/examples/cxx/tree/xpath/people.xsd new file mode 100644 index 0000000..5be94de --- /dev/null +++ b/xsd/examples/cxx/tree/xpath/people.xsd @@ -0,0 +1,38 @@ +<?xml version="1.0"?> + +<!-- + +file      : examples/cxx/tree/xpath/people.xsd +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +            xmlns:ppl="http://www.codesynthesis.com/people" +            targetNamespace="http://www.codesynthesis.com/people"> + +  <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="ppl:gender"/> +      <xsd:element name="age" type="xsd:unsignedShort"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:complexType name="directory"> +    <xsd:sequence> +      <xsd:element name="person" type="ppl:person" maxOccurs="unbounded"/> +    </xsd:sequence> +  </xsd:complexType> + +  <xsd:element name="directory" type="ppl:directory"/> + +</xsd:schema> diff --git a/xsd/examples/makefile b/xsd/examples/makefile new file mode 100644 index 0000000..42c2bb7 --- /dev/null +++ b/xsd/examples/makefile @@ -0,0 +1,20 @@ +# file      : examples/makefile +# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC +# license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make + +default  := $(out_base)/ +install  := $(out_base)/.install +dist     := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean    := $(out_base)/.clean + +$(default): $(out_base)/cxx/parser/ $(out_base)/cxx/tree/ +$(install): $(out_base)/cxx/parser/.install $(out_base)/cxx/tree/.install +$(dist): $(out_base)/cxx/parser/.dist $(out_base)/cxx/tree/.dist +$(dist-win): $(out_base)/cxx/parser/.dist-win $(out_base)/cxx/tree/.dist-win +$(clean): $(out_base)/cxx/parser/.clean $(out_base)/cxx/tree/.clean + +$(call import,$(src_base)/cxx/parser/makefile) +$(call import,$(src_base)/cxx/tree/makefile)  | 
