aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2009-11-27 18:17:22 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2009-11-27 18:17:22 +0200
commitb0846152c522c859bee2fbce55721d7b79264848 (patch)
tree6e3daedf516d67d54d344af92193cb03ab18d9c4 /examples
parent9e77d565b3b817ceb427d7ffc2c71fd7ffe5d169 (diff)
Add XML compression example
Diffstat (limited to 'examples')
-rw-r--r--examples/cxx/tree/README4
-rw-r--r--examples/cxx/tree/compression/README48
-rw-r--r--examples/cxx/tree/compression/compressed-format-target.cxx157
-rw-r--r--examples/cxx/tree/compression/compressed-format-target.hxx96
-rw-r--r--examples/cxx/tree/compression/compressed-input-source.cxx215
-rw-r--r--examples/cxx/tree/compression/compressed-input-source.hxx132
-rw-r--r--examples/cxx/tree/compression/driver.cxx125
-rw-r--r--examples/cxx/tree/compression/library.xml.gzbin0 -> 486 bytes
-rw-r--r--examples/cxx/tree/compression/library.xsd73
-rw-r--r--examples/cxx/tree/compression/makefile117
-rw-r--r--examples/cxx/tree/makefile8
11 files changed, 974 insertions, 1 deletions
diff --git a/examples/cxx/tree/README b/examples/cxx/tree/README
index e2ba8de..1c89961 100644
--- a/examples/cxx/tree/README
+++ b/examples/cxx/tree/README
@@ -67,6 +67,10 @@ streaming
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 XML documents during serialization and decompress
+ them 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/examples/cxx/tree/compression/README b/examples/cxx/tree/compression/README
new file mode 100644
index 0000000..f2f0563
--- /dev/null
+++ b/examples/cxx/tree/compression/README
@@ -0,0 +1,48 @@
+This example shows how to compress XML documents during serialization
+and decompress them 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/examples/cxx/tree/compression/compressed-format-target.cxx b/examples/cxx/tree/compression/compressed-format-target.cxx
new file mode 100644
index 0000000..b4a8a85
--- /dev/null
+++ b/examples/cxx/tree/compression/compressed-format-target.cxx
@@ -0,0 +1,157 @@
+// file : examples/cxx/tree/compression/compressed-format-target.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// 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,
+#if _XERCES_VERSION >= 30000
+ const XMLSize_t size,
+#else
+ const unsigned int size,
+#endif
+ 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/examples/cxx/tree/compression/compressed-format-target.hxx b/examples/cxx/tree/compression/compressed-format-target.hxx
new file mode 100644
index 0000000..5d12e81
--- /dev/null
+++ b/examples/cxx/tree/compression/compressed-format-target.hxx
@@ -0,0 +1,96 @@
+// file : examples/cxx/tree/compression/compressed-format-target.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// 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,
+#if _XERCES_VERSION >= 30000
+ const XMLSize_t size,
+#else
+ const unsigned int size,
+#endif
+ 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/examples/cxx/tree/compression/compressed-input-source.cxx b/examples/cxx/tree/compression/compressed-input-source.cxx
new file mode 100644
index 0000000..22d09ff
--- /dev/null
+++ b/examples/cxx/tree/compression/compressed-input-source.cxx
@@ -0,0 +1,215 @@
+// file : examples/cxx/tree/compression/compressed-input-source.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// 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_);
+}
+
+#if _XERCES_VERSION >= 30000
+XMLFilePos compressed_input_stream::
+curPos () const
+{
+ return static_cast<XMLFilePos> (pos_);
+}
+#else
+unsigned int compressed_input_stream::
+curPos () const
+{
+ return static_cast<unsigned int> (pos_);
+}
+#endif
+
+#if _XERCES_VERSION >= 30000
+XMLSize_t compressed_input_stream::
+readBytes (XMLByte* const buf, const XMLSize_t size)
+#else
+unsigned int compressed_input_stream::
+readBytes (XMLByte* const buf, const unsigned int size)
+#endif
+{
+ 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;
+
+#if _XERCES_VERSION >= 30000
+ return static_cast<XMLSize_t> (n);
+#else
+ return static_cast<unsigned int> (n);
+#endif
+}
+
+#if _XERCES_VERSION >= 30000
+const XMLCh* compressed_input_stream::
+getContentType () const
+{
+ return 0;
+}
+#endif
+
+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/examples/cxx/tree/compression/compressed-input-source.hxx b/examples/cxx/tree/compression/compressed-input-source.hxx
new file mode 100644
index 0000000..680d39f
--- /dev/null
+++ b/examples/cxx/tree/compression/compressed-input-source.hxx
@@ -0,0 +1,132 @@
+// file : examples/cxx/tree/compression/compressed-input-source.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// 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 ();
+
+#if _XERCES_VERSION >= 30000
+ virtual XMLFilePos
+ curPos () const;
+
+ virtual XMLSize_t
+ readBytes (XMLByte* const buf, const XMLSize_t size);
+
+ virtual const XMLCh*
+ getContentType () const;
+
+#else
+
+ virtual unsigned int
+ readBytes (XMLByte* const buf, const unsigned int size);
+
+ virtual unsigned int
+ curPos () const;
+#endif
+
+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/examples/cxx/tree/compression/driver.cxx b/examples/cxx/tree/compression/driver.cxx
new file mode 100644
index 0000000..db285cf
--- /dev/null
+++ b/examples/cxx/tree/compression/driver.cxx
@@ -0,0 +1,125 @@
+// file : examples/cxx/tree/compression/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// 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" << 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/examples/cxx/tree/compression/library.xml.gz b/examples/cxx/tree/compression/library.xml.gz
new file mode 100644
index 0000000..dd71159
--- /dev/null
+++ b/examples/cxx/tree/compression/library.xml.gz
Binary files differ
diff --git a/examples/cxx/tree/compression/library.xsd b/examples/cxx/tree/compression/library.xsd
new file mode 100644
index 0000000..0451b36
--- /dev/null
+++ b/examples/cxx/tree/compression/library.xsd
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/tree/compression/library.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+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/examples/cxx/tree/compression/makefile b/examples/cxx/tree/compression/makefile
new file mode 100644
index 0000000..f9b65d7
--- /dev/null
+++ b/examples/cxx/tree/compression/makefile
@@ -0,0 +1,117 @@
+# file : examples/cxx/tree/compression/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+xsd := library.xsd
+cxx := driver.cxx 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$(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))
+
+# 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): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+
+# Clean.
+#
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean))
+ $(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,$(bld_root)/install.make)
+$(call include,$(scf_root)/xsd/tree/xsd-cxx.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsd/makefile)
diff --git a/examples/cxx/tree/makefile b/examples/cxx/tree/makefile
index 03c8101..8c8f137 100644
--- a/examples/cxx/tree/makefile
+++ b/examples/cxx/tree/makefile
@@ -6,11 +6,17 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
all_examples := binary caching embedded custom hello library messaging \
-mixed multiroot performance polymorphism streaming wildcard dbxml xpath
+mixed multiroot performance polymorphism streaming wildcard compression \
+dbxml xpath
+
build_examples := binary caching embedded custom hello library messaging \
mixed multiroot performance polymorphism streaming wildcard
+ifeq ($(xsd_with_zlib),y)
+build_examples += compression
+endif
+
ifeq ($(xsd_with_dbxml),y)
build_examples += dbxml
endif