From 5e527213a2430bb3018e5eebd909aef294edf9b5 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 18 Dec 2020 18:48:46 +0300 Subject: Switch to build2 --- xsd-examples/cxx/tree/README | 84 +++ xsd-examples/cxx/tree/binary/README | 16 + xsd-examples/cxx/tree/binary/boost/.gitignore | 1 + xsd-examples/cxx/tree/binary/boost/README | 49 ++ .../tree/binary/boost/boost-archive-extraction.hxx | 188 ++++++ .../tree/binary/boost/boost-archive-insertion.hxx | 177 ++++++ xsd-examples/cxx/tree/binary/boost/buildfile | 32 ++ xsd-examples/cxx/tree/binary/boost/driver.cxx | 72 +++ .../cxx/tree/binary/boost/library-prologue.hxx | 9 + xsd-examples/cxx/tree/binary/boost/library.xml | 52 ++ xsd-examples/cxx/tree/binary/boost/library.xsd | 75 +++ xsd-examples/cxx/tree/binary/cdr/.gitignore | 1 + xsd-examples/cxx/tree/binary/cdr/README | 36 ++ xsd-examples/cxx/tree/binary/cdr/buildfile | 28 + xsd-examples/cxx/tree/binary/cdr/driver.cxx | 87 +++ xsd-examples/cxx/tree/binary/cdr/library.xml | 52 ++ xsd-examples/cxx/tree/binary/cdr/library.xsd | 75 +++ xsd-examples/cxx/tree/binary/xdr/.gitignore | 1 + xsd-examples/cxx/tree/binary/xdr/README | 36 ++ xsd-examples/cxx/tree/binary/xdr/buildfile | 30 + xsd-examples/cxx/tree/binary/xdr/driver.cxx | 148 +++++ xsd-examples/cxx/tree/binary/xdr/library.xml | 52 ++ xsd-examples/cxx/tree/binary/xdr/library.xsd | 75 +++ xsd-examples/cxx/tree/buildfile | 6 + xsd-examples/cxx/tree/caching/.gitignore | 1 + xsd-examples/cxx/tree/caching/README | 29 + xsd-examples/cxx/tree/caching/buildfile | 27 + xsd-examples/cxx/tree/caching/driver.cxx | 165 ++++++ xsd-examples/cxx/tree/caching/library.xml | 52 ++ xsd-examples/cxx/tree/caching/library.xsd | 72 +++ xsd-examples/cxx/tree/compression/.gitignore | 2 + xsd-examples/cxx/tree/compression/README | 48 ++ xsd-examples/cxx/tree/compression/buildfile | 28 + .../tree/compression/compressed-format-target.cxx | 152 +++++ .../tree/compression/compressed-format-target.hxx | 91 +++ .../tree/compression/compressed-input-source.cxx | 195 +++++++ .../tree/compression/compressed-input-source.hxx | 121 ++++ xsd-examples/cxx/tree/compression/driver.cxx | 124 ++++ xsd-examples/cxx/tree/compression/library.xml.gz | Bin 0 -> 486 bytes xsd-examples/cxx/tree/compression/library.xsd | 72 +++ xsd-examples/cxx/tree/compression/testscript | 4 + xsd-examples/cxx/tree/custom/README | 40 ++ xsd-examples/cxx/tree/custom/buildfile | 6 + xsd-examples/cxx/tree/custom/calendar/.gitignore | 2 + xsd-examples/cxx/tree/custom/calendar/README | 47 ++ xsd-examples/cxx/tree/custom/calendar/buildfile | 47 ++ xsd-examples/cxx/tree/custom/calendar/calendar.xml | 22 + xsd-examples/cxx/tree/custom/calendar/calendar.xsd | 31 + xsd-examples/cxx/tree/custom/calendar/driver.cxx | 39 ++ .../cxx/tree/custom/calendar/xml-schema-custom.cxx | 56 ++ .../cxx/tree/custom/calendar/xml-schema-custom.hxx | 33 ++ xsd-examples/cxx/tree/custom/comments/.gitignore | 2 + xsd-examples/cxx/tree/custom/comments/README | 57 ++ xsd-examples/cxx/tree/custom/comments/buildfile | 48 ++ .../cxx/tree/custom/comments/dom-parse.cxx | 93 +++ .../cxx/tree/custom/comments/dom-parse.hxx | 23 + xsd-examples/cxx/tree/custom/comments/driver.cxx | 90 +++ xsd-examples/cxx/tree/custom/comments/people.xml | 20 + xsd-examples/cxx/tree/custom/comments/people.xsd | 29 + .../cxx/tree/custom/comments/xml-schema-custom.cxx | 117 ++++ .../cxx/tree/custom/comments/xml-schema-custom.hxx | 60 ++ xsd-examples/cxx/tree/custom/contacts/.gitignore | 1 + xsd-examples/cxx/tree/custom/contacts/README | 40 ++ xsd-examples/cxx/tree/custom/contacts/buildfile | 25 + .../cxx/tree/custom/contacts/contacts-custom.cxx | 50 ++ .../cxx/tree/custom/contacts/contacts-custom.hxx | 43 ++ xsd-examples/cxx/tree/custom/contacts/contacts.xml | 20 + xsd-examples/cxx/tree/custom/contacts/contacts.xsd | 31 + xsd-examples/cxx/tree/custom/contacts/driver.cxx | 38 ++ xsd-examples/cxx/tree/custom/double/.gitignore | 2 + xsd-examples/cxx/tree/custom/double/README | 62 ++ xsd-examples/cxx/tree/custom/double/buildfile | 46 ++ .../cxx/tree/custom/double/double-custom.cxx | 96 ++++ .../cxx/tree/custom/double/double-custom.hxx | 67 +++ xsd-examples/cxx/tree/custom/double/driver.cxx | 31 + xsd-examples/cxx/tree/custom/double/order.xsd | 25 + xsd-examples/cxx/tree/custom/mixed/.gitignore | 1 + xsd-examples/cxx/tree/custom/mixed/README | 50 ++ xsd-examples/cxx/tree/custom/mixed/buildfile | 30 + xsd-examples/cxx/tree/custom/mixed/driver.cxx | 122 ++++ .../cxx/tree/custom/mixed/people-custom.cxx | 89 +++ .../cxx/tree/custom/mixed/people-custom.hxx | 83 +++ xsd-examples/cxx/tree/custom/mixed/people.xml | 38 ++ xsd-examples/cxx/tree/custom/mixed/people.xsd | 45 ++ xsd-examples/cxx/tree/custom/taxonomy/.gitignore | 2 + xsd-examples/cxx/tree/custom/taxonomy/README | 53 ++ xsd-examples/cxx/tree/custom/taxonomy/buildfile | 31 + xsd-examples/cxx/tree/custom/taxonomy/driver.cxx | 38 ++ .../cxx/tree/custom/taxonomy/people-custom-fwd.hxx | 19 + .../cxx/tree/custom/taxonomy/people-custom.cxx | 156 +++++ .../cxx/tree/custom/taxonomy/people-custom.hxx | 105 ++++ xsd-examples/cxx/tree/custom/taxonomy/people.xml | 26 + xsd-examples/cxx/tree/custom/taxonomy/people.xsd | 44 ++ xsd-examples/cxx/tree/custom/wildcard/.gitignore | 1 + xsd-examples/cxx/tree/custom/wildcard/README | 45 ++ xsd-examples/cxx/tree/custom/wildcard/buildfile | 27 + xsd-examples/cxx/tree/custom/wildcard/driver.cxx | 47 ++ .../cxx/tree/custom/wildcard/wildcard-custom.cxx | 84 +++ .../cxx/tree/custom/wildcard/wildcard-custom.hxx | 66 +++ xsd-examples/cxx/tree/custom/wildcard/wildcard.xml | 14 + xsd-examples/cxx/tree/custom/wildcard/wildcard.xsd | 25 + xsd-examples/cxx/tree/embedded/.gitignore | 3 + xsd-examples/cxx/tree/embedded/README | 48 ++ xsd-examples/cxx/tree/embedded/buildfile | 46 ++ xsd-examples/cxx/tree/embedded/driver.cxx | 183 ++++++ .../cxx/tree/embedded/grammar-input-stream.cxx | 95 +++ .../cxx/tree/embedded/grammar-input-stream.hxx | 40 ++ xsd-examples/cxx/tree/embedded/library.xml | 52 ++ xsd-examples/cxx/tree/embedded/library.xsd | 72 +++ xsd-examples/cxx/tree/embedded/xsdbin.cxx | 494 ++++++++++++++++ xsd-examples/cxx/tree/hello/.gitignore | 1 + xsd-examples/cxx/tree/hello/README | 26 + xsd-examples/cxx/tree/hello/buildfile | 23 + xsd-examples/cxx/tree/hello/driver.cxx | 36 ++ xsd-examples/cxx/tree/hello/hello.xml | 19 + xsd-examples/cxx/tree/hello/hello.xsd | 52 ++ xsd-examples/cxx/tree/library/.gitignore | 1 + xsd-examples/cxx/tree/library/README | 32 ++ xsd-examples/cxx/tree/library/buildfile | 25 + xsd-examples/cxx/tree/library/driver.cxx | 130 +++++ xsd-examples/cxx/tree/library/library.xml | 52 ++ xsd-examples/cxx/tree/library/library.xsd | 72 +++ xsd-examples/cxx/tree/messaging/.gitignore | 1 + xsd-examples/cxx/tree/messaging/README | 58 ++ xsd-examples/cxx/tree/messaging/balance.xml | 16 + xsd-examples/cxx/tree/messaging/buildfile | 29 + xsd-examples/cxx/tree/messaging/deposit.xml | 17 + xsd-examples/cxx/tree/messaging/dom-parse.cxx | 93 +++ xsd-examples/cxx/tree/messaging/dom-parse.hxx | 22 + xsd-examples/cxx/tree/messaging/dom-serialize.cxx | 64 +++ xsd-examples/cxx/tree/messaging/dom-serialize.hxx | 20 + xsd-examples/cxx/tree/messaging/driver.cxx | 146 +++++ xsd-examples/cxx/tree/messaging/protocol.xsd | 53 ++ xsd-examples/cxx/tree/messaging/testscript | 6 + xsd-examples/cxx/tree/messaging/withdraw.xml | 17 + xsd-examples/cxx/tree/mixed/.gitignore | 1 + xsd-examples/cxx/tree/mixed/README | 45 ++ xsd-examples/cxx/tree/mixed/buildfile | 27 + xsd-examples/cxx/tree/mixed/driver.cxx | 122 ++++ xsd-examples/cxx/tree/mixed/text.xml | 17 + xsd-examples/cxx/tree/mixed/text.xsd | 28 + xsd-examples/cxx/tree/multiroot/.gitignore | 1 + xsd-examples/cxx/tree/multiroot/README | 45 ++ xsd-examples/cxx/tree/multiroot/balance.xml | 16 + xsd-examples/cxx/tree/multiroot/buildfile | 26 + xsd-examples/cxx/tree/multiroot/deposit.xml | 17 + xsd-examples/cxx/tree/multiroot/dom-parse.cxx | 93 +++ xsd-examples/cxx/tree/multiroot/dom-parse.hxx | 22 + xsd-examples/cxx/tree/multiroot/driver.cxx | 124 ++++ xsd-examples/cxx/tree/multiroot/protocol.xsd | 50 ++ xsd-examples/cxx/tree/multiroot/testscript | 6 + xsd-examples/cxx/tree/multiroot/withdraw.xml | 17 + xsd-examples/cxx/tree/order/README | 11 + xsd-examples/cxx/tree/order/element/.gitignore | 1 + xsd-examples/cxx/tree/order/element/README | 35 ++ xsd-examples/cxx/tree/order/element/buildfile | 30 + xsd-examples/cxx/tree/order/element/driver.cxx | 147 +++++ .../cxx/tree/order/element/transactions.xml | 32 ++ .../cxx/tree/order/element/transactions.xsd | 58 ++ xsd-examples/cxx/tree/order/mixed/.gitignore | 1 + xsd-examples/cxx/tree/order/mixed/README | 45 ++ xsd-examples/cxx/tree/order/mixed/buildfile | 25 + xsd-examples/cxx/tree/order/mixed/driver.cxx | 89 +++ xsd-examples/cxx/tree/order/mixed/text.xml | 17 + xsd-examples/cxx/tree/order/mixed/text.xsd | 28 + xsd-examples/cxx/tree/performance/.gitignore | 5 + xsd-examples/cxx/tree/performance/README | 62 ++ xsd-examples/cxx/tree/performance/buildfile | 36 ++ xsd-examples/cxx/tree/performance/driver.cxx | 90 +++ xsd-examples/cxx/tree/performance/gen.cxx | 76 +++ xsd-examples/cxx/tree/performance/gen.testscript | 9 + xsd-examples/cxx/tree/performance/parsing.cxx | 172 ++++++ .../cxx/tree/performance/serialization.cxx | 132 +++++ xsd-examples/cxx/tree/performance/test-50k.xml | 1 + xsd-examples/cxx/tree/performance/test.xsd | 49 ++ xsd-examples/cxx/tree/performance/time.cxx | 46 ++ xsd-examples/cxx/tree/performance/time.hxx | 110 ++++ xsd-examples/cxx/tree/polymorphism/.gitignore | 1 + xsd-examples/cxx/tree/polymorphism/README | 32 ++ xsd-examples/cxx/tree/polymorphism/buildfile | 26 + xsd-examples/cxx/tree/polymorphism/driver.cxx | 59 ++ xsd-examples/cxx/tree/polymorphism/supermen.xml | 25 + xsd-examples/cxx/tree/polymorphism/supermen.xsd | 48 ++ xsd-examples/cxx/tree/secure/.gitignore | 1 + xsd-examples/cxx/tree/secure/README | 41 ++ xsd-examples/cxx/tree/secure/buildfile | 27 + xsd-examples/cxx/tree/secure/driver.cxx | 141 +++++ xsd-examples/cxx/tree/secure/library.xml | 59 ++ xsd-examples/cxx/tree/secure/library.xsd | 72 +++ xsd-examples/cxx/tree/secure/secure-dom-parser.cxx | 24 + xsd-examples/cxx/tree/secure/secure-dom-parser.hxx | 25 + xsd-examples/cxx/tree/streaming/.gitignore | 1 + xsd-examples/cxx/tree/streaming/README | 51 ++ xsd-examples/cxx/tree/streaming/buildfile | 26 + xsd-examples/cxx/tree/streaming/driver.cxx | 139 +++++ .../cxx/tree/streaming/grammar-input-stream.cxx | 96 ++++ .../cxx/tree/streaming/grammar-input-stream.hxx | 41 ++ xsd-examples/cxx/tree/streaming/parser.cxx | 371 ++++++++++++ xsd-examples/cxx/tree/streaming/parser.hxx | 67 +++ xsd-examples/cxx/tree/streaming/position.xml | 29 + xsd-examples/cxx/tree/streaming/position.xsd | 37 ++ xsd-examples/cxx/tree/streaming/serializer.cxx | 636 +++++++++++++++++++++ xsd-examples/cxx/tree/streaming/serializer.hxx | 209 +++++++ xsd-examples/cxx/tree/streaming/testscript | 10 + xsd-examples/cxx/tree/wildcard/.gitignore | 1 + xsd-examples/cxx/tree/wildcard/README | 34 ++ xsd-examples/cxx/tree/wildcard/buildfile | 30 + xsd-examples/cxx/tree/wildcard/driver.cxx | 159 ++++++ xsd-examples/cxx/tree/wildcard/email.xml | 31 + xsd-examples/cxx/tree/wildcard/email.xsd | 50 ++ xsd-examples/cxx/tree/xpath/.gitignore | 1 + xsd-examples/cxx/tree/xpath/README | 43 ++ xsd-examples/cxx/tree/xpath/buildfile | 28 + xsd-examples/cxx/tree/xpath/dom-parse.cxx | 88 +++ xsd-examples/cxx/tree/xpath/dom-parse.hxx | 25 + xsd-examples/cxx/tree/xpath/driver.cxx | 137 +++++ xsd-examples/cxx/tree/xpath/people.xml | 28 + xsd-examples/cxx/tree/xpath/people.xsd | 38 ++ 218 files changed, 12240 insertions(+) create mode 100644 xsd-examples/cxx/tree/README create mode 100644 xsd-examples/cxx/tree/binary/README create mode 100644 xsd-examples/cxx/tree/binary/boost/.gitignore create mode 100644 xsd-examples/cxx/tree/binary/boost/README create mode 100644 xsd-examples/cxx/tree/binary/boost/boost-archive-extraction.hxx create mode 100644 xsd-examples/cxx/tree/binary/boost/boost-archive-insertion.hxx create mode 100644 xsd-examples/cxx/tree/binary/boost/buildfile create mode 100644 xsd-examples/cxx/tree/binary/boost/driver.cxx create mode 100644 xsd-examples/cxx/tree/binary/boost/library-prologue.hxx create mode 100644 xsd-examples/cxx/tree/binary/boost/library.xml create mode 100644 xsd-examples/cxx/tree/binary/boost/library.xsd create mode 100644 xsd-examples/cxx/tree/binary/cdr/.gitignore create mode 100644 xsd-examples/cxx/tree/binary/cdr/README create mode 100644 xsd-examples/cxx/tree/binary/cdr/buildfile create mode 100644 xsd-examples/cxx/tree/binary/cdr/driver.cxx create mode 100644 xsd-examples/cxx/tree/binary/cdr/library.xml create mode 100644 xsd-examples/cxx/tree/binary/cdr/library.xsd create mode 100644 xsd-examples/cxx/tree/binary/xdr/.gitignore create mode 100644 xsd-examples/cxx/tree/binary/xdr/README create mode 100644 xsd-examples/cxx/tree/binary/xdr/buildfile create mode 100644 xsd-examples/cxx/tree/binary/xdr/driver.cxx create mode 100644 xsd-examples/cxx/tree/binary/xdr/library.xml create mode 100644 xsd-examples/cxx/tree/binary/xdr/library.xsd create mode 100644 xsd-examples/cxx/tree/buildfile create mode 100644 xsd-examples/cxx/tree/caching/.gitignore create mode 100644 xsd-examples/cxx/tree/caching/README create mode 100644 xsd-examples/cxx/tree/caching/buildfile create mode 100644 xsd-examples/cxx/tree/caching/driver.cxx create mode 100644 xsd-examples/cxx/tree/caching/library.xml create mode 100644 xsd-examples/cxx/tree/caching/library.xsd create mode 100644 xsd-examples/cxx/tree/compression/.gitignore create mode 100644 xsd-examples/cxx/tree/compression/README create mode 100644 xsd-examples/cxx/tree/compression/buildfile create mode 100644 xsd-examples/cxx/tree/compression/compressed-format-target.cxx create mode 100644 xsd-examples/cxx/tree/compression/compressed-format-target.hxx create mode 100644 xsd-examples/cxx/tree/compression/compressed-input-source.cxx create mode 100644 xsd-examples/cxx/tree/compression/compressed-input-source.hxx create mode 100644 xsd-examples/cxx/tree/compression/driver.cxx create mode 100644 xsd-examples/cxx/tree/compression/library.xml.gz create mode 100644 xsd-examples/cxx/tree/compression/library.xsd create mode 100644 xsd-examples/cxx/tree/compression/testscript create mode 100644 xsd-examples/cxx/tree/custom/README create mode 100644 xsd-examples/cxx/tree/custom/buildfile create mode 100644 xsd-examples/cxx/tree/custom/calendar/.gitignore create mode 100644 xsd-examples/cxx/tree/custom/calendar/README create mode 100644 xsd-examples/cxx/tree/custom/calendar/buildfile create mode 100644 xsd-examples/cxx/tree/custom/calendar/calendar.xml create mode 100644 xsd-examples/cxx/tree/custom/calendar/calendar.xsd create mode 100644 xsd-examples/cxx/tree/custom/calendar/driver.cxx create mode 100644 xsd-examples/cxx/tree/custom/calendar/xml-schema-custom.cxx create mode 100644 xsd-examples/cxx/tree/custom/calendar/xml-schema-custom.hxx create mode 100644 xsd-examples/cxx/tree/custom/comments/.gitignore create mode 100644 xsd-examples/cxx/tree/custom/comments/README create mode 100644 xsd-examples/cxx/tree/custom/comments/buildfile create mode 100644 xsd-examples/cxx/tree/custom/comments/dom-parse.cxx create mode 100644 xsd-examples/cxx/tree/custom/comments/dom-parse.hxx create mode 100644 xsd-examples/cxx/tree/custom/comments/driver.cxx create mode 100644 xsd-examples/cxx/tree/custom/comments/people.xml create mode 100644 xsd-examples/cxx/tree/custom/comments/people.xsd create mode 100644 xsd-examples/cxx/tree/custom/comments/xml-schema-custom.cxx create mode 100644 xsd-examples/cxx/tree/custom/comments/xml-schema-custom.hxx create mode 100644 xsd-examples/cxx/tree/custom/contacts/.gitignore create mode 100644 xsd-examples/cxx/tree/custom/contacts/README create mode 100644 xsd-examples/cxx/tree/custom/contacts/buildfile create mode 100644 xsd-examples/cxx/tree/custom/contacts/contacts-custom.cxx create mode 100644 xsd-examples/cxx/tree/custom/contacts/contacts-custom.hxx create mode 100644 xsd-examples/cxx/tree/custom/contacts/contacts.xml create mode 100644 xsd-examples/cxx/tree/custom/contacts/contacts.xsd create mode 100644 xsd-examples/cxx/tree/custom/contacts/driver.cxx create mode 100644 xsd-examples/cxx/tree/custom/double/.gitignore create mode 100644 xsd-examples/cxx/tree/custom/double/README create mode 100644 xsd-examples/cxx/tree/custom/double/buildfile create mode 100644 xsd-examples/cxx/tree/custom/double/double-custom.cxx create mode 100644 xsd-examples/cxx/tree/custom/double/double-custom.hxx create mode 100644 xsd-examples/cxx/tree/custom/double/driver.cxx create mode 100644 xsd-examples/cxx/tree/custom/double/order.xsd create mode 100644 xsd-examples/cxx/tree/custom/mixed/.gitignore create mode 100644 xsd-examples/cxx/tree/custom/mixed/README create mode 100644 xsd-examples/cxx/tree/custom/mixed/buildfile create mode 100644 xsd-examples/cxx/tree/custom/mixed/driver.cxx create mode 100644 xsd-examples/cxx/tree/custom/mixed/people-custom.cxx create mode 100644 xsd-examples/cxx/tree/custom/mixed/people-custom.hxx create mode 100644 xsd-examples/cxx/tree/custom/mixed/people.xml create mode 100644 xsd-examples/cxx/tree/custom/mixed/people.xsd create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/.gitignore create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/README create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/buildfile create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/driver.cxx create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/people-custom-fwd.hxx create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/people-custom.cxx create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/people-custom.hxx create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/people.xml create mode 100644 xsd-examples/cxx/tree/custom/taxonomy/people.xsd create mode 100644 xsd-examples/cxx/tree/custom/wildcard/.gitignore create mode 100644 xsd-examples/cxx/tree/custom/wildcard/README create mode 100644 xsd-examples/cxx/tree/custom/wildcard/buildfile create mode 100644 xsd-examples/cxx/tree/custom/wildcard/driver.cxx create mode 100644 xsd-examples/cxx/tree/custom/wildcard/wildcard-custom.cxx create mode 100644 xsd-examples/cxx/tree/custom/wildcard/wildcard-custom.hxx create mode 100644 xsd-examples/cxx/tree/custom/wildcard/wildcard.xml create mode 100644 xsd-examples/cxx/tree/custom/wildcard/wildcard.xsd create mode 100644 xsd-examples/cxx/tree/embedded/.gitignore create mode 100644 xsd-examples/cxx/tree/embedded/README create mode 100644 xsd-examples/cxx/tree/embedded/buildfile create mode 100644 xsd-examples/cxx/tree/embedded/driver.cxx create mode 100644 xsd-examples/cxx/tree/embedded/grammar-input-stream.cxx create mode 100644 xsd-examples/cxx/tree/embedded/grammar-input-stream.hxx create mode 100644 xsd-examples/cxx/tree/embedded/library.xml create mode 100644 xsd-examples/cxx/tree/embedded/library.xsd create mode 100644 xsd-examples/cxx/tree/embedded/xsdbin.cxx create mode 100644 xsd-examples/cxx/tree/hello/.gitignore create mode 100644 xsd-examples/cxx/tree/hello/README create mode 100644 xsd-examples/cxx/tree/hello/buildfile create mode 100644 xsd-examples/cxx/tree/hello/driver.cxx create mode 100644 xsd-examples/cxx/tree/hello/hello.xml create mode 100644 xsd-examples/cxx/tree/hello/hello.xsd create mode 100644 xsd-examples/cxx/tree/library/.gitignore create mode 100644 xsd-examples/cxx/tree/library/README create mode 100644 xsd-examples/cxx/tree/library/buildfile create mode 100644 xsd-examples/cxx/tree/library/driver.cxx create mode 100644 xsd-examples/cxx/tree/library/library.xml create mode 100644 xsd-examples/cxx/tree/library/library.xsd create mode 100644 xsd-examples/cxx/tree/messaging/.gitignore create mode 100644 xsd-examples/cxx/tree/messaging/README create mode 100644 xsd-examples/cxx/tree/messaging/balance.xml create mode 100644 xsd-examples/cxx/tree/messaging/buildfile create mode 100644 xsd-examples/cxx/tree/messaging/deposit.xml create mode 100644 xsd-examples/cxx/tree/messaging/dom-parse.cxx create mode 100644 xsd-examples/cxx/tree/messaging/dom-parse.hxx create mode 100644 xsd-examples/cxx/tree/messaging/dom-serialize.cxx create mode 100644 xsd-examples/cxx/tree/messaging/dom-serialize.hxx create mode 100644 xsd-examples/cxx/tree/messaging/driver.cxx create mode 100644 xsd-examples/cxx/tree/messaging/protocol.xsd create mode 100644 xsd-examples/cxx/tree/messaging/testscript create mode 100644 xsd-examples/cxx/tree/messaging/withdraw.xml create mode 100644 xsd-examples/cxx/tree/mixed/.gitignore create mode 100644 xsd-examples/cxx/tree/mixed/README create mode 100644 xsd-examples/cxx/tree/mixed/buildfile create mode 100644 xsd-examples/cxx/tree/mixed/driver.cxx create mode 100644 xsd-examples/cxx/tree/mixed/text.xml create mode 100644 xsd-examples/cxx/tree/mixed/text.xsd create mode 100644 xsd-examples/cxx/tree/multiroot/.gitignore create mode 100644 xsd-examples/cxx/tree/multiroot/README create mode 100644 xsd-examples/cxx/tree/multiroot/balance.xml create mode 100644 xsd-examples/cxx/tree/multiroot/buildfile create mode 100644 xsd-examples/cxx/tree/multiroot/deposit.xml create mode 100644 xsd-examples/cxx/tree/multiroot/dom-parse.cxx create mode 100644 xsd-examples/cxx/tree/multiroot/dom-parse.hxx create mode 100644 xsd-examples/cxx/tree/multiroot/driver.cxx create mode 100644 xsd-examples/cxx/tree/multiroot/protocol.xsd create mode 100644 xsd-examples/cxx/tree/multiroot/testscript create mode 100644 xsd-examples/cxx/tree/multiroot/withdraw.xml create mode 100644 xsd-examples/cxx/tree/order/README create mode 100644 xsd-examples/cxx/tree/order/element/.gitignore create mode 100644 xsd-examples/cxx/tree/order/element/README create mode 100644 xsd-examples/cxx/tree/order/element/buildfile create mode 100644 xsd-examples/cxx/tree/order/element/driver.cxx create mode 100644 xsd-examples/cxx/tree/order/element/transactions.xml create mode 100644 xsd-examples/cxx/tree/order/element/transactions.xsd create mode 100644 xsd-examples/cxx/tree/order/mixed/.gitignore create mode 100644 xsd-examples/cxx/tree/order/mixed/README create mode 100644 xsd-examples/cxx/tree/order/mixed/buildfile create mode 100644 xsd-examples/cxx/tree/order/mixed/driver.cxx create mode 100644 xsd-examples/cxx/tree/order/mixed/text.xml create mode 100644 xsd-examples/cxx/tree/order/mixed/text.xsd create mode 100644 xsd-examples/cxx/tree/performance/.gitignore create mode 100644 xsd-examples/cxx/tree/performance/README create mode 100644 xsd-examples/cxx/tree/performance/buildfile create mode 100644 xsd-examples/cxx/tree/performance/driver.cxx create mode 100644 xsd-examples/cxx/tree/performance/gen.cxx create mode 100644 xsd-examples/cxx/tree/performance/gen.testscript create mode 100644 xsd-examples/cxx/tree/performance/parsing.cxx create mode 100644 xsd-examples/cxx/tree/performance/serialization.cxx create mode 100644 xsd-examples/cxx/tree/performance/test-50k.xml create mode 100644 xsd-examples/cxx/tree/performance/test.xsd create mode 100644 xsd-examples/cxx/tree/performance/time.cxx create mode 100644 xsd-examples/cxx/tree/performance/time.hxx create mode 100644 xsd-examples/cxx/tree/polymorphism/.gitignore create mode 100644 xsd-examples/cxx/tree/polymorphism/README create mode 100644 xsd-examples/cxx/tree/polymorphism/buildfile create mode 100644 xsd-examples/cxx/tree/polymorphism/driver.cxx create mode 100644 xsd-examples/cxx/tree/polymorphism/supermen.xml create mode 100644 xsd-examples/cxx/tree/polymorphism/supermen.xsd create mode 100644 xsd-examples/cxx/tree/secure/.gitignore create mode 100644 xsd-examples/cxx/tree/secure/README create mode 100644 xsd-examples/cxx/tree/secure/buildfile create mode 100644 xsd-examples/cxx/tree/secure/driver.cxx create mode 100644 xsd-examples/cxx/tree/secure/library.xml create mode 100644 xsd-examples/cxx/tree/secure/library.xsd create mode 100644 xsd-examples/cxx/tree/secure/secure-dom-parser.cxx create mode 100644 xsd-examples/cxx/tree/secure/secure-dom-parser.hxx create mode 100644 xsd-examples/cxx/tree/streaming/.gitignore create mode 100644 xsd-examples/cxx/tree/streaming/README create mode 100644 xsd-examples/cxx/tree/streaming/buildfile create mode 100644 xsd-examples/cxx/tree/streaming/driver.cxx create mode 100644 xsd-examples/cxx/tree/streaming/grammar-input-stream.cxx create mode 100644 xsd-examples/cxx/tree/streaming/grammar-input-stream.hxx create mode 100644 xsd-examples/cxx/tree/streaming/parser.cxx create mode 100644 xsd-examples/cxx/tree/streaming/parser.hxx create mode 100644 xsd-examples/cxx/tree/streaming/position.xml create mode 100644 xsd-examples/cxx/tree/streaming/position.xsd create mode 100644 xsd-examples/cxx/tree/streaming/serializer.cxx create mode 100644 xsd-examples/cxx/tree/streaming/serializer.hxx create mode 100644 xsd-examples/cxx/tree/streaming/testscript create mode 100644 xsd-examples/cxx/tree/wildcard/.gitignore create mode 100644 xsd-examples/cxx/tree/wildcard/README create mode 100644 xsd-examples/cxx/tree/wildcard/buildfile create mode 100644 xsd-examples/cxx/tree/wildcard/driver.cxx create mode 100644 xsd-examples/cxx/tree/wildcard/email.xml create mode 100644 xsd-examples/cxx/tree/wildcard/email.xsd create mode 100644 xsd-examples/cxx/tree/xpath/.gitignore create mode 100644 xsd-examples/cxx/tree/xpath/README create mode 100644 xsd-examples/cxx/tree/xpath/buildfile create mode 100644 xsd-examples/cxx/tree/xpath/dom-parse.cxx create mode 100644 xsd-examples/cxx/tree/xpath/dom-parse.hxx create mode 100644 xsd-examples/cxx/tree/xpath/driver.cxx create mode 100644 xsd-examples/cxx/tree/xpath/people.xml create mode 100644 xsd-examples/cxx/tree/xpath/people.xsd (limited to 'xsd-examples/cxx/tree') diff --git a/xsd-examples/cxx/tree/README b/xsd-examples/cxx/tree/README new file mode 100644 index 0000000..83ffcab --- /dev/null +++ b/xsd-examples/cxx/tree/README @@ -0,0 +1,84 @@ +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. + +secure + Shows how to perform more secure XML parsing by disabling the XML + External Entity (XXE) Processing. + +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/.gitignore b/xsd-examples/cxx/tree/binary/boost/.gitignore new file mode 100644 index 0000000..c116ec1 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/boost/.gitignore @@ -0,0 +1 @@ +library.?xx 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..93241da --- /dev/null +++ b/xsd-examples/cxx/tree/binary/boost/boost-archive-extraction.hxx @@ -0,0 +1,188 @@ +// file : cxx/tree/binary/boost/boost-archive-insertion.cxx +// copyright : not copyrighted - public domain + +#ifndef BOOST_ARCHIVE_EXTRACTION_HXX +#define BOOST_ARCHIVE_EXTRACTION_HXX + +#include // std::size_t +#include + +#include +#include + +#include + +namespace xsd +{ + namespace cxx + { + namespace tree + { + // as_size + // + template + inline istream& + operator>> (istream& s, istream_common::as_size& x) + { + std::size_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + // 8-bit + // + template + inline istream& + operator>> (istream& s, istream_common::as_int8& x) + { + boost::int8_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + template + inline istream& + operator>> (istream& s, istream_common::as_uint8& x) + { + boost::uint8_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + + // 16-bit + // + template + inline istream& + operator>> (istream& s, istream_common::as_int16& x) + { + boost::int16_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + template + inline istream& + operator>> (istream& s, istream_common::as_uint16& x) + { + boost::uint16_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + + // 32-bit + // + template + inline istream& + operator>> (istream& s, istream_common::as_int32& x) + { + boost::int32_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + template + inline istream& + operator>> (istream& s, istream_common::as_uint32& x) + { + boost::uint32_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + + // 64-bit + // + template + inline istream& + operator>> (istream& s, istream_common::as_int64& x) + { + boost::int64_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + template + inline istream& + operator>> (istream& s, istream_common::as_uint64& x) + { + boost::uint64_t r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + + // Boolean + // + template + inline istream& + operator>> (istream& s, istream_common::as_bool& x) + { + bool r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + + // Floating-point + // + template + inline istream& + operator>> (istream& s, istream_common::as_float32& x) + { + float r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + template + inline istream& + operator>> (istream& s, istream_common::as_float64& x) + { + double r; + s.impl () >> r; + x.x_ = static_cast (r); + return s; + } + + // Extraction of std::basic_string. + // + + template + inline istream& + operator>> (istream& s, std::basic_string& x) + { + s.impl () >> x; + return s; + } + + + // Extraction of a binary buffer. + // + template + istream& + operator>> (istream& s, buffer& 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..b2f7936 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/boost/boost-archive-insertion.hxx @@ -0,0 +1,177 @@ +// file : cxx/tree/binary/boost/boost-archive-insertion.cxx +// copyright : not copyrighted - public domain + +#ifndef BOOST_ARCHIVE_INSERTION_HXX +#define BOOST_ARCHIVE_INSERTION_HXX + +#include // std::size_t +#include + +#include +#include + +#include + +namespace xsd +{ + namespace cxx + { + namespace tree + { + // as_size + // + template + inline ostream& + operator<< (ostream& s, ostream_common::as_size x) + { + std::size_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + // 8-bit + // + template + inline ostream& + operator<< (ostream& s, ostream_common::as_int8 x) + { + boost::int8_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + template + inline ostream& + operator<< (ostream& s, ostream_common::as_uint8 x) + { + boost::uint8_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + + // 16-bit + // + template + inline ostream& + operator<< (ostream& s, ostream_common::as_int16 x) + { + boost::int16_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + template + inline ostream& + operator<< (ostream& s, ostream_common::as_uint16 x) + { + boost::uint16_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + + // 32-bit + // + template + inline ostream& + operator<< (ostream& s, ostream_common::as_int32 x) + { + boost::int32_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + template + inline ostream& + operator<< (ostream& s, ostream_common::as_uint32 x) + { + boost::uint32_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + + // 64-bit + // + template + inline ostream& + operator<< (ostream& s, ostream_common::as_int64 x) + { + boost::int64_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + template + inline ostream& + operator<< (ostream& s, ostream_common::as_uint64 x) + { + boost::uint64_t v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + + // Boolean + // + template + inline ostream& + operator<< (ostream& s, ostream_common::as_bool x) + { + bool v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + + // Floating-point + // + template + inline ostream& + operator<< (ostream& s, ostream_common::as_float32 x) + { + float v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + template + inline ostream& + operator<< (ostream& s, ostream_common::as_float64 x) + { + double v (static_cast (x.x_)); + s.impl () << v; + return s; + } + + + // Insertion of std::basic_string. + // + template + inline ostream& + operator<< (ostream& s, const std::basic_string& x) + { + s.impl () << x; + return s; + } + + + // Insertion of a binary buffer. + // + template + ostream& + operator<< (ostream& s, const buffer& 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/buildfile b/xsd-examples/cxx/tree/binary/boost/buildfile new file mode 100644 index 0000000..4306273 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/boost/buildfile @@ -0,0 +1,32 @@ +# file : cxx/tree/binary/boost/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} +import libs += libboost-serialization%lib{boost_serialization} + +./: exe{driver} doc{README} + +exe{driver}: {hxx cxx}{* -library} {hxx ixx cxx}{library} $libs + +exe{driver}: xml{library}: test.input = true + +<{hxx ixx cxx}{library}>: xsd{library} hxx{library-prologue} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-ostream \ + --hxx-prologue-file $path($<[1]) \ + --generate-insertion 'boost::archive::text_oarchive' \ + --generate-extraction 'boost::archive::text_iarchive' \ + --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/binary/boost/driver.cxx b/xsd-examples/cxx/tree/binary/boost/driver.cxx new file mode 100644 index 0000000..d1d08d9 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/boost/driver.cxx @@ -0,0 +1,72 @@ +// file : cxx/tree/binary/boost/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include // std::memcpy +#include +#include + +// You can generate insertion/extraction code for other archive +// types (for example, binary, XML, etc). +// +#include +#include + +#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::unique_ptr c (catalog_ (argv[1])); + + cerr << *c << endl; + + // Save into a text archive. + // + std::ostringstream ostr; + text_oarchive oa (ostr); + xml_schema::ostream 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 is (ia); + + std::unique_ptr 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 +#include + +// 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..6368f44 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/boost/library.xml @@ -0,0 +1,52 @@ + + + + + + + + 0679760806 + The Master and Margarita + fiction + + + Mikhail Bulgakov + 1891-05-15 + 1940-03-10 + + + + + + 0679600841 + War and Peace + history + + + Leo Tolstoy + 1828-09-09 + 1910-11-20 + + + + + + 0679420290 + Crime and Punishment + philosophy + + + Fyodor Dostoevsky + 1821-11-11 + 1881-02-09 + + + + 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..3959788 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/boost/library.xsd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/binary/cdr/.gitignore b/xsd-examples/cxx/tree/binary/cdr/.gitignore new file mode 100644 index 0000000..c116ec1 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/cdr/.gitignore @@ -0,0 +1 @@ +library.?xx 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/buildfile b/xsd-examples/cxx/tree/binary/cdr/buildfile new file mode 100644 index 0000000..d78a56a --- /dev/null +++ b/xsd-examples/cxx/tree/binary/cdr/buildfile @@ -0,0 +1,28 @@ +# file : cxx/tree/binary/cdr/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} +import libs += libace%lib{ACE} + +./: exe{driver} doc{README} + +exe{driver}: {hxx cxx}{* -library} {hxx ixx cxx}{library} $libs + +exe{driver}: xml{library}: test.input = true + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-ostream \ + --generate-insertion 'ACE_OutputCDR' \ + --generate-extraction 'ACE_InputCDR' \ + --generate-comparison \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" 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..2ab0674 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/cdr/driver.cxx @@ -0,0 +1,87 @@ +// file : cxx/tree/binary/cdr/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include // std::memcpy +#include + +#include // ACE_HEX_DUMP +#include + +// 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::unique_ptr c (catalog_ (argv[1])); + + cerr << *c << endl; + + // Save to a CDR stream. + // + ACE_OutputCDR ace_ocdr; + xml_schema::ostream 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 icdr (ace_icdr); + + std::unique_ptr 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..5700131 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/cdr/library.xml @@ -0,0 +1,52 @@ + + + + + + + + 0679760806 + The Master and Margarita + fiction + + + Mikhail Bulgakov + 1891-05-15 + 1940-03-10 + + + + + + 0679600841 + War and Peace + history + + + Leo Tolstoy + 1828-09-09 + 1910-11-20 + + + + + + 0679420290 + Crime and Punishment + philosophy + + + Fyodor Dostoevsky + 1821-11-11 + 1881-02-09 + + + + 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..c7f056e --- /dev/null +++ b/xsd-examples/cxx/tree/binary/cdr/library.xsd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/binary/xdr/.gitignore b/xsd-examples/cxx/tree/binary/xdr/.gitignore new file mode 100644 index 0000000..c116ec1 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/xdr/.gitignore @@ -0,0 +1 @@ +library.?xx diff --git a/xsd-examples/cxx/tree/binary/xdr/README b/xsd-examples/cxx/tree/binary/xdr/README new file mode 100644 index 0000000..e02b2b9 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/xdr/README @@ -0,0 +1,36 @@ +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 on most UNIX and GNU/Linux systems as part +of Sun RPC (libtirpc-dev package on Debian/Ubuntu, libtirpc-devel +package on Fedora/RHEL, and as a part of the Standard C Library on +FreeBSD and MacOS). 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/buildfile b/xsd-examples/cxx/tree/binary/xdr/buildfile new file mode 100644 index 0000000..92f0c48 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/xdr/buildfile @@ -0,0 +1,30 @@ +# file : cxx/tree/binary/xdr/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} + +if ($cxx.target.class == 'linux') + import libs += libtirpc%lib{tirpc} + +./: exe{driver} doc{README} + +exe{driver}: {hxx cxx}{* -library} {hxx ixx cxx}{library} $libs + +exe{driver}: xml{library}: test.input = true + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-ostream \ + --generate-insertion 'XDR' \ + --generate-extraction 'XDR' \ + --generate-comparison \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" 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..f706ebf --- /dev/null +++ b/xsd-examples/cxx/tree/binary/xdr/driver.cxx @@ -0,0 +1,148 @@ +// file : cxx/tree/binary/xdr/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include // std::memcpy +#include // std::size_t +#include + +#include +#include + +#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); + + // Read in the file. + // + std::unique_ptr 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 (&buf), 0, &overflow); + xdr.x_op = XDR_ENCODE; + + xml_schema::ostream 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 (&ui), &underflow, 0); + xdr.x_op = XDR_DECODE; + + xdrrec_skiprecord (&xdr); + + xml_schema::istream ixdr (xdr); + + std::unique_ptr 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 (p)); + size_t n (static_cast (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 (p)); + size_t n (static_cast (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..05ed593 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/xdr/library.xml @@ -0,0 +1,52 @@ + + + + + + + + 0679760806 + The Master and Margarita + fiction + + + Mikhail Bulgakov + 1891-05-15 + 1940-03-10 + + + + + + 0679600841 + War and Peace + history + + + Leo Tolstoy + 1828-09-09 + 1910-11-20 + + + + + + 0679420290 + Crime and Punishment + philosophy + + + Fyodor Dostoevsky + 1821-11-11 + 1881-02-09 + + + + 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..8e1b316 --- /dev/null +++ b/xsd-examples/cxx/tree/binary/xdr/library.xsd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/buildfile b/xsd-examples/cxx/tree/buildfile new file mode 100644 index 0000000..3345cfb --- /dev/null +++ b/xsd-examples/cxx/tree/buildfile @@ -0,0 +1,6 @@ +# file : cxx/tree/buildfile +# license : not copyrighted - public domain + +# Exclude examples which depend on not yet packaged libraries. +# +./: {*/ -binary/ -xpath/} doc{README} diff --git a/xsd-examples/cxx/tree/caching/.gitignore b/xsd-examples/cxx/tree/caching/.gitignore new file mode 100644 index 0000000..c116ec1 --- /dev/null +++ b/xsd-examples/cxx/tree/caching/.gitignore @@ -0,0 +1 @@ +library.?xx diff --git a/xsd-examples/cxx/tree/caching/README b/xsd-examples/cxx/tree/caching/README new file mode 100644 index 0000000..64dffb3 --- /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 library.xsd diff --git a/xsd-examples/cxx/tree/caching/buildfile b/xsd-examples/cxx/tree/caching/buildfile new file mode 100644 index 0000000..cb369b7 --- /dev/null +++ b/xsd-examples/cxx/tree/caching/buildfile @@ -0,0 +1,27 @@ +# file : cxx/tree/caching/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}{* -library} {hxx ixx cxx}{library} $libs + +exe{driver}: {xml xsd}{library}: test.input = true + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" + +# Define XSD_CXX11 since we include libxsd headers directly. +# +cxx.poptions += -DXSD_CXX11 diff --git a/xsd-examples/cxx/tree/caching/driver.cxx b/xsd-examples/cxx/tree/caching/driver.cxx new file mode 100644 index 0000000..9cabbd4 --- /dev/null +++ b/xsd-examples/cxx/tree/caching/driver.cxx @@ -0,0 +1,165 @@ +// file : cxx/tree/caching/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#include +#include // chLatin_* +#include +#include // xercesc::Grammar +#include + +#include +#include +#include + +#include + +#include "library.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + if (argc != 3) + { + cerr << "usage: " << argv[0] << " library.xml library.xsd" << 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::unique_ptr 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 eh; + xml::dom::bits::error_handler_proxy ehp (eh); + conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + + // Initialize the schema cache. + // + if (!parser->loadGrammar (argv[2], Grammar::SchemaGrammarType, true)) + { + // In Xerces-C++ grammar loading failure results in just a warning. + // Make it a fatal error. + // + eh.handle (argv[2], 0, 0, + tree::error_handler::severity::fatal, + "unable to load schema"); + } + + eh.throw_if_failed (); + + // 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::unique_ptr doc (parser->parse (&wrap)); + + eh.throw_if_failed (); + + // Parse DOM to the object model. + // + unique_ptr 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..b36786f --- /dev/null +++ b/xsd-examples/cxx/tree/caching/library.xml @@ -0,0 +1,52 @@ + + + + + + + + 0679760806 + The Master and Margarita + fiction + + + Mikhail Bulgakov + 1891-05-15 + 1940-03-10 + + + + + + 0679600841 + War and Peace + history + + + Leo Tolstoy + 1828-09-09 + 1910-11-20 + + + + + + 0679420290 + Crime and Punishment + philosophy + + + Fyodor Dostoevsky + 1821-11-11 + 1881-02-09 + + + + diff --git a/xsd-examples/cxx/tree/caching/library.xsd b/xsd-examples/cxx/tree/caching/library.xsd new file mode 100644 index 0000000..2dd5037 --- /dev/null +++ b/xsd-examples/cxx/tree/caching/library.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/compression/.gitignore b/xsd-examples/cxx/tree/compression/.gitignore new file mode 100644 index 0000000..f7293f9 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/.gitignore @@ -0,0 +1,2 @@ +library.?xx +out.xml.gz 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/buildfile b/xsd-examples/cxx/tree/compression/buildfile new file mode 100644 index 0000000..6997339 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/buildfile @@ -0,0 +1,28 @@ +# file : cxx/tree/compression/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} +import libs += libz%lib{z} + +./: exe{driver} file{library.xml.gz} doc{README} + +exe{driver}: {hxx cxx}{* -library} {hxx ixx cxx}{library} $libs testscript + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --generate-ostream \ + --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/compression/compressed-format-target.cxx b/xsd-examples/cxx/tree/compression/compressed-format-target.cxx new file mode 100644 index 0000000..2d150a0 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-format-target.cxx @@ -0,0 +1,152 @@ +// file : cxx/tree/compression/compressed-format-target.cxx +// copyright : not copyrighted - public domain + +#include +#include // 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 (buf), size); + n_ += size; + } + else + write (reinterpret_cast (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 (const_cast (buf)); + zs_.avail_in = static_cast (size); + + do + { + zs_.next_out = reinterpret_cast (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 (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..0061cfa --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-format-target.hxx @@ -0,0 +1,91 @@ +// file : cxx/tree/compression/compressed-format-target.hxx +// copyright : not copyrighted - public domain + +#ifndef COMPRESSED_FORMAT_TARGET_HXX +#define COMPRESSED_FORMAT_TARGET_HXX + +#include + +#include +#include // std::size_t +#include + +#include + +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..03be960 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-input-source.cxx @@ -0,0 +1,195 @@ +// file : cxx/tree/compression/compressed-input-source.cxx +// copyright : not copyrighted - public domain + +#include + +#include + +#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 (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 (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 (buf); + zs_.avail_out = static_cast (size); + + int r; + + do + { + if (zs_.avail_in == 0) + { + zs_.avail_in = static_cast (read ()); + zs_.next_in = reinterpret_cast (const_cast (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 (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 (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 (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..706433b --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-input-source.hxx @@ -0,0 +1,121 @@ +// file : cxx/tree/compression/compressed-input-source.hxx +// copyright : not copyrighted - public domain + +#ifndef COMPRESSED_INPUT_SOURCE_HXX +#define COMPRESSED_INPUT_SOURCE_HXX + +#include + +#include +#include +#include // std::size_t +#include + +#include +#include + +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..15d842b --- /dev/null +++ b/xsd-examples/cxx/tree/compression/driver.cxx @@ -0,0 +1,124 @@ +// file : cxx/tree/compression/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#include + +#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]); + + unique_ptr 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 new file mode 100644 index 0000000..dd71159 Binary files /dev/null and b/xsd-examples/cxx/tree/compression/library.xml.gz differ diff --git a/xsd-examples/cxx/tree/compression/library.xsd b/xsd-examples/cxx/tree/compression/library.xsd new file mode 100644 index 0000000..a741e7e --- /dev/null +++ b/xsd-examples/cxx/tree/compression/library.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/compression/testscript b/xsd-examples/cxx/tree/compression/testscript new file mode 100644 index 0000000..649de5a --- /dev/null +++ b/xsd-examples/cxx/tree/compression/testscript @@ -0,0 +1,4 @@ +# file : cxx/tree/compression/testscript +# license : not copyrighted - public domain + +$* $src_base/library.xml.gz &out.xml.gz 2>| : compressed-out 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/buildfile b/xsd-examples/cxx/tree/custom/buildfile new file mode 100644 index 0000000..e650f99 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/buildfile @@ -0,0 +1,6 @@ +# file : cxx/tree/custom/buildfile +# license : not copyrighted - public domain + +# Exclude examples which depend on not yet packaged libraries. +# +./: {*/ -calendar/} diff --git a/xsd-examples/cxx/tree/custom/calendar/.gitignore b/xsd-examples/cxx/tree/custom/calendar/.gitignore new file mode 100644 index 0000000..2f35b6b --- /dev/null +++ b/xsd-examples/cxx/tree/custom/calendar/.gitignore @@ -0,0 +1,2 @@ +calendar.?xx +xml-schema.hxx 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/buildfile b/xsd-examples/cxx/tree/custom/calendar/buildfile new file mode 100644 index 0000000..3c26122 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/calendar/buildfile @@ -0,0 +1,47 @@ +# file : cxx/tree/custom/calendar/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} +import libs += libboost-date-time%lib{boost_date_time} + +./: exe{driver} doc{README} + +exe{driver}: {hxx cxx}{* -calendar -xml-schema} \ + {hxx ixx cxx}{calendar} \ + {hxx }{xml-schema} \ + $libs + +exe{driver}: xml{calendar}: test.input = true + +<{hxx ixx cxx}{calendar}>: xsd{calendar} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --extern-xml-schema xml-schema.xsd \ + --output-dir $out_base \ + $path($<[0]) +}} + +hxx{xml-schema}: $xsd +{{ + diag xsd gen ($>[0]) + + # Note that the specified xml-schema.xsd doesn't exist and is only used to + # deduce the generated header name. + # + $xsd cxx-tree --std c++11 \ + --generate-xml-schema \ + --custom-type date \ + --hxx-epilogue '#include "xml-schema-custom.hxx"' \ + --output-dir $out_base \ + xml-schema.xsd +}} + +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/calendar/calendar.xml b/xsd-examples/cxx/tree/custom/calendar/calendar.xml new file mode 100644 index 0000000..8fff59c --- /dev/null +++ b/xsd-examples/cxx/tree/custom/calendar/calendar.xml @@ -0,0 +1,22 @@ + + + + + + + + Don't forget to change the tire. + + + + Can be cancelled if it is too cold. + + + 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..8b36c34 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/calendar/calendar.xsd @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + 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..fdecf57 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/calendar/driver.cxx @@ -0,0 +1,39 @@ +// file : cxx/tree/custom/calendar/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#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::unique_ptr 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/xml-schema-custom.cxx b/xsd-examples/cxx/tree/custom/calendar/xml-schema-custom.cxx new file mode 100644 index 0000000..2bfe0f2 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/calendar/xml-schema-custom.cxx @@ -0,0 +1,56 @@ +// file : 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::transcode +#include // 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 (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 (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..f8f8218 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/calendar/xml-schema-custom.hxx @@ -0,0 +1,33 @@ +// file : 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::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/.gitignore b/xsd-examples/cxx/tree/custom/comments/.gitignore new file mode 100644 index 0000000..78cfc67 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/.gitignore @@ -0,0 +1,2 @@ +people.?xx +xml-schema.hxx 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/buildfile b/xsd-examples/cxx/tree/custom/comments/buildfile new file mode 100644 index 0000000..093a6cc --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/buildfile @@ -0,0 +1,48 @@ +# file : cxx/tree/custom/comments/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 -xml-schema} \ + {hxx ixx cxx}{people} \ + {hxx }{xml-schema} \ + $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 \ + --extern-xml-schema xml-schema.xsd \ + --output-dir $out_base \ + $path($<[0]) +}} + +hxx{xml-schema}: $xsd +{{ + diag xsd gen ($>[0]) + + # Note that the specified xml-schema.xsd doesn't exist and is only used to + # deduce the generated header name. + # + $xsd cxx-tree --std c++11 \ + --generate-xml-schema \ + --generate-serialization \ + --custom-type anyType=/type_base \ + --hxx-epilogue '#include "xml-schema-custom.hxx"' \ + --output-dir $out_base \ + xml-schema.xsd +}} + +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/comments/dom-parse.cxx b/xsd-examples/cxx/tree/custom/comments/dom-parse.cxx new file mode 100644 index 0000000..2fa6a70 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/dom-parse.cxx @@ -0,0 +1,93 @@ +// file : cxx/tree/custom/comments/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include + +#include +#include // chLatin_* +#include + +#include +#include + +#include +#include + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::unique_ptr +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::unique_ptr 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 eh; + xml::dom::bits::error_handler_proxy ehp (eh); + conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + + // Prepare input stream. + // + xml::sax::std_input_source isrc (is, id); + Wrapper4InputSource wrap (&isrc, false); + + xml::dom::unique_ptr doc (parser->parse (&wrap)); + + eh.throw_if_failed > (); + + 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..83c3dd4 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/dom-parse.hxx @@ -0,0 +1,23 @@ +// file : cxx/tree/custom/comments/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include +#include + +#include + +#include + +// 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::unique_ptr +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..5588273 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/driver.cxx @@ -0,0 +1,90 @@ +// file : cxx/tree/custom/commens/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#include +#include + +#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::unique_ptr doc ( + parse (ifs, argv[1], true)); + + // Parse the DOM document to the object model. + // + unique_ptr 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/people.xml b/xsd-examples/cxx/tree/custom/comments/people.xml new file mode 100644 index 0000000..08d69e9 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/people.xml @@ -0,0 +1,20 @@ + + + + + + + + + Joe Dirt + 28 + + + 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..20f265f --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/people.xsd @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + 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..265e0cb --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/xml-schema-custom.cxx @@ -0,0 +1,117 @@ +// file : 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 +#include + +#include // 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 (n)); + comment_ = xml::transcode (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..01a4f9c --- /dev/null +++ b/xsd-examples/cxx/tree/custom/comments/xml-schema-custom.hxx @@ -0,0 +1,60 @@ +// file : 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 + +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); + + type& + operator= (const type&) = default; + + 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/.gitignore b/xsd-examples/cxx/tree/custom/contacts/.gitignore new file mode 100644 index 0000000..43c214d --- /dev/null +++ b/xsd-examples/cxx/tree/custom/contacts/.gitignore @@ -0,0 +1 @@ +contacts.?xx 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/buildfile b/xsd-examples/cxx/tree/custom/contacts/buildfile new file mode 100644 index 0000000..190306c --- /dev/null +++ b/xsd-examples/cxx/tree/custom/contacts/buildfile @@ -0,0 +1,25 @@ +# file : cxx/tree/custom/contacts/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}{* -contacts} {hxx ixx cxx}{contacts} $libs + +exe{driver}: xml{contacts}: test.input = true + +<{hxx ixx cxx}{contacts}>: xsd{contacts} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --custom-type contact=/contact_base \ + --hxx-epilogue '#include "contacts-custom.hxx"' \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" "-I$src_base" 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..208b00f --- /dev/null +++ b/xsd-examples/cxx/tree/custom/contacts/contacts-custom.cxx @@ -0,0 +1,50 @@ +// file : cxx/tree/custom/contacts/contacts-custom.cxx +// copyright : not copyrighted - public domain + +#include + +// 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..a5bc893 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/contacts/contacts-custom.hxx @@ -0,0 +1,43 @@ +// file : 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 // 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..884c25e --- /dev/null +++ b/xsd-examples/cxx/tree/custom/contacts/contacts.xml @@ -0,0 +1,20 @@ + + + + + + + + Joe Dirt + joe@dirt.com + 555 DIRT + + + 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..5348810 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/contacts/contacts.xsd @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + 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..a0c7510 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/contacts/driver.cxx @@ -0,0 +1,38 @@ +// file : cxx/tree/custom/contacts/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#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::unique_ptr 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/double/.gitignore b/xsd-examples/cxx/tree/custom/double/.gitignore new file mode 100644 index 0000000..5cc7f75 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/double/.gitignore @@ -0,0 +1,2 @@ +order.?xx +xml-schema.hxx 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/buildfile b/xsd-examples/cxx/tree/custom/double/buildfile new file mode 100644 index 0000000..258191a --- /dev/null +++ b/xsd-examples/cxx/tree/custom/double/buildfile @@ -0,0 +1,46 @@ +# file : cxx/tree/custom/double/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}{* -order -xml-schema} \ + {hxx ixx cxx}{order} \ + {hxx }{xml-schema} \ + $libs + +<{hxx ixx cxx}{order}>: xsd{order} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --extern-xml-schema xml-schema.xsd \ + --output-dir $out_base \ + $path($<[0]) +}} + +hxx{xml-schema}: $xsd +{{ + diag xsd gen ($>[0]) + + # Note that the specified xml-schema.xsd doesn't exist and is only used to + # deduce the generated header name. + # + $xsd cxx-tree --std c++11 \ + --generate-xml-schema \ + --generate-serialization \ + --custom-type double=double \ + --hxx-epilogue '#include "double-custom.hxx"' \ + --output-dir $out_base \ + xml-schema.xsd +}} + +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/double/double-custom.cxx b/xsd-examples/cxx/tree/custom/double/double-custom.cxx new file mode 100644 index 0000000..bfec6e0 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/double/double-custom.cxx @@ -0,0 +1,96 @@ +// file : 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 +#include +#include + +#include +#include + +using namespace std; + +// Parsing. +// +namespace xsd +{ + namespace cxx + { + namespace tree + { + double traits:: + 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 tmp (s); + trim (tmp); + + zc_istream 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..cb74442 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/double/double-custom.hxx @@ -0,0 +1,67 @@ +// file : 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 // xml::transcode +#include // text_content + +// Parsing. +// +namespace xsd +{ + namespace cxx + { + namespace tree + { + template<> + struct traits + { + static double + create (const xercesc::DOMElement& e, flags f, type* c) + { + return create (text_content (e), 0, f, c); + } + + static double + create (const xercesc::DOMAttr& a, flags f, type* c) + { + return create (xml::transcode (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..e3f1800 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/double/driver.cxx @@ -0,0 +1,31 @@ +// file : cxx/tree/custom/double/driver.cxx +// copyright : not copyrighted - public domain + +#include + +#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/order.xsd b/xsd-examples/cxx/tree/custom/double/order.xsd new file mode 100644 index 0000000..8066975 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/double/order.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + 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 // std::unique_ptr +#include + +#include +#include + +#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 + +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 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 (n->getTextContent ()); + break; + } + case DOMNode::ELEMENT_NODE: + { + xhtml2txt (static_cast (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 + +// 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 (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 ( + doc_->importNode (const_cast (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 (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 +#include + +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 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 @@ + + + + + + + + John + Doe + male + 32 + + +

Married to Jane Doe.

+
+
+
+ + + Jane + Doe + female + 28 + + +

Married to John Doe.

+
+
+
+ +
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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/custom/taxonomy/.gitignore b/xsd-examples/cxx/tree/custom/taxonomy/.gitignore new file mode 100644 index 0000000..71428ab --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/.gitignore @@ -0,0 +1,2 @@ +people.?xx +people-fwd.hxx 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/buildfile b/xsd-examples/cxx/tree/custom/taxonomy/buildfile new file mode 100644 index 0000000..9267c68 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/buildfile @@ -0,0 +1,31 @@ +# file : cxx/tree/custom/taxonomy/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} hxx{people-fwd} $libs + +exe{driver}: xml{people}: test.input = true + +<{hxx ixx cxx}{people} hxx{people-fwd}>: xsd{people} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-forward \ + --generate-polymorphic \ + --polymorphic-type person \ + --custom-type "person=person_impl/person_base" \ + --custom-type "superman=superman_impl/superman_base" \ + --custom-type "batman=batman_impl/batman_base" \ + --fwd-prologue '#include "people-custom-fwd.hxx"' \ + --hxx-prologue '#include "people-custom.hxx"' \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" "-I$src_base" 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..f719bbb --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/driver.cxx @@ -0,0 +1,38 @@ +// file : cxx/tree/custom/taxonomy/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#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::unique_ptr 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/people-custom-fwd.hxx b/xsd-examples/cxx/tree/custom/taxonomy/people-custom-fwd.hxx new file mode 100644 index 0000000..1b59a54 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/people-custom-fwd.hxx @@ -0,0 +1,19 @@ +// file : 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 + class person_impl; + + template + class superman_impl; + + template + 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..decc847 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/people-custom.cxx @@ -0,0 +1,156 @@ +// file : cxx/tree/custom/taxonomy/people-custom.cxx +// copyright : not copyrighted - public domain + +#include + +// Include people.hxx instead of people-custom.hxx here. +// +#include "people.hxx" + +namespace people +{ + // person_impl + // + template + person_impl:: + person_impl (const xml_schema::string& name) + : base (name) + { + } + + template + person_impl:: + person_impl (const xercesc::DOMElement& e, + xml_schema::flags f, + xml_schema::container* c) + : base (e, f, c) + { + } + + template + person_impl:: + person_impl (const person_impl& p, + xml_schema::flags f, + xml_schema::container* c) + : base (p, f, c) + { + } + + template + person_impl* person_impl:: + _clone (xml_schema::flags f, xml_schema::container* c) const + { + return new person_impl (*this, f, c); + } + + template + void person_impl:: + print (std::ostream& os) const + { + os << this->name () << std::endl; + } + + // Explicitly instantiate person_impl class template for person_base. + // + template class person_impl; + + + // superman_impl + // + template + superman_impl:: + superman_impl (const xml_schema::string& name, bool can_fly) + : base (name, can_fly) + { + } + + template + superman_impl:: + superman_impl (const xercesc::DOMElement& e, + xml_schema::flags f, + xml_schema::container* c) + : base (e, f, c) + { + } + + template + superman_impl:: + superman_impl (const superman_impl& s, + xml_schema::flags f, + xml_schema::container* c) + : base (s, f, c) + { + } + + template + superman_impl* superman_impl:: + _clone (xml_schema::flags f, xml_schema::container* c) const + { + return new superman_impl (*this, f, c); + } + + template + void superman_impl:: + 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; + + + // batman_impl + // + template + batman_impl:: + batman_impl (const xml_schema::string& name, + bool can_fly, + unsigned int wing_span) + : base (name, can_fly, wing_span) + { + } + + template + batman_impl:: + batman_impl (const xercesc::DOMElement& e, + xml_schema::flags f, + xml_schema::container* c) + : base (e, f, c) + { + } + + template + batman_impl:: + batman_impl (const batman_impl& s, + xml_schema::flags f, + xml_schema::container* c) + : base (s, f, c) + { + } + + template + batman_impl* batman_impl:: + _clone (xml_schema::flags f, xml_schema::container* c) const + { + return new batman_impl (*this, f, c); + } + + template + void batman_impl:: + 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; +} 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..58c94c4 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/people-custom.hxx @@ -0,0 +1,105 @@ +// file : 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 // std::ostream + +// Include people-fwd.hxx here so that we can refer to the generated +// types. +// +#include "people-fwd.hxx" + +namespace people +{ + // + // + template + 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); + + person_impl& + operator= (const person_impl&) = default; + + virtual person_impl* + _clone (xml_schema::flags = 0, + xml_schema::container* = 0) const; + + public: + virtual void + print (std::ostream&) const; + }; + + + // + // + template + 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; + + superman_impl& + operator= (const superman_impl&) = default; + + public: + virtual void + print (std::ostream&) const; + }; + + + // + // + template + 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); + + batman_impl& + operator= (const batman_impl&) = default; + + 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..831c547 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/people.xml @@ -0,0 +1,26 @@ + + + + + + + + Joe Dirt + + + + James "007" Bond + + + + Bruce Wayne + + + 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..b07f338 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/taxonomy/people.xsd @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/custom/wildcard/.gitignore b/xsd-examples/cxx/tree/custom/wildcard/.gitignore new file mode 100644 index 0000000..f32cbe8 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/wildcard/.gitignore @@ -0,0 +1 @@ +wildcard.?xx 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/buildfile b/xsd-examples/cxx/tree/custom/wildcard/buildfile new file mode 100644 index 0000000..e386709 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/wildcard/buildfile @@ -0,0 +1,27 @@ +# file : cxx/tree/custom/wildcard/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}{* -wildcard} {hxx ixx cxx}{wildcard} $libs + +exe{driver}: xml{wildcard}: test.input = true + +<{hxx ixx cxx}{wildcard}>: xsd{wildcard} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --generate-ostream \ + --custom-type data=/data_base \ + --hxx-epilogue '#include "wildcard-custom.hxx"' \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" "-I$src_base" 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..43fae82 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/wildcard/driver.cxx @@ -0,0 +1,47 @@ +// file : cxx/tree/custom/wildcard/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#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::unique_ptr 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/wildcard-custom.cxx b/xsd-examples/cxx/tree/custom/wildcard/wildcard-custom.cxx new file mode 100644 index 0000000..16798d2 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/wildcard/wildcard-custom.cxx @@ -0,0 +1,84 @@ +// file : cxx/tree/custom/wildcard/wildcard-custom.cxx +// copyright : not copyrighted - public domain + +#include + +// 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 (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..e789a86 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/wildcard/wildcard-custom.hxx @@ -0,0 +1,66 @@ +// file : 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..8f6ba65 --- /dev/null +++ b/xsd-examples/cxx/tree/custom/wildcard/wildcard.xml @@ -0,0 +1,14 @@ + + + + +abc123 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..a19be3f --- /dev/null +++ b/xsd-examples/cxx/tree/custom/wildcard/wildcard.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/embedded/.gitignore b/xsd-examples/cxx/tree/embedded/.gitignore new file mode 100644 index 0000000..9023e82 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/.gitignore @@ -0,0 +1,3 @@ +xsdbin +library.?xx +library-schema.?xx 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/buildfile b/xsd-examples/cxx/tree/embedded/buildfile new file mode 100644 index 0000000..c8e7808 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/buildfile @@ -0,0 +1,46 @@ +# file : cxx/tree/embedded/buildfile +# license : not copyrighted - public domain + +import libxsd = libxsd%lib{xsd} +import libxerces = libxerces-c%lib{xerces-c} + +./: exe{driver} exe{xsdbin} doc{README} + +# exe{driver} +# +exe{driver}: {hxx cxx}{* -xsdbin -library -library-schema} \ + {hxx ixx cxx}{library} \ + {hxx cxx}{library-schema} \ + $libxsd $libxerces + +exe{driver}: xml{library}: test.input = true + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --output-dir $out_base \ + $path($<[0]) +}} + +<{hxx cxx}{library-schema}>: xsd{library} exe{xsdbin} +{{ + diag xsdbin ($<[0]) # @@ TMP + + ($<[1]) --output-dir $out_base $path($<[0]) +}} + +# exe{xsdbin} +# +exe{xsdbin}: cxx{xsdbin} $libxerces +exe{xsdbin}: test = false + +# Build options. +# +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/embedded/driver.cxx b/xsd-examples/cxx/tree/embedded/driver.cxx new file mode 100644 index 0000000..445d046 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/driver.cxx @@ -0,0 +1,183 @@ +// file : cxx/tree/embedded/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#include +#include // chLatin_* +#include +#include // xercesc::Grammar +#include + +#include + +#include +#include +#include +#include + +#include + +#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); + + unique_ptr 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 (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::unique_ptr 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 eh; + xml::dom::bits::error_handler_proxy 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::unique_ptr doc (parser->parse (&wrap)); + + eh.throw_if_failed (); + + // Parse DOM to the object model. + // + unique_ptr 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..118ecb0 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/grammar-input-stream.cxx @@ -0,0 +1,95 @@ +// file : cxx/tree/embedded/grammar-input-stream.cxx +// copyright : not copyrighted - public domain + +#include +#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 (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 (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 (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..701be31 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/grammar-input-stream.hxx @@ -0,0 +1,40 @@ +// file : cxx/tree/embedded/grammar-input-stream.hxx +// copyright : not copyrighted - public domain + +#ifndef GRAMMAR_INPUT_STREAM_HXX +#define GRAMMAR_INPUT_STREAM_HXX + +#include +#include + +// 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..f2816e7 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/library.xml @@ -0,0 +1,52 @@ + + + + + + + + 0679760806 + The Master and Margarita + fiction + + + Mikhail Bulgakov + 1891-05-15 + 1940-03-10 + + + + + + 0679600841 + War and Peace + history + + + Leo Tolstoy + 1828-09-09 + 1910-11-20 + + + + + + 0679420290 + Crime and Punishment + philosophy + + + Fyodor Dostoevsky + 1821-11-11 + 1881-02-09 + + + + diff --git a/xsd-examples/cxx/tree/embedded/library.xsd b/xsd-examples/cxx/tree/embedded/library.xsd new file mode 100644 index 0000000..0ffee32 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/library.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/embedded/xsdbin.cxx b/xsd-examples/cxx/tree/embedded/xsdbin.cxx new file mode 100644 index 0000000..3539c52 --- /dev/null +++ b/xsd-examples/cxx/tree/embedded/xsdbin.cxx @@ -0,0 +1,494 @@ +// file : 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 +#include // std::unique_ptr +#include // std::size_t +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +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] " << endl + << "Options:" << endl + << " --help Print usage information and exit." << endl + << " --verbose Print progress information." << endl + << " --output-dir Write generated files to ." << endl + << " --hxx-suffix Header file suffix instead of '-schema.hxx'." << endl + << " --cxx-suffix Source file suffix instead of '-schema.cxx'." << endl + << " --array-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); + + unique_ptr gp (new XMLGrammarPoolImpl (mm)); + + // Load the schemas into grammar pool. + // + { + unique_ptr 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 (data.curPos ())); + const unsigned char* buf ( + static_cast (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 ( + 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 && (p == 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 " << 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 " << endl + << "#include " << 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 (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/.gitignore b/xsd-examples/cxx/tree/hello/.gitignore new file mode 100644 index 0000000..d73130a --- /dev/null +++ b/xsd-examples/cxx/tree/hello/.gitignore @@ -0,0 +1 @@ +hello.?xx 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/buildfile b/xsd-examples/cxx/tree/hello/buildfile new file mode 100644 index 0000000..241d6f1 --- /dev/null +++ b/xsd-examples/cxx/tree/hello/buildfile @@ -0,0 +1,23 @@ +# file : cxx/tree/hello/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}{* -hello} {hxx ixx cxx}{hello} $libs + +exe{driver}: xml{hello}: test.input = true + +<{hxx ixx cxx}{hello}>: xsd{hello} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" diff --git a/xsd-examples/cxx/tree/hello/driver.cxx b/xsd-examples/cxx/tree/hello/driver.cxx new file mode 100644 index 0000000..7c8cec0 --- /dev/null +++ b/xsd-examples/cxx/tree/hello/driver.cxx @@ -0,0 +1,36 @@ +// file : cxx/tree/hello/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#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 + { + unique_ptr 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..b534d21 --- /dev/null +++ b/xsd-examples/cxx/tree/hello/hello.xml @@ -0,0 +1,19 @@ + + + + + + + Hello + + sun + moon + world + + diff --git a/xsd-examples/cxx/tree/hello/hello.xsd b/xsd-examples/cxx/tree/hello/hello.xsd new file mode 100644 index 0000000..a945ecf --- /dev/null +++ b/xsd-examples/cxx/tree/hello/hello.xsd @@ -0,0 +1,52 @@ + + + + + + + + + + + The hello_t type consists of a greeting phrase and a + collection of names to which this greeting applies. + + + + + + + + + The greeting element contains the greeting phrase + for this hello object. + + + + + + + + The name elements contains names to be greeted. + + + + + + + + + + + The hello element is a root of the Hello XML vocabulary. + Every conforming document should start with this element. + + + + + diff --git a/xsd-examples/cxx/tree/library/.gitignore b/xsd-examples/cxx/tree/library/.gitignore new file mode 100644 index 0000000..c116ec1 --- /dev/null +++ b/xsd-examples/cxx/tree/library/.gitignore @@ -0,0 +1 @@ +library.?xx 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/buildfile b/xsd-examples/cxx/tree/library/buildfile new file mode 100644 index 0000000..4ab023b --- /dev/null +++ b/xsd-examples/cxx/tree/library/buildfile @@ -0,0 +1,25 @@ +# file : cxx/tree/library/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}{* -library} {hxx ixx cxx}{library} $libs + +exe{driver}: xml{library}: test.input = true + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-ostream \ + --generate-serialization \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" diff --git a/xsd-examples/cxx/tree/library/driver.cxx b/xsd-examples/cxx/tree/library/driver.cxx new file mode 100644 index 0000000..9086891 --- /dev/null +++ b/xsd-examples/cxx/tree/library/driver.cxx @@ -0,0 +1,130 @@ +// file : cxx/tree/library/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#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::unique_ptr 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..d048aa4 --- /dev/null +++ b/xsd-examples/cxx/tree/library/library.xml @@ -0,0 +1,52 @@ + + + + + + + + 0679760806 + The Master and Margarita + fiction + + + Mikhail Bulgakov + 1891-05-15 + 1940-03-10 + + + + + + 0679600841 + War and Peace + history + + + Leo Tolstoy + 1828-09-09 + 1910-11-20 + + + + + + 0679420290 + Crime and Punishment + philosophy + + + Fyodor Dostoevsky + 1821-11-11 + 1881-02-09 + + + + diff --git a/xsd-examples/cxx/tree/library/library.xsd b/xsd-examples/cxx/tree/library/library.xsd new file mode 100644 index 0000000..4db07ef --- /dev/null +++ b/xsd-examples/cxx/tree/library/library.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/messaging/.gitignore b/xsd-examples/cxx/tree/messaging/.gitignore new file mode 100644 index 0000000..f493b6c --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/.gitignore @@ -0,0 +1 @@ +protocol.?xx 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..27c1509 --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/balance.xml @@ -0,0 +1,16 @@ + + + + + + + 123456789 + + diff --git a/xsd-examples/cxx/tree/messaging/buildfile b/xsd-examples/cxx/tree/messaging/buildfile new file mode 100644 index 0000000..62fadda --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/buildfile @@ -0,0 +1,29 @@ +# file : cxx/tree/messaging/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} + +./: exe{driver} xml{balance deposit withdraw} doc{README} + +exe{driver}: {hxx cxx}{* -protocol} {hxx ixx cxx}{protocol} $libs testscript + +<{hxx ixx cxx}{protocol}>: xsd{protocol} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --root-element-all \ + --generate-element-type \ + --generate-element-map \ + --generate-serialization \ + --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/messaging/deposit.xml b/xsd-examples/cxx/tree/messaging/deposit.xml new file mode 100644 index 0000000..5be2a0a --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/deposit.xml @@ -0,0 +1,17 @@ + + + + + + + 123456789 + 1000000 + + 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..3ae5787 --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/dom-parse.cxx @@ -0,0 +1,93 @@ +// file : cxx/tree/messaging/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include + +#include +#include // chLatin_* +#include + +#include +#include + +#include +#include + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::unique_ptr +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::unique_ptr 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 eh; + xml::dom::bits::error_handler_proxy ehp (eh); + conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + + // Prepare input stream. + // + xml::sax::std_input_source isrc (is, id); + Wrapper4InputSource wrap (&isrc, false); + + xml::dom::unique_ptr doc (parser->parse (&wrap)); + + eh.throw_if_failed > (); + + 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..b73c52d --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/dom-parse.hxx @@ -0,0 +1,22 @@ +// file : cxx/tree/messaging/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include +#include + +#include +#include + +// 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::unique_ptr +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..b32c5a2 --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/dom-serialize.cxx @@ -0,0 +1,64 @@ +// file : cxx/tree/messaging/dom-serialize.cxx +// copyright : not copyrighted - public domain + +#include "dom-serialize.hxx" + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +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 eh; + xml::dom::bits::error_handler_proxy ehp (eh); + + xml::dom::ostream_format_target oft (os); + + // Create a DOMSerializer. + // + xml::dom::unique_ptr 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::unique_ptr out (impl->createLSOutput ()); + out->setEncoding (xml::string (encoding).c_str ()); + out->setByteStream (&oft); + + writer->write (&doc, out.get ()); + + eh.throw_if_failed > (); +} 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..bf1e290 --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/dom-serialize.hxx @@ -0,0 +1,20 @@ +// file : cxx/tree/messaging/dom-serialize.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_SERIALIZE +#define DOM_SERIALIZE + +#include +#include + +#include + +// 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..a358014 --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/driver.cxx @@ -0,0 +1,146 @@ +// file : cxx/tree/messaging/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include +#include +#include + +#include +#include + +#include + +#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]); + + unique_ptr req, res; + + // Parse the XML request to a DOM document using the parse() + // function from dom-parse.hxx. + // + { + xml_schema::dom::unique_ptr 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 (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 (*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 (*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::unique_ptr 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/protocol.xsd b/xsd-examples/cxx/tree/messaging/protocol.xsd new file mode 100644 index 0000000..4a28ac3 --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/protocol.xsd @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/messaging/testscript b/xsd-examples/cxx/tree/messaging/testscript new file mode 100644 index 0000000..c9df49f --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/testscript @@ -0,0 +1,6 @@ +# file : cxx/tree/messaging/testscript +# license : not copyrighted - public domain + +$* $src_base/balance.xml >| 2>| : balance +$* $src_base/withdraw.xml >| 2>| : withdraw +$* $src_base/deposit.xml >| 2>| : deposit diff --git a/xsd-examples/cxx/tree/messaging/withdraw.xml b/xsd-examples/cxx/tree/messaging/withdraw.xml new file mode 100644 index 0000000..e9ef526 --- /dev/null +++ b/xsd-examples/cxx/tree/messaging/withdraw.xml @@ -0,0 +1,17 @@ + + + + + + + 123456789 + 1000000 + + diff --git a/xsd-examples/cxx/tree/mixed/.gitignore b/xsd-examples/cxx/tree/mixed/.gitignore new file mode 100644 index 0000000..cbeac00 --- /dev/null +++ b/xsd-examples/cxx/tree/mixed/.gitignore @@ -0,0 +1 @@ +text.?xx 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 time. + +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/buildfile b/xsd-examples/cxx/tree/mixed/buildfile new file mode 100644 index 0000000..4c1be8e --- /dev/null +++ b/xsd-examples/cxx/tree/mixed/buildfile @@ -0,0 +1,27 @@ +# file : cxx/tree/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}{* -text} {hxx ixx cxx}{text} $libs + +exe{driver}: xml{text}: test.input = true + +<{hxx ixx cxx}{text}>: xsd{text} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" + +# Define XSD_CXX11 since we include libxsd headers directly. +# +cxx.poptions += -DXSD_CXX11 diff --git a/xsd-examples/cxx/tree/mixed/driver.cxx b/xsd-examples/cxx/tree/mixed/driver.cxx new file mode 100644 index 0000000..cf64e7f --- /dev/null +++ b/xsd-examples/cxx/tree/mixed/driver.cxx @@ -0,0 +1,122 @@ +// file : cxx/tree/mixed/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#include + +#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 + +using std::cout; +using std::cerr; +using std::endl; +using std::unique_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 + { + unique_ptr 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 (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 ( + n->getUserData (xml_schema::dom::tree_node_key))); + + anchor& a (dynamic_cast (t)); + + cout << a << "[" << ref << "]"; + + // Or we could continue using DOM interface: + // + //cout << xml::transcode (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/text.xml b/xsd-examples/cxx/tree/mixed/text.xml new file mode 100644 index 0000000..dfe730e --- /dev/null +++ b/xsd-examples/cxx/tree/mixed/text.xml @@ -0,0 +1,17 @@ + + + + + + +The first paragraph of this text talks about time. + +And this paragraph talks about space. + + diff --git a/xsd-examples/cxx/tree/mixed/text.xsd b/xsd-examples/cxx/tree/mixed/text.xsd new file mode 100644 index 0000000..f3c023d --- /dev/null +++ b/xsd-examples/cxx/tree/mixed/text.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/multiroot/.gitignore b/xsd-examples/cxx/tree/multiroot/.gitignore new file mode 100644 index 0000000..f493b6c --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/.gitignore @@ -0,0 +1 @@ +protocol.?xx 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..5f4a441 --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/balance.xml @@ -0,0 +1,16 @@ + + + + + + + 123456789 + + diff --git a/xsd-examples/cxx/tree/multiroot/buildfile b/xsd-examples/cxx/tree/multiroot/buildfile new file mode 100644 index 0000000..dc10588 --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/buildfile @@ -0,0 +1,26 @@ +# file : cxx/tree/multiroot/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} + +./: exe{driver} xml{balance deposit withdraw} doc{README} + +exe{driver}: {hxx cxx}{* -protocol} {hxx ixx cxx}{protocol} $libs testscript + +<{hxx ixx cxx}{protocol}>: xsd{protocol} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --root-element-all \ + --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/multiroot/deposit.xml b/xsd-examples/cxx/tree/multiroot/deposit.xml new file mode 100644 index 0000000..9db2a2a --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/deposit.xml @@ -0,0 +1,17 @@ + + + + + + + 123456789 + 1000000 + + 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..e67c187 --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/dom-parse.cxx @@ -0,0 +1,93 @@ +// file : cxx/tree/multiroot/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include + +#include +#include // chLatin_* +#include + +#include +#include + +#include +#include + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::unique_ptr +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::unique_ptr 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 eh; + xml::dom::bits::error_handler_proxy ehp (eh); + conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + + // Prepare input stream. + // + xml::sax::std_input_source isrc (is, id); + Wrapper4InputSource wrap (&isrc, false); + + xml::dom::unique_ptr doc (parser->parse (&wrap)); + + eh.throw_if_failed > (); + + 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..3699a77 --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/dom-parse.hxx @@ -0,0 +1,22 @@ +// file : cxx/tree/multiroot/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include +#include + +#include +#include + +// 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::unique_ptr +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..d22c25e --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/driver.cxx @@ -0,0 +1,124 @@ +// file : cxx/tree/multiroot/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include +#include + +#include +#include + +#include // 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. +// +unique_ptr +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::unique_ptr doc (parse (is, id, true)); + + DOMElement* root (doc->getDocumentElement ()); + + string ns (xml::transcode (root->getNamespaceURI ())); + string name (xml::transcode (root->getLocalName ())); + + unique_ptr 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]); + + unique_ptr r (parse (ifs, argv[1])); + + // Let's print what we've got. + // + if (balance_t* b = dynamic_cast (r.get ())) + { + cerr << "balance request for acc# " << b->account () << endl; + } + else if (withdraw_t* w = dynamic_cast (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/protocol.xsd b/xsd-examples/cxx/tree/multiroot/protocol.xsd new file mode 100644 index 0000000..2fe9456 --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/protocol.xsd @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/multiroot/testscript b/xsd-examples/cxx/tree/multiroot/testscript new file mode 100644 index 0000000..383bed4 --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/testscript @@ -0,0 +1,6 @@ +# file : cxx/tree/multiroot/testscript +# license : not copyrighted - public domain + +$* $src_base/balance.xml 2>| : balance +$* $src_base/withdraw.xml 2>| : withdraw +$* $src_base/deposit.xml 2>| : deposit diff --git a/xsd-examples/cxx/tree/multiroot/withdraw.xml b/xsd-examples/cxx/tree/multiroot/withdraw.xml new file mode 100644 index 0000000..f98ad16 --- /dev/null +++ b/xsd-examples/cxx/tree/multiroot/withdraw.xml @@ -0,0 +1,17 @@ + + + + + + + 123456789 + 1000000 + + 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/.gitignore b/xsd-examples/cxx/tree/order/element/.gitignore new file mode 100644 index 0000000..2fff792 --- /dev/null +++ b/xsd-examples/cxx/tree/order/element/.gitignore @@ -0,0 +1 @@ +transactions.?xx 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/buildfile b/xsd-examples/cxx/tree/order/element/buildfile new file mode 100644 index 0000000..eb3834e --- /dev/null +++ b/xsd-examples/cxx/tree/order/element/buildfile @@ -0,0 +1,30 @@ +# file : cxx/tree/order/element/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}{* -transactions} {hxx ixx cxx}{transactions} $libs + +exe{driver}: xml{transactions}: test.input = true + +<{hxx ixx cxx}{transactions}>: xsd{transactions} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --generate-wildcard \ + --ordered-type batch \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" + +# Define XSD_CXX11 since we include libxsd headers directly. +# +cxx.poptions += -DXSD_CXX11 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..2f62700 --- /dev/null +++ b/xsd-examples/cxx/tree/order/element/driver.cxx @@ -0,0 +1,147 @@ +// file : cxx/tree/order/element/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#include +#include + +#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 + +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::unique_ptr 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 (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/transactions.xml b/xsd-examples/cxx/tree/order/element/transactions.xml new file mode 100644 index 0000000..7af9ab1 --- /dev/null +++ b/xsd-examples/cxx/tree/order/element/transactions.xml @@ -0,0 +1,32 @@ + + + + + + + 123456789 + 1000000 + + + + 123456789 + + + + 123456789 + 500000 + + + + 123456789 + 500000 + + 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..7a63c9f --- /dev/null +++ b/xsd-examples/cxx/tree/order/element/transactions.xsd @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/order/mixed/.gitignore b/xsd-examples/cxx/tree/order/mixed/.gitignore new file mode 100644 index 0000000..cbeac00 --- /dev/null +++ b/xsd-examples/cxx/tree/order/mixed/.gitignore @@ -0,0 +1 @@ +text.?xx 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 time. + +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/buildfile b/xsd-examples/cxx/tree/order/mixed/buildfile new file mode 100644 index 0000000..149bca0 --- /dev/null +++ b/xsd-examples/cxx/tree/order/mixed/buildfile @@ -0,0 +1,25 @@ +# file : cxx/tree/order/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}{* -text} {hxx ixx cxx}{text} $libs + +exe{driver}: xml{text}: test.input = true + +<{hxx ixx cxx}{text}>: xsd{text} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --ordered-type-mixed \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" 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..a18f4ad --- /dev/null +++ b/xsd-examples/cxx/tree/order/mixed/driver.cxx @@ -0,0 +1,89 @@ +// file : cxx/tree/order/mixed/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#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::unique_ptr 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/text.xml b/xsd-examples/cxx/tree/order/mixed/text.xml new file mode 100644 index 0000000..3d7476d --- /dev/null +++ b/xsd-examples/cxx/tree/order/mixed/text.xml @@ -0,0 +1,17 @@ + + + + + + +The first paragraph of this text talks about time. + +And this paragraph talks about space. + + 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..b55d214 --- /dev/null +++ b/xsd-examples/cxx/tree/order/mixed/text.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/performance/.gitignore b/xsd-examples/cxx/tree/performance/.gitignore new file mode 100644 index 0000000..b143f97 --- /dev/null +++ b/xsd-examples/cxx/tree/performance/.gitignore @@ -0,0 +1,5 @@ +gen + +# Testscript output directory (can be symlink). +# +test-gen diff --git a/xsd-examples/cxx/tree/performance/README b/xsd-examples/cxx/tree/performance/README new file mode 100644 index 0000000..0206387 --- /dev/null +++ b/xsd-examples/cxx/tree/performance/README @@ -0,0 +1,62 @@ +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 + +To generate the test document execute, for example: + +$ ./gen 633 test-100k.xml diff --git a/xsd-examples/cxx/tree/performance/buildfile b/xsd-examples/cxx/tree/performance/buildfile new file mode 100644 index 0000000..e9faeef --- /dev/null +++ b/xsd-examples/cxx/tree/performance/buildfile @@ -0,0 +1,36 @@ +# file : cxx/tree/performance/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} + +./: doc{README} + +# exe{driver} +# +./: exe{driver}: {hxx cxx}{* -gen -test} {hxx ixx cxx}{test} $libs + +exe{driver}: xml{test-50k}: test.input = true + +<{hxx ixx cxx}{test}>: xsd{test} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --output-dir $out_base \ + $path($<[0]) +}} + +# exe{gen} +# +./: exe{gen}: cxx{gen} testscript{gen} + +# Build options. +# +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/performance/driver.cxx b/xsd-examples/cxx/tree/performance/driver.cxx new file mode 100644 index 0000000..b156f84 --- /dev/null +++ b/xsd-examples/cxx/tree/performance/driver.cxx @@ -0,0 +1,90 @@ +// file : cxx/tree/performance/driver.cxx +// copyright : not copyrighted - public domain + +#include +#include +#include + +#include + +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 ] 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 +#include +#include + +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] << " " << 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 << ""; + + unsigned short ch (1), en (0); + + for (unsigned long i (0); i < n; ++i) + { + ofs << "" + << "42" + << "42345.4232" + << "name123_45"; + + if (i % 2 == 1) + ofs << "one two three"; + + ofs << "" << ch << " choice" + << "" << enums[en] << "" + << ""; + + if (++ch > 4) + ch = 1; + + if (++en > 4) + en = 0; + } + + ofs << ""; +} diff --git a/xsd-examples/cxx/tree/performance/gen.testscript b/xsd-examples/cxx/tree/performance/gen.testscript new file mode 100644 index 0000000..deefc05 --- /dev/null +++ b/xsd-examples/cxx/tree/performance/gen.testscript @@ -0,0 +1,9 @@ +# file : cxx/tree/performance/gen.testscript +# license : not copyrighted - public domain + +: 50k +: +{ + $* 317 test-50k.xml &test-50k.xml; + cat test-50k.xml >>>$src_base/test-50k.xml +} diff --git a/xsd-examples/cxx/tree/performance/parsing.cxx b/xsd-examples/cxx/tree/performance/parsing.cxx new file mode 100644 index 0000000..c41b57d --- /dev/null +++ b/xsd-examples/cxx/tree/performance/parsing.cxx @@ -0,0 +1,172 @@ +// file : cxx/tree/performance/parsing.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include // std::size_t +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#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 eh; + xsd::cxx::xml::dom::bits::error_handler_proxy ehp (eh); + + xml_schema::dom::unique_ptr 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::severity::fatal, + "unable to load schema"); + } + + eh.throw_if_failed (); + 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 (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::unique_ptr doc (parser->parse (&wis)); + eh.throw_if_failed (); + + // Then parse DOM to the object model. + // + unique_ptr 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..e81fcbd --- /dev/null +++ b/xsd-examples/cxx/tree/performance/serialization.cxx @@ -0,0 +1,132 @@ +// file : cxx/tree/performance/serialization.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include // std::size_t +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#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. + // + unique_ptr 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 eh; + xsd::cxx::xml::dom::bits::error_handler_proxy ehp (eh); + + xml_schema::dom::unique_ptr writer ( + impl->createLSSerializer ()); + + DOMConfiguration* conf (writer->getDomConfig ()); + + conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + conf->setParameter (XMLUni::fgDOMXMLDeclaration, false); + + xml_schema::dom::unique_ptr 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::unique_ptr 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 (); + } + + 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 @@ +4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction4242345.4232name123_45one two three2 choicehorror4242345.4232name123_453 choicehistory4242345.4232name123_45one two three4 choicephilosophy4242345.4232name123_451 choiceromance4242345.4232name123_45one two three2 choicefiction4242345.4232name123_453 choicehorror4242345.4232name123_45one two three4 choicehistory4242345.4232name123_451 choicephilosophy4242345.4232name123_45one two three2 choiceromance4242345.4232name123_453 choicefiction4242345.4232name123_45one two three4 choicehorror4242345.4232name123_451 choicehistory4242345.4232name123_45one two three2 choicephilosophy4242345.4232name123_453 choiceromance4242345.4232name123_45one two three4 choicefiction4242345.4232name123_451 choicehorror4242345.4232name123_45one two three2 choicehistory4242345.4232name123_453 choicephilosophy4242345.4232name123_45one two three4 choiceromance4242345.4232name123_451 choicefiction \ 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..98ee921 --- /dev/null +++ b/xsd-examples/cxx/tree/performance/test.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/performance/time.cxx b/xsd-examples/cxx/tree/performance/time.cxx new file mode 100644 index 0000000..48385a1 --- /dev/null +++ b/xsd-examples/cxx/tree/performance/time.cxx @@ -0,0 +1,46 @@ +// file : cxx/tree/performance/time.cxx +// copyright : not copyrighted - public domain + +#include "time.hxx" + +#if defined (WIN32) || defined (__WIN32__) +# define WIN32_LEAN_AND_MEAN +# include // GetSystemTimeAsFileTime +#else +# include // gettimeofday +# include // timeval +#endif + +#include // std::ostream +#include // 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 (v / 10000000ULL); + nsec_ = static_cast ((v % 10000000ULL) * 100); +#else + timeval tv; + if (gettimeofday(&tv, 0) != 0) + throw failed (); + + sec_ = static_cast (tv.tv_sec); + nsec_ = static_cast (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..b05414b --- /dev/null +++ b/xsd-examples/cxx/tree/performance/time.hxx @@ -0,0 +1,110 @@ +// file : cxx/tree/performance/time.hxx +// copyright : not copyrighted - public domain + +#ifndef TIME_HXX +#define TIME_HXX + +#include // 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 (nsec / 1000000000ULL); + nsec_ = static_cast (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 (b.sec_ + tmp / 1000000000ULL); + nsec_ = static_cast (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/.gitignore b/xsd-examples/cxx/tree/polymorphism/.gitignore new file mode 100644 index 0000000..f2e9b04 --- /dev/null +++ b/xsd-examples/cxx/tree/polymorphism/.gitignore @@ -0,0 +1 @@ +supermen.?xx 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/buildfile b/xsd-examples/cxx/tree/polymorphism/buildfile new file mode 100644 index 0000000..754c6c2 --- /dev/null +++ b/xsd-examples/cxx/tree/polymorphism/buildfile @@ -0,0 +1,26 @@ +# file : cxx/tree/polymorphism/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}{* -supermen} {hxx ixx cxx}{supermen} $libs + +exe{driver}: xml{supermen}: test.input = true + +<{hxx ixx cxx}{supermen}>: xsd{supermen} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-polymorphic \ + --generate-serialization \ + --root-element-last \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" diff --git a/xsd-examples/cxx/tree/polymorphism/driver.cxx b/xsd-examples/cxx/tree/polymorphism/driver.cxx new file mode 100644 index 0000000..6458170 --- /dev/null +++ b/xsd-examples/cxx/tree/polymorphism/driver.cxx @@ -0,0 +1,59 @@ +// file : cxx/tree/polymorphism/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include + +#include "supermen.hxx" + +using std::cerr; +using std::endl; +using std::unique_ptr; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " supermen.xml" << endl; + return 1; + } + + try + { + unique_ptr 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 (&*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/supermen.xml b/xsd-examples/cxx/tree/polymorphism/supermen.xml new file mode 100644 index 0000000..08430fa --- /dev/null +++ b/xsd-examples/cxx/tree/polymorphism/supermen.xml @@ -0,0 +1,25 @@ + + + + + + + + John Doe + + + + James "007" Bond + + + + Bruce Wayne + + + diff --git a/xsd-examples/cxx/tree/polymorphism/supermen.xsd b/xsd-examples/cxx/tree/polymorphism/supermen.xsd new file mode 100644 index 0000000..cf5ff0c --- /dev/null +++ b/xsd-examples/cxx/tree/polymorphism/supermen.xsd @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/secure/.gitignore b/xsd-examples/cxx/tree/secure/.gitignore new file mode 100644 index 0000000..c116ec1 --- /dev/null +++ b/xsd-examples/cxx/tree/secure/.gitignore @@ -0,0 +1 @@ +library.?xx diff --git a/xsd-examples/cxx/tree/secure/README b/xsd-examples/cxx/tree/secure/README new file mode 100644 index 0000000..649f0a3 --- /dev/null +++ b/xsd-examples/cxx/tree/secure/README @@ -0,0 +1,41 @@ +This example shows how to perform more secure XML parsing by disabling +the XML External Entity (XXE) Processing. If XML Schema validation is +used, then it would also make sense to pre-load the known schemas and +to disable loading of any external schemas, for example, via the +schemaLocation attribute found in the XML documents. See the comment +in driver.cxx for more information on how to achieve this. + +The example consists of the following files: + +library.xsd + XML Schema which describes a library of books. + +library.xml + Sample XML instance document. It includes (commented out) DOCTYPE + declarations with internal and external subsets that the parser + will refuse to process. + +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. + +secure-dom-parser.hxx +secure-dom-parser.cxx + A secure Xerces-C++ DOM parser implementation that disables processing + of internal/external DTD subsets. + +driver.cxx + Driver for the example. It first sets up the secure DOM parser. It then + parses the input file to a DOM document using the secure DOM parser and + calls one of the parsing functions that constructs the object model from + this DOM document. Finally, 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 + +To verify that DTD processing is disabled, uncomment a different DOCTYPE +version in the sample document. diff --git a/xsd-examples/cxx/tree/secure/buildfile b/xsd-examples/cxx/tree/secure/buildfile new file mode 100644 index 0000000..b1ca71f --- /dev/null +++ b/xsd-examples/cxx/tree/secure/buildfile @@ -0,0 +1,27 @@ +# file : cxx/tree/secure/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}{* -library} {hxx ixx cxx}{library} $libs + +exe{driver}: xml{library}: test.input = true + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --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/secure/driver.cxx b/xsd-examples/cxx/tree/secure/driver.cxx new file mode 100644 index 0000000..7b6886f --- /dev/null +++ b/xsd-examples/cxx/tree/secure/driver.cxx @@ -0,0 +1,141 @@ +// file : cxx/tree/secure/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "library.hxx" +#include "secure-dom-parser.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; + + xml::dom::unique_ptr parser (new SecureDOMParser ()); + + 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 + + // Disable loading schemas via other means (e.g., schemaLocation). + // + // Note: this might be a good idea though if you need validation, + // you will need to pre-load the schema via other means. See the + // 'caching' and 'embedded' examples for different approaches. + // Both of them can be used with SecureDOMParser. + // + // conf->setParameter (XMLUni::fgXercesLoadSchema, false); + + // We will release the DOM document ourselves. + // + conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); + + // Set error handler. + // + tree::error_handler eh; + xml::dom::bits::error_handler_proxy ehp (eh); + conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + + // Parse the XML document. + // + 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::unique_ptr doc (parser->parse (&wrap)); + + eh.throw_if_failed (); + + // Parse DOM to the object model. + // + unique_ptr 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/secure/library.xml b/xsd-examples/cxx/tree/secure/library.xml new file mode 100644 index 0000000..fa5f044 --- /dev/null +++ b/xsd-examples/cxx/tree/secure/library.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + 0679760806 + The Master and Margarita + fiction + + + Mikhail Bulgakov + 1891-05-15 + 1940-03-10 + + + + + + 0679600841 + War and Peace + history + + + Leo Tolstoy + 1828-09-09 + 1910-11-20 + + + + + + 0679420290 + Crime and Punishment + philosophy + + + Fyodor Dostoevsky + 1821-11-11 + 1881-02-09 + + + + diff --git a/xsd-examples/cxx/tree/secure/library.xsd b/xsd-examples/cxx/tree/secure/library.xsd new file mode 100644 index 0000000..f80da3c --- /dev/null +++ b/xsd-examples/cxx/tree/secure/library.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/secure/secure-dom-parser.cxx b/xsd-examples/cxx/tree/secure/secure-dom-parser.cxx new file mode 100644 index 0000000..8eb7a28 --- /dev/null +++ b/xsd-examples/cxx/tree/secure/secure-dom-parser.cxx @@ -0,0 +1,24 @@ +// file : cxx/tree/secure/secure-dom-parser.cxx +// copyright : not copyrighted - public domain + +#include "secure-dom-parser.hxx" + +#include +#include + +using namespace xercesc; + +void SecureDOMParser:: +doctypeDecl (const DTDElementDecl& e, + const XMLCh* const pub_id, + const XMLCh* const sys_id, + const bool hasi, + const bool hase) +{ + if (hasi || hase) + ThrowXMLwithMemMgr(RuntimeException, + XMLExcepts::Gen_NoDTDValidator, + fMemoryManager); + + DOMLSParserImpl::doctypeDecl (e, pub_id, sys_id, hasi, hase); +} diff --git a/xsd-examples/cxx/tree/secure/secure-dom-parser.hxx b/xsd-examples/cxx/tree/secure/secure-dom-parser.hxx new file mode 100644 index 0000000..d70dff0 --- /dev/null +++ b/xsd-examples/cxx/tree/secure/secure-dom-parser.hxx @@ -0,0 +1,25 @@ +// file : cxx/tree/secure/secure-dom-parser.hxx +// copyright : not copyrighted - public domain + +#ifndef SECURE_DOM_PARSER_HXX +#define SECURE_DOM_PARSER_HXX + +#include + +class SecureDOMParser: public xercesc::DOMLSParserImpl +{ +public: + SecureDOMParser (xercesc::MemoryManager* mm = + xercesc::XMLPlatformUtils::fgMemoryManager, + xercesc::XMLGrammarPool* gp = 0) + : DOMLSParserImpl (0, mm, gp) {} + + virtual void + doctypeDecl (const xercesc::DTDElementDecl& root, + const XMLCh* const public_id, + const XMLCh* const system_id, + const bool has_internal, + const bool has_external); +}; + +#endif // SECURE_DOM_PARSER_HXX diff --git a/xsd-examples/cxx/tree/streaming/.gitignore b/xsd-examples/cxx/tree/streaming/.gitignore new file mode 100644 index 0000000..db4a6e9 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/.gitignore @@ -0,0 +1 @@ +position.?xx 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/buildfile b/xsd-examples/cxx/tree/streaming/buildfile new file mode 100644 index 0000000..8c34b17 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/buildfile @@ -0,0 +1,26 @@ +# file : cxx/tree/streaming/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} + +./: exe{driver} xml{position} doc{README} + +exe{driver}: {hxx cxx}{* -position} {hxx ixx cxx}{position} $libs testscript + +<{hxx ixx cxx}{position}>: xsd{position} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --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/streaming/driver.cxx b/xsd-examples/cxx/tree/streaming/driver.cxx new file mode 100644 index 0000000..8a70f58 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/driver.cxx @@ -0,0 +1,139 @@ +// file : cxx/tree/streaming/driver.cxx +// copyright : not copyrighted - public domain + +#include +#include + +#include + +#include // 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::unique_ptr 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 ( + 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 (move (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 (move (doc1), move (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..6f17f33 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/grammar-input-stream.cxx @@ -0,0 +1,96 @@ +// file : cxx/tree/streaming/grammar-input-stream.cxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#include +#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 (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 (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 (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..17e6913 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/grammar-input-stream.hxx @@ -0,0 +1,41 @@ +// file : cxx/tree/streaming/grammar-input-stream.hxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#ifndef GRAMMAR_INPUT_STREAM_HXX +#define GRAMMAR_INPUT_STREAM_HXX + +#include +#include + +// 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/parser.cxx b/xsd-examples/cxx/tree/streaming/parser.cxx new file mode 100644 index 0000000..064dc77 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/parser.cxx @@ -0,0 +1,371 @@ +#include +#include // std::move() + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include // xercesc::Grammar +#include + +#include +#include + +#include +#include + +#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_; + unique_ptr grammar_pool_; + unique_ptr parser_; + XMLPScanToken token_; + tree::error_handler error_handler_; + xml::sax::bits::error_handler_proxy error_proxy_; + unique_ptr 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 > (); +} + +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 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 > (); + } + + if (!r) + return document_ptr (); + + return move (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) + { + // Move doc to outer_doc. + // + doc_ = move (outer_doc); + cur_ = static_cast ( + doc_->importNode (doc->getDocumentElement (), true)); + doc_->getDocumentElement ()->appendChild (cur_); + } + else + { + doc_ = move (doc); + cur_ = doc_->getDocumentElement (); + } + + // This handles the 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 move (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 > (); + } + + if (!r) + return document_ptr (); + + // 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 > (); + } + + if (!r) + return document_ptr (); + + return move (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 (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 (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 (move (doc), move (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..605d236 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/parser.hxx @@ -0,0 +1,67 @@ +#ifndef PARSER_HXX +#define PARSER_HXX + +#include +#include +#include // std::size_t +#include // std::unique_ptr + +#include + +#include + +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::unique_ptr 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::unique_ptr 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..3308306 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/position.xml @@ -0,0 +1,29 @@ + + + + + + +
+ Lion's Head + rock +
+ + + + + + + + + + +
diff --git a/xsd-examples/cxx/tree/streaming/position.xsd b/xsd-examples/cxx/tree/streaming/position.xsd new file mode 100644 index 0000000..0fbcf87 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/position.xsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/streaming/serializer.cxx b/xsd-examples/cxx/tree/streaming/serializer.cxx new file mode 100644 index 0000000..b903a49 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/serializer.cxx @@ -0,0 +1,636 @@ +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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* 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(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(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(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. + +public: + // Update the namespace stack to point to the strings from the + // new document's string pool. + // + void + update_namespace_stack (DOMDocument& d) + { + DOMDocumentImpl& di (dynamic_cast (d)); + + for (XMLSize_t i (0); i != fNamespaceStack->size (); ++i) + { + RefHashTableOf& t (*fNamespaceStack->elementAt (i)); + RefHashTableOfEnumerator e (&t, false, fMemoryManager); + while (e.hasMoreElements ()) + { + XMLCh* k ((XMLCh*) (e.nextElementKey ())); + XMLCh* v (t.get (k)); + t.put ((void*) (di.getPooledString (k)), + (XMLCh*) (di.getPooledString (v))); + } + } + } + +private: + XMLFormatTarget* target_; + std::unique_ptr formatter_; + int level_; + + std::vector 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::unique_ptr); + + void + serialize_open (xml::dom::unique_ptr); + + void + serialize_close (const string&); + +private: + void + clear_document (); + +private: + bool start_; + + // Serializer. + // + xml::dom::unique_ptr out_; + xml::dom::unique_ptr serializer_; + + unique_ptr oft_; + + tree::error_handler error_handler_; + xml::dom::bits::error_handler_proxy error_proxy_; + + // DOM document that we use to create the elements. + // + DOMImplementation& dom_impl_; + xml::dom::unique_ptr doc_; + vector 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 (*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 (*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::unique_ptr p) +{ + DOMElement* e (p.get ()); + + if (start_) + { + serializer_->write (e, out_.get ()); + start_ = false; + } + else + serializer_->write (e); + + error_handler_.throw_if_failed > (); + + // 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::unique_ptr p) +{ + DOMElement* e (p.get ()); + + if (start_) + { + serializer_->startOpen (e, out_.get ()); + start_ = false; + } + else + serializer_->writeOpen (e); + + error_handler_.throw_if_failed > (); + + // 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 > (); + + // 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::unique_ptr doc (dom_impl_.createDocument ()); + + if (!element_stack_.empty ()) + { + DOMElement* e ( + static_cast ( + doc->importNode (element_stack_.front (), true))); + + for (vector::iterator i (element_stack_.begin ()); + i != element_stack_.end (); + ++i) + { + *i = e; + e = static_cast (e->getFirstChild ()); + } + } + + // Update the namespace stack to use the new document. + // + serializer_->update_namespace_stack (*doc); + + doc_ = move (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::unique_ptr e) +{ + impl_->serialize (move (e)); +} + +void serializer:: +serialize_open (xml::dom::unique_ptr e) +{ + impl_->serialize_open (move (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..585bd76 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/serializer.hxx @@ -0,0 +1,209 @@ +// file : cxx/tree/streaming/serializer.hxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#ifndef SERIALIZER_HXX +#define SERIALIZER_HXX + +#include +#include +#include // std::unique_ptr + +#include + +#include +#include // namespace_infomap + +class serializer_impl; + +class serializer +{ +public: + typedef xsd::cxx::xml::dom::namespace_infomap 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 + 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 + 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 + 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 + 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 + void + next_open (const std::string& name, const T& x); + + template + void + next_open (const std::string& name, const namespace_infomap&, const T& x); + + template + void + next_open (const std::string& ns, const std::string& name, const T& x); + + template + 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::unique_ptr); + + void + serialize_open (xsd::cxx::xml::dom::unique_ptr); + + void + serialize_close (const std::string& name); + +private: + std::unique_ptr impl_; +}; + +template +inline void serializer:: +next (const std::string& name, const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e ( + create (name, namespace_infomap ())); + *e << x; + serialize (std::move (e)); +} + +template +inline void serializer:: +next (const std::string& name, const namespace_infomap& map, const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e (create (name, map)); + *e << x; + serialize (std::move (e)); +} + +template +inline void serializer:: +next (const std::string& ns, const std::string& name, const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e ( + create (ns, name, namespace_infomap ())); + *e << x; + serialize (std::move (e)); +} + +template +inline void serializer:: +next (const std::string& ns, + const std::string& name, + const namespace_infomap& map, + const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e ( + create (ns, name, map)); + + *e << x; + serialize (std::move (e)); +} + +template +inline void serializer:: +next_open (const std::string& name, const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e ( + create (name, namespace_infomap ())); + *e << x; + serialize_open (std::move (e)); +} + +template +inline void serializer:: +next_open (const std::string& name, const namespace_infomap& map, const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e (create (name, map)); + *e << x; + serialize_open (std::move (e)); +} + +template +inline void serializer:: +next_open (const std::string& ns, const std::string& name, const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e ( + create (ns, name, namespace_infomap ())); + *e << x; + serialize_open (std::move (e)); +} + +template +inline void serializer:: +next_open (const std::string& ns, + const std::string& name, + const namespace_infomap& map, + const T& x) +{ + xsd::cxx::xml::dom::unique_ptr e ( + create (ns, name, map)); + + *e << x; + serialize_open (std::move (e)); +} + +inline void serializer:: +next_close (const std::string& name) +{ + serialize_close (name); +} + +#endif // SERIALIZER_HXX diff --git a/xsd-examples/cxx/tree/streaming/testscript b/xsd-examples/cxx/tree/streaming/testscript new file mode 100644 index 0000000..d3c744d --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/testscript @@ -0,0 +1,10 @@ +# file : cxx/tree/streaming/testscript +# license : not copyrighted - public domain + +: position +: +{ + $* $src_base/position.xml 2>| &out.xml; + echo '' >|; + cat out.xml >| +} diff --git a/xsd-examples/cxx/tree/wildcard/.gitignore b/xsd-examples/cxx/tree/wildcard/.gitignore new file mode 100644 index 0000000..234645e --- /dev/null +++ b/xsd-examples/cxx/tree/wildcard/.gitignore @@ -0,0 +1 @@ +email.?xx 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/buildfile b/xsd-examples/cxx/tree/wildcard/buildfile new file mode 100644 index 0000000..5bc63c5 --- /dev/null +++ b/xsd-examples/cxx/tree/wildcard/buildfile @@ -0,0 +1,30 @@ +# file : cxx/tree/wildcard/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}{* -email} {hxx ixx cxx}{email} $libs + +exe{driver}: xml{email}: test.input = true + +<{hxx ixx cxx}{email}>: xsd{email} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-wildcard \ + --generate-serialization \ + --root-element message \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" + +# Define XSD_CXX11 since we include libxsd headers directly. +# +cxx.poptions += -DXSD_CXX11 diff --git a/xsd-examples/cxx/tree/wildcard/driver.cxx b/xsd-examples/cxx/tree/wildcard/driver.cxx new file mode 100644 index 0000000..146a2d9 --- /dev/null +++ b/xsd-examples/cxx/tree/wildcard/driver.cxx @@ -0,0 +1,159 @@ +// file : cxx/tree/wildcard/driver.cxx +// copyright : not copyrighted - public domain + +#include +#include // std::unique_ptr +#include // std::memcpy +#include + +#include +#include + +#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 + +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::unique_ptr 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 (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..a9331e5 --- /dev/null +++ b/xsd-examples/cxx/tree/wildcard/email.xml @@ -0,0 +1,31 @@ + + + + + + + Jane Doe <jane@doe.com> + John Doe <john@doe.com> + Surfing pictures + + +Hi Jane, + +Here are cool pictures of me surfing. + +Cheers, +John + + + YmFzZTY0IGJpbmFyeQ== + YmFzZTY0IGJpbmFyeQ== + + diff --git a/xsd-examples/cxx/tree/wildcard/email.xsd b/xsd-examples/cxx/tree/wildcard/email.xsd new file mode 100644 index 0000000..c051e85 --- /dev/null +++ b/xsd-examples/cxx/tree/wildcard/email.xsd @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/xpath/.gitignore b/xsd-examples/cxx/tree/xpath/.gitignore new file mode 100644 index 0000000..83d0a51 --- /dev/null +++ b/xsd-examples/cxx/tree/xpath/.gitignore @@ -0,0 +1 @@ +people.?xx 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/buildfile b/xsd-examples/cxx/tree/xpath/buildfile new file mode 100644 index 0000000..c6f090a --- /dev/null +++ b/xsd-examples/cxx/tree/xpath/buildfile @@ -0,0 +1,28 @@ +# file : cxx/tree/xpath/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} +import libs += libxqilla%lib{xqilla} + +./: 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 \ + --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/xpath/dom-parse.cxx b/xsd-examples/cxx/tree/xpath/dom-parse.cxx new file mode 100644 index 0000000..f033de6 --- /dev/null +++ b/xsd-examples/cxx/tree/xpath/dom-parse.cxx @@ -0,0 +1,88 @@ +// file : cxx/tree/xpath/dom-parse.cxx +// copyright : not copyrighted - public domain + +#include "dom-parse.hxx" + +#include + +#include +#include + +#include +#include + +#include +#include + +using namespace xercesc; +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +xml::dom::unique_ptr +parse (std::istream& is, + const std::string& id, + bool validate, + DOMImplementation* impl) +{ + xml::dom::unique_ptr 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 eh; + xml::dom::bits::error_handler_proxy ehp (eh); + conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); + + // Prepare input stream. + // + xml::sax::std_input_source isrc (is, id); + Wrapper4InputSource wrap (&isrc, false); + + xml::dom::unique_ptr doc (parser->parse (&wrap)); + + eh.throw_if_failed > (); + + 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..61dbbfe --- /dev/null +++ b/xsd-examples/cxx/tree/xpath/dom-parse.hxx @@ -0,0 +1,25 @@ +// file : cxx/tree/xpath/dom-parse.hxx +// copyright : not copyrighted - public domain + +#ifndef DOM_PARSE +#define DOM_PARSE + +#include +#include + +#include +#include + +#include + +// 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::unique_ptr +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..246f804 --- /dev/null +++ b/xsd-examples/cxx/tree/xpath/driver.cxx @@ -0,0 +1,137 @@ +// file : cxx/tree/xpath/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include // std::move() +#include +#include +#include + +#include + +#include + +#include // 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::unique_ptr 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::unique_ptr d ( + directory_ (move (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 (d->_node ())); + DOMDocument* doc (root->getOwnerDocument ()); + + // Obtain namespace resolver. + // + xml_schema::dom::unique_ptr 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::unique_ptr expr ( + doc->createExpression ( + xml::string ("p:directory/person[age > 30]").c_str (), + resolver.get ())); + + // Execute the query. + // + xml_schema::dom::unique_ptr 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 ( + 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 (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/people.xml b/xsd-examples/cxx/tree/xpath/people.xml new file mode 100644 index 0000000..3ce6e38 --- /dev/null +++ b/xsd-examples/cxx/tree/xpath/people.xml @@ -0,0 +1,28 @@ + + + + + + + + John + Doe + male + 32 + + + + Jane + Doe + female + 28 + + + diff --git a/xsd-examples/cxx/tree/xpath/people.xsd b/xsd-examples/cxx/tree/xpath/people.xsd new file mode 100644 index 0000000..951d410 --- /dev/null +++ b/xsd-examples/cxx/tree/xpath/people.xsd @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.1