diff options
Diffstat (limited to 'xsd-examples/cxx/tree/custom/mixed')
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/.gitignore | 1 | ||||
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/README | 50 | ||||
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/buildfile | 30 | ||||
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/driver.cxx | 122 | ||||
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/people-custom.cxx | 89 | ||||
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/people-custom.hxx | 83 | ||||
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/people.xml | 38 | ||||
-rw-r--r-- | xsd-examples/cxx/tree/custom/mixed/people.xsd | 45 |
8 files changed, 458 insertions, 0 deletions
diff --git a/xsd-examples/cxx/tree/custom/mixed/.gitignore b/xsd-examples/cxx/tree/custom/mixed/.gitignore new file mode 100644 index 0000000..83d0a51 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/mixed/.gitignore @@ -0,0 +1 @@ +people.?xx 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/buildfile b/xsd-examples/cxx/tree/custom/mixed/buildfile new file mode 100644 index 0000000..9da936e --- /dev/null +++ b/xsd-examples/cxx/tree/custom/mixed/buildfile @@ -0,0 +1,30 @@ +# file : cxx/tree/custom/mixed/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} + +./: exe{driver} doc{README} + +exe{driver}: {hxx cxx}{* -people} {hxx ixx cxx}{people} $libs + +exe{driver}: xml{people}: test.input = true + +<{hxx ixx cxx}{people}>: xsd{people} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --custom-type bio=/bio_base \ + --hxx-epilogue '#include "people-custom.hxx"' \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" "-I$src_base" + +# Define XSD_CXX11 since we include libxsd headers directly. +# +cxx.poptions += -DXSD_CXX11 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..08c83e0 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/mixed/driver.cxx @@ -0,0 +1,122 @@ +// file : cxx/tree/custom/mixed/driver.cxx +// copyright : not copyrighted - public domain + +#include <memory> // std::unique_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::unique_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/people-custom.cxx b/xsd-examples/cxx/tree/custom/mixed/people-custom.cxx new file mode 100644 index 0000000..bd03fcc --- /dev/null +++ b/xsd-examples/cxx/tree/custom/mixed/people-custom.cxx @@ -0,0 +1,89 @@ +// file : 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..2ab949d --- /dev/null +++ b/xsd-examples/cxx/tree/custom/mixed/people-custom.hxx @@ -0,0 +1,83 @@ +// file : 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::unique_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..4033f95 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/mixed/people.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> + +<!-- + +file : 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..739861b --- /dev/null +++ b/xsd-examples/cxx/tree/custom/mixed/people.xsd @@ -0,0 +1,45 @@ +<?xml version="1.0"?> + +<!-- + +file : 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> |