aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2014-04-10 12:57:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2014-04-10 12:57:06 +0200
commit884dea7531962b17ef843ac2175faa050e8b0758 (patch)
treed70950ab2a6f314b06f37faa67252678ce3007b1
parent0f6ff689dc6bae8fed94da0fcabd39f015e7a62b (diff)
Add support for ordered types, mixed content
-rw-r--r--NEWS10
-rw-r--r--dist/examples/cxx/tree/makefile2
-rw-r--r--dist/examples/cxx/tree/order/element/makefile31
-rw-r--r--dist/examples/cxx/tree/order/makefile11
-rw-r--r--dist/examples/cxx/tree/order/mixed/makefile32
-rw-r--r--doc/cxx/tree/guide/index.xhtml23
-rw-r--r--doc/cxx/tree/manual/index.xhtml665
-rw-r--r--doc/xsd-epilogue.15
-rw-r--r--doc/xsd-epilogue.xhtml5
-rw-r--r--examples/cxx/tree/README8
-rw-r--r--examples/cxx/tree/makefile7
-rw-r--r--examples/cxx/tree/mixed/README6
-rw-r--r--examples/cxx/tree/mixed/text.xml2
-rw-r--r--examples/cxx/tree/order/README11
-rw-r--r--examples/cxx/tree/order/element/README35
-rw-r--r--examples/cxx/tree/order/element/driver.cxx147
-rw-r--r--examples/cxx/tree/order/element/makefile100
-rw-r--r--examples/cxx/tree/order/element/transactions.xml33
-rw-r--r--examples/cxx/tree/order/element/transactions.xsd59
-rw-r--r--examples/cxx/tree/order/makefile44
-rw-r--r--examples/cxx/tree/order/mixed/README45
-rw-r--r--examples/cxx/tree/order/mixed/driver.cxx89
-rw-r--r--examples/cxx/tree/order/mixed/makefile99
-rw-r--r--examples/cxx/tree/order/mixed/text.xml18
-rw-r--r--examples/cxx/tree/order/mixed/text.xsd29
-rw-r--r--libxsd/xsd/cxx/tree/elements.hxx40
-rw-r--r--libxsd/xsd/cxx/tree/elements.ixx21
-rw-r--r--libxsd/xsd/cxx/xml/dom/parsing-source.hxx33
-rw-r--r--libxsd/xsd/cxx/xml/dom/parsing-source.txx44
-rw-r--r--tests/cxx/tree/makefile1
-rw-r--r--tests/cxx/tree/order/driver.cxx65
-rw-r--r--tests/cxx/tree/order/makefile94
-rw-r--r--tests/cxx/tree/order/output92
-rw-r--r--tests/cxx/tree/order/test.xml71
-rw-r--r--tests/cxx/tree/order/test.xsd130
-rw-r--r--tests/cxx/tree/wildcard/driver.cxx3
-rw-r--r--xsd/cxx/tree/elements.hxx71
-rw-r--r--xsd/cxx/tree/fundamental-header.hxx11
-rw-r--r--xsd/cxx/tree/generator.cxx10
-rw-r--r--xsd/cxx/tree/name-processor.cxx285
-rw-r--r--xsd/cxx/tree/options.cli60
-rw-r--r--xsd/cxx/tree/order-processor.cxx244
-rw-r--r--xsd/cxx/tree/order-processor.hxx30
-rw-r--r--xsd/cxx/tree/polymorphism-processor.cxx64
-rw-r--r--xsd/cxx/tree/serialization-source.cxx219
-rw-r--r--xsd/cxx/tree/tree-header.cxx369
-rw-r--r--xsd/cxx/tree/tree-inline.cxx74
-rw-r--r--xsd/cxx/tree/tree-source.cxx251
-rw-r--r--xsd/makefile2
-rw-r--r--xsd/options-parser.hxx3
50 files changed, 3599 insertions, 204 deletions
diff --git a/NEWS b/NEWS
index 54a956b..bb220b9 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,16 @@ Version 4.0.0
C++/Tree
+ * Support for ordered types. C++/Tree flattens nested compositors
+ which sometimes can result in loss of element ordering information
+ that could be significant to the application. Ordered types address
+ this problem. For more information, refer to Section 2.8.4, "Element
+ Order" in the C++/Tree Mapping User Manual.
+
+ * Support for mixed content in ordered types. For more information, refer
+ to Section 2.13, "Mapping for Mixed Content Models" in the C++/Tree
+ Mapping User Manual.
+
* New option, --suppress-assignment, suppress the generation of copy
assignment operators for complex types. If this option is specified,
the copy assignment operators for such types are declared private
diff --git a/dist/examples/cxx/tree/makefile b/dist/examples/cxx/tree/makefile
index 70226f9..44e7a0f 100644
--- a/dist/examples/cxx/tree/makefile
+++ b/dist/examples/cxx/tree/makefile
@@ -1,5 +1,5 @@
dirs := binary caching embedded custom hello library messaging mixed \
-multiroot performance polymorphism streaming wildcard
+multiroot order performance polymorphism streaming wildcard
ifeq ($(WITH_ZLIB),1)
dirs += compression
diff --git a/dist/examples/cxx/tree/order/element/makefile b/dist/examples/cxx/tree/order/element/makefile
new file mode 100644
index 0000000..31f5ec5
--- /dev/null
+++ b/dist/examples/cxx/tree/order/element/makefile
@@ -0,0 +1,31 @@
+root := ../../../..
+
+include $(root)/build/cxx/rules.make
+include $(root)/build/xsd/tree-rules.make
+
+
+override XSDFLAGS += --generate-serialization --generate-wildcard --ordered-type batch
+
+
+# Build.
+#
+driver: driver.o transactions.o
+
+transactions.o: transactions.cxx transactions.hxx
+driver.o: driver.cxx transactions.hxx
+
+transactions.cxx transactions.hxx: transactions.xsd
+
+
+# Test
+#
+.PHONY: test
+test: driver transactions.xml
+ ./driver transactions.xml
+
+
+# Clean.
+#
+.PHONY: clean
+clean:
+ rm -f transactions.o transactions.?xx driver.o driver
diff --git a/dist/examples/cxx/tree/order/makefile b/dist/examples/cxx/tree/order/makefile
new file mode 100644
index 0000000..2713b6e
--- /dev/null
+++ b/dist/examples/cxx/tree/order/makefile
@@ -0,0 +1,11 @@
+dirs := element mixed
+
+.PHONY: all $(dirs)
+
+all: $(dirs)
+
+$(dirs):
+ @$(MAKE) -C $@ $(MAKECMDGOALS)
+
+makefile: ;
+% :: $(dirs) ;
diff --git a/dist/examples/cxx/tree/order/mixed/makefile b/dist/examples/cxx/tree/order/mixed/makefile
new file mode 100644
index 0000000..b7929d9
--- /dev/null
+++ b/dist/examples/cxx/tree/order/mixed/makefile
@@ -0,0 +1,32 @@
+root := ../../../..
+
+include $(root)/build/cxx/rules.make
+include $(root)/build/xsd/tree-rules.make
+
+
+override XSDFLAGS += --generate-serialization --ordered-type-mixed
+
+
+# Build.
+#
+driver: driver.o text.o
+
+text.o: text.cxx text.hxx
+driver.o: driver.cxx text.hxx
+
+text.cxx text.hxx: text.xsd
+
+
+# Test
+#
+.PHONY: test
+test: driver text.xml
+ ./driver text.xml
+
+
+# Clean.
+#
+.PHONY: clean
+clean:
+ rm -f text.o text.?xx driver.o driver
+
diff --git a/doc/cxx/tree/guide/index.xhtml b/doc/cxx/tree/guide/index.xhtml
index 5c03280..49ad3a6 100644
--- a/doc/cxx/tree/guide/index.xhtml
+++ b/doc/cxx/tree/guide/index.xhtml
@@ -1558,18 +1558,31 @@ class people_t
container. The modifier functions copies the entries from
the passed sequence.</p>
+ <p>C++/Tree is a "flattening" mapping in a sense that many levels of
+ nested compositors (<code>choice</code> and <code>sequence</code>),
+ all potentially with their own cardinalities, are in the end mapped
+ to a flat set of elements with one of the three cardinality classes
+ discussed above. While this results in a simple and easy to use API
+ for most types, in certain cases, the order of elements in the actual
+ XML documents is not preserved once parsed into the object model. To
+ overcome this limitation we can mark certain schema types, for which
+ content order is not sufficiently preserved, as ordered. For more
+ information on this functionality refer to
+ <a href="http://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.8.4">Section
+ 2.8.4, "Element Order"</a> in the C++/Tree Mapping User Manual.</p>
+
<p>For complex schemas with many levels of nested compositors
- (<code>xs:choice</code> and <code>xs:sequence</code>) it can
+ (<code>choice</code> and <code>sequence</code>) it can also
be hard to deduce the cardinality class of a particular element.
The generated Doxygen documentation can greatly help with
this task. For each element and attribute the documentation
clearly identifies its cardinality class. Alternatively, you
can study the generated header files to find out the cardinality
- class of a particular attribute or element. In the next sections
- we will examine how to access and modify information stored in
- an object model using accessor and modifier functions described
- in this section.</p>
+ class of a particular attribute or element.</p>
+ <p>In the next sections we will examine how to access and modify
+ information stored in an object model using accessor and modifier
+ functions described in this section.</p>
<h2><a name="4.2">4.2 Accessing the Object Model</a></h2>
diff --git a/doc/cxx/tree/manual/index.xhtml b/doc/cxx/tree/manual/index.xhtml
index 85a5f83..052f2b3 100644
--- a/doc/cxx/tree/manual/index.xhtml
+++ b/doc/cxx/tree/manual/index.xhtml
@@ -298,6 +298,7 @@
<tr><th>2.8.1</th><td><a href="#2.8.1">Mapping for Members with the One Cardinality Class</a></td></tr>
<tr><th>2.8.2</th><td><a href="#2.8.2">Mapping for Members with the Optional Cardinality Class</a></td></tr>
<tr><th>2.8.3</th><td><a href="#2.8.3">Mapping for Members with the Sequence Cardinality Class</a></td></tr>
+ <tr><th>2.8.4</th><td><a href="#2.8.4">Element Order</a></td></tr>
</table>
</td>
</tr>
@@ -321,7 +322,8 @@
<tr><th>2.12.1</th><td><a href="#2.12.1">Mapping for <code>any</code> with the One Cardinality Class</a></td></tr>
<tr><th>2.12.2</th><td><a href="#2.12.2">Mapping for <code>any</code> with the Optional Cardinality Class</a></td></tr>
<tr><th>2.12.3</th><td><a href="#2.12.3">Mapping for <code>any</code> with the Sequence Cardinality Class</a></td></tr>
- <tr><th>2.12.4</th><td><a href="#2.12.4">Mapping for <code>anyAttribute</code></a></td></tr>
+ <tr><th>2.12.4</th><td><a href="#2.12.4">Element Wildcard Order</a></td></tr>
+ <tr><th>2.12.5</th><td><a href="#2.12.5">Mapping for <code>anyAttribute</code></a></td></tr>
</table>
</td>
</tr>
@@ -2237,7 +2239,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class color: xml_schema::string
+class color: public xml_schema::string
{
public:
enum value
@@ -2423,7 +2425,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class complex: xml_schema::type
+class complex: public xml_schema::type
{
public:
object (const int&amp; a, const xml_schema::string&amp; b);
@@ -2441,7 +2443,7 @@ public:
};
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
object (const bool&amp; s_one, const complex&amp; c_one);
@@ -2484,7 +2486,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::string
+class object: public xml_schema::string
{
public:
object (const xml_schema::language&amp; lang);
@@ -2529,7 +2531,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class color: xml_schema::string
+class color: public xml_schema::string
{
public:
enum value
@@ -2666,7 +2668,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
typedef xml_schema::string member_type;
@@ -2692,7 +2694,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
typedef xml_schema::string data_type;
@@ -2749,7 +2751,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// Type definitions.
@@ -2782,7 +2784,7 @@ public:
member's type, for example:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
...
@@ -2873,7 +2875,7 @@ f (object&amp; o)
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// Type definitions.
@@ -3102,7 +3104,7 @@ f (object&amp; o)
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// Type definitions.
@@ -3221,6 +3223,415 @@ f (object&amp; o)
}
</pre>
+ <h3><a name="2.8.4">2.8.4 Element Order</a></h3>
+
+ <p>C++/Tree is a "flattening" mapping in a sense that many levels of
+ nested compositors (<code>choice</code> and <code>sequence</code>),
+ all potentially with their own cardinalities, are in the end mapped
+ to a flat set of elements with one of the three cardinality classes
+ discussed in the previous sections. While this results in a simple
+ and easy to use API for most types, in certain cases, the order of
+ elements in the actual XML documents is not preserved once parsed
+ into the object model. And sometimes such order has
+ application-specific significance. As an example, consider a schema
+ that defines a batch of bank transactions:</p>
+
+ <pre class="xml">
+&lt;complexType name="withdraw">
+ &lt;sequence>
+ &lt;element name="account" type="unsignedInt"/>
+ &lt;element name="amount" type="unsignedInt"/>
+ &lt;/sequence>
+&lt;/complexType>
+
+&lt;complexType name="deposit">
+ &lt;sequence>
+ &lt;element name="account" type="unsignedInt"/>
+ &lt;element name="amount" type="unsignedInt"/>
+ &lt;/sequence>
+&lt;/complexType>
+
+&lt;complexType name="batch">
+ &lt;choice minOccurs="0" maxOccurs="unbounded">
+ &lt;element name="withdraw" type="withdraw"/>
+ &lt;element name="deposit" type="deposit"/>
+ &lt;/choice>
+&lt;/complexType>
+ </pre>
+
+ <p>The batch can contain any number of transactions in any order
+ but the order of transactions in each actual batch is significant.
+ For instance, consider what could happen if we reorder the
+ transactions and apply all the withdrawals before deposits.</p>
+
+ <p>For the <code>batch</code> schema type defined above the default
+ C++/Tree mapping will produce a C++ class that contains a pair of
+ sequence containers, one for each of the two elements. While this
+ will capture the content (transactions), the order of this content
+ as it appears in XML will be lost. Also, if we try to serialize the
+ batch we just loaded back to XML, all the withdrawal transactions
+ will appear before deposits.</p>
+
+ <p>To overcome this limitation of a flattening mapping, C++/Tree
+ allows us to mark certain XML Schema types, for which content
+ order is important, as ordered.</p>
+
+ <p>There are several command line options that control which
+ schema types are treated as ordered. To make an individual
+ type ordered, we use the <code>--ordered-type</code> option,
+ for example:</p>
+
+ <pre class="term">
+--ordered-type batch
+ </pre>
+
+ <p>To automatically treat all the types that are derived from an ordered
+ type also ordered, we use the <code>--ordered-type-derived</code>
+ option. This is primarily useful if you would like to iterate
+ over the complete hierarchy's content using the content order
+ sequence (discussed below).</p>
+
+ <p>Ordered types are also useful for handling mixed content. To
+ automatically mark all the types with mixed content as ordered
+ we use the <code>--ordered-type-mixed</code> option. For more
+ information on handling mixed content see <a href="#2.13">Section
+ 2.13, "Mapping for Mixed Content Models"</a>.</p>
+
+ <p>Finally, we can mark all the types in the schema we are
+ compiling with the <code>--ordered-type-all</code> option.
+ You should only resort to this option if all the types in
+ your schema truly suffer from the loss of content
+ order since, as we will discuss shortly, ordered types
+ require extra effort to access and, especially, modify.
+ See the
+ <a href="http://www.codesynthesis.com/projects/xsd/documentation/xsd.xhtml">XSD
+ Compiler Command Line Manual</a> for more information on
+ these options.</p>
+
+ <p>Once a type is marked ordered, C++/Tree alters its mapping
+ in several ways. Firstly, for each local element, element
+ wildcard (<a href="#2.12.4">Section 2.12.4, "Element Wildcard
+ Order"</a>), and mixed content text (<a href="#2.13">Section
+ 2.13, "Mapping for Mixed Content Models"</a>) in this type, a
+ content id constant is generated. Secondly, an addition sequence
+ is added to the class that captures the content order. Here
+ is how the mapping of our <code>batch</code> class changes
+ once we make it ordered:</p>
+
+ <pre class="c++">
+class batch: public xml_schema::type
+{
+public:
+ // withdraw
+ //
+ typedef withdraw withdraw_type;
+ typedef sequence&lt;withdraw_type> withdraw_sequence;
+ typedef withdraw_sequence::iterator withdraw_iterator;
+ typedef withdraw_sequence::const_iterator withdraw_const_iterator;
+
+ static const std::size_t withdraw_id = 1;
+
+ const withdraw_sequence&amp;
+ withdraw () const;
+
+ withdraw_sequence&amp;
+ withdraw ();
+
+ void
+ withdraw (const withdraw_sequence&amp;);
+
+ // deposit
+ //
+ typedef deposit deposit_type;
+ typedef sequence&lt;deposit_type> deposit_sequence;
+ typedef deposit_sequence::iterator deposit_iterator;
+ typedef deposit_sequence::const_iterator deposit_const_iterator;
+
+ static const std::size_t deposit_id = 2;
+
+ const deposit_sequence&amp;
+ deposit () const;
+
+ deposit_sequence&amp;
+ deposit ();
+
+ void
+ deposit (const deposit_sequence&amp;);
+
+ // content_order
+ //
+ typedef xml_schema::content_order content_order_type;
+ typedef std::vector&lt;content_order_type> content_order_sequence;
+ typedef content_order_sequence::iterator content_order_iterator;
+ typedef content_order_sequence::const_iterator content_order_const_iterator;
+
+ const content_order_sequence&amp;
+ content_order () const;
+
+ content_order_sequence&amp;
+ content_order ();
+
+ void
+ content_order (const content_order_sequence&amp;);
+
+ ...
+};
+ </pre>
+
+ <p>Notice the <code>withdraw_id</code> and <code>deposit_id</code>
+ content ids as well as the extra <code>content_order</code>
+ sequence that does not correspond to any element in the
+ schema definition. The other changes to the mapping for ordered
+ types has to do with XML parsing and serialization code. During
+ parsing the content order is captured in the <code>content_order</code>
+ sequence while during serialization this sequence is used to
+ determine the order in which content is serialized. The
+ <code>content_order</code> sequence is also copied during
+ copy construction and assigned during copy assignment. It is also
+ taken into account during comparison.</p>
+
+ <p>The entry type of the <code>content_order</code> sequence is the
+ <code>xml_schema::content_order</code> type that has the following
+ interface:</p>
+
+ <pre class="c++">
+namespace xml_schema
+{
+ struct content_order
+ {
+ content_order (std::size_t id, std::size_t index = 0);
+
+ std::size_t id;
+ std::size_t index;
+ };
+
+ bool
+ operator== (const content_order&amp;, const content_order&amp;);
+
+ bool
+ operator!= (const content_order&amp;, const content_order&amp;);
+
+ bool
+ operator&lt; (const content_order&amp;, const content_order&amp;);
+}
+ </pre>
+
+ <p>The <code>content_order</code> sequence describes the order of
+ content (elements, including wildcards, as well as mixed content
+ text). Each entry in this sequence consists of the content id
+ (for example, <code>withdraw_id</code> or <code>deposit_id</code>
+ in our case) as well as, for elements of the sequence cardinality
+ class, an index into the corresponding sequence container (the
+ index is unused for the one and optional cardinality classes).
+ For example, in our case, if the content id is <code>withdraw_id</code>,
+ then the index will point into the <code>withdraw</code> element
+ sequence.</p>
+
+ <p>With all this information we can now examine how to iterate over
+ transaction in the batch in content order:</p>
+
+ <pre class="c++">
+batch&amp; b = ...
+
+for (batch::content_order_const_iterator i (b.content_order ().begin ());
+ i != b.content_order ().end ();
+ ++i)
+{
+ switch (i->id)
+ {
+ case batch::withdraw_id:
+ {
+ const withdraw&amp; t (b.withdraw ()[i->index]);
+ cerr &lt;&lt; t.account () &lt;&lt; " withdraw " &lt;&lt; t.amount () &lt;&lt; endl;
+ break;
+ }
+ case batch::deposit_id:
+ {
+ const deposit&amp; t (b.deposit ()[i->index]);
+ cerr &lt;&lt; t.account () &lt;&lt; " deposit " &lt;&lt; t.amount () &lt;&lt; endl;
+ break;
+ }
+ default:
+ {
+ assert (false); // Unknown content id.
+ }
+ }
+}
+ </pre>
+
+ <p>If we serialized our batch back to XML, we would also see that the
+ order of transactions in the output is exactly the same as in the
+ input rather than all the withdrawals first followed by all the
+ deposits.</p>
+
+ <p>The most complex aspect of working with ordered types is
+ modifications. Now we not only need to change the content,
+ but also remember to update the order information corresponding
+ to this change. As a first example, we add a deposit transaction
+ to the batch:</p>
+
+ <pre class="c++">
+using xml_schema::content_order;
+
+batch::deposit_sequence&amp; d (b.deposit ());
+batch::withdraw_sequence&amp; w (b.withdraw ());
+batch::content_order_sequence&amp; co (b.content_order ());
+
+d.push_back (deposit (123456789, 100000));
+co.push_back (content_order (batch::deposit_id, d.size () - 1));
+ </pre>
+
+ <p>In the above example we first added the content (deposit
+ transaction) and then updated the content order information
+ by adding an entry with <code>deposit_id</code> content
+ id and the index of the just added deposit transaction.</p>
+
+ <p>Removing the last transaction can be easy if we know which
+ transaction (deposit or withdrawal) is last:</p>
+
+ <pre class="c++">
+d.pop_back ();
+co.pop_back ();
+ </pre>
+
+ <p>If, however, we do not know which transaction is last, then
+ things get a bit more complicated:</p>
+
+ <pre class="c++">
+switch (co.back ().id)
+{
+case batch::withdraw_id:
+ {
+ d.pop_back ();
+ break;
+ }
+case batch::deposit_id:
+ {
+ w.pop_back ();
+ break;
+ }
+}
+
+co.pop_back ();
+ </pre>
+
+ <p>The following example shows how to add a transaction at the
+ beginning of the batch:</p>
+
+ <pre class="c++">
+w.push_back (withdraw (123456789, 100000));
+co.insert (co.begin (),
+ content_order (batch::withdraw_id, w.size () - 1));
+ </pre>
+
+ <p>Note also that when we merely modify the content of one
+ of the elements in place, we do not need to update its
+ order since it doesn't change. For example, here is how
+ we can change the amount in the first withdrawal:</p>
+
+ <pre class="c++">
+w[0].amount (10000);
+ </pre>
+
+ <p>For the complete working code shown in this section refer to the
+ <code>order/element</code> example in the
+ <code>examples/cxx/tree/</code> directory in the XSD distribution.</p>
+
+ <p>If both the base and derived types are ordered, then the
+ content order sequence is only added to the base and the content
+ ids are unique within the whole hierarchy. In this case
+ the content order sequence for the derived type contains
+ ordering information for both base and derived content.</p>
+
+ <p>In some applications we may need to perform more complex
+ content processing. For example, in our case, we may need
+ to remove all the withdrawal transactions. The default
+ container, <code>std::vector</code>, is not particularly
+ suitable for such operations. What may be required by
+ some applications is a multi-index container that not
+ only allows us to iterate in content order similar to
+ <code>std::vector</code> but also search by the content
+ id as well as the content id and index pair.</p>
+
+ <p>While C++/Tree does not provide this functionality by
+ default, it allows us to specify a custom container
+ type for content order with the <code>--order-container</code>
+ command line option. The only requirement from the
+ generated code side for such a container is to provide
+ the <code>vector</code>-like <code>push_back()</code>,
+ <code>size()</code>, and const iteration interfaces.</p>
+
+ <p>As an example, here is how we can use the Boost Multi-Index
+ container for content order. First we create the
+ <code>content-order-container.hxx</code> header with the
+ following definition (in C++11, use the alias template
+ instead):</p>
+
+ <pre class="c++">
+#ifndef CONTENT_ORDER_CONTAINER
+#define CONTENT_ORDER_CONTAINER
+
+#include &lt;cstddef> // std::size_t
+
+#include &lt;boost/multi_index_container.hpp>
+#include &lt;boost/multi_index/member.hpp>
+#include &lt;boost/multi_index/identity.hpp>
+#include &lt;boost/multi_index/ordered_index.hpp>
+#include &lt;boost/multi_index/random_access_index.hpp>
+
+struct by_id {};
+struct by_id_index {};
+
+template &lt;typename T>
+struct content_order_container:
+ boost::multi_index::multi_index_container&lt;
+ T,
+ boost::multi_index::indexed_by&lt;
+ boost::multi_index::random_access&lt;>,
+ boost::multi_index::ordered_unique&lt;
+ boost::multi_index::tag&lt;by_id_index>,
+ boost::multi_index::identity&lt;T>
+ >,
+ boost::multi_index::ordered_non_unique&lt;
+ boost::multi_index::tag&lt;by_id>,
+ boost::multi_index::member&lt;T, std::size_t, &amp;T::id>
+ >
+ >
+ >
+{};
+
+#endif
+ </pre>
+
+ <p>Next we add the following two XSD compiler options to include
+ this header into every generated header file and to use the
+ custom container type (see the XSD compiler command line manual
+ for more information on shell quoting for the first option):</p>
+
+ <pre class="term">
+--hxx-prologue '#include "content-order-container.hxx"'
+--order-container content_order_container
+ </pre>
+
+ <p>With these changes we can now use the multi-index functionality,
+ for example, to search for a specific content id:</p>
+
+ <pre class="c++">
+typedef batch::content_order_sequence::index&lt;by_id>::type id_set;
+typedef id_set::iterator id_iterator;
+
+const id_set&amp; ids (b.content_order ().get&lt;by_id> ());
+
+std::pair&lt;id_iterator, id_iterator> r (
+ ids.equal_range (std::size_t (batch::deposit_id));
+
+for (id_iterator i (r.first); i != r.second; ++i)
+{
+ const deposit&amp; t (b.deposit ()[i->index]);
+ cerr &lt;&lt; t.account () &lt;&lt; " deposit " &lt;&lt; t.amount () &lt;&lt; endl;
+}
+ </pre>
+
<h2><a name="2.9">2.9 Mapping for Global Elements</a></h2>
<p>An XML Schema element definition is called global if it appears
@@ -3729,7 +4140,7 @@ f (root&amp; r)
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// any
@@ -3807,7 +4218,7 @@ public:
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// Accessors.
@@ -3888,7 +4299,7 @@ f (object&amp; o, const xercesc::DOMElement&amp; e)
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// Type definitions.
@@ -4071,7 +4482,7 @@ f (object&amp; o, const xercesc::DOMElement&amp; e)
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// Type definitions.
@@ -4314,8 +4725,84 @@ f (object&amp; o, const xercesc::DOMElement&amp; e)
}
</pre>
+ <h3><a name="2.12.4">2.12.4 Element Wildcard Order</a></h3>
+
+ <p>Similar to elements, element wildcards in ordered types
+ (<a href="#2.8.4">Section 2.8.4, "Element Order"</a>) are assigned
+ content ids and are included in the content order sequence.
+ Continuing with the bank transactions example started in Section
+ 2.8.4, we can extend the batch by allowing custom transactions:</p>
+
+ <pre class="xml">
+&lt;complexType name="batch">
+ &lt;choice minOccurs="0" maxOccurs="unbounded">
+ &lt;element name="withdraw" type="withdraw"/>
+ &lt;element name="deposit" type="deposit"/>
+ &lt;any namespace="##other" processContents="lax"/>
+ &lt;/choice>
+&lt;/complexType>
+ </pre>
+
+ <p>This will lead to the following changes in the generated
+ <code>batch</code> C++ class:</p>
+
+ <pre class="c++">
+class batch: public xml_schema::type
+{
+public:
+ ...
+
+ // any
+ //
+ typedef element_sequence any_sequence;
+ typedef any_sequence::iterator any_iterator;
+ typedef any_sequence::const_iterator any_const_iterator;
+
+ static const std::size_t any_id = 3UL;
+
+ const any_sequence&amp;
+ any () const;
+
+ any_sequence&amp;
+ any ();
+
+ void
+ any (const any_sequence&amp;);
+
+ ...
+};
+ </pre>
+
+ <p>With this change we also need to update the iteration code to handle
+ the new content id:</p>
+
+ <pre class="c++">
+for (batch::content_order_const_iterator i (b.content_order ().begin ());
+ i != b.content_order ().end ();
+ ++i)
+{
+ switch (i->id)
+ {
+ ...
+
+ case batch::any_id:
+ {
+ const DOMElement&amp; e (b.any ()[i->index]);
+ ...
+ break;
+ }
+
+ ...
+ }
+}
+ </pre>
+
+ <p>For the complete working code that shows the use of wildcards in
+ ordered types refer to the <code>order/element</code> example in
+ the <code>examples/cxx/tree/</code> directory in the XSD
+ distribution.</p>
- <h3><a name="2.12.4">2.12.4 Mapping for <code>anyAttribute</code></a></h3>
+ <h3><a name="2.12.5">2.12.5 Mapping for <code>anyAttribute</code></a></h3>
<p>For <code>anyAttribute</code> the type definitions consist of an alias
of the container type with name <code>any_attribute_set</code>
@@ -4353,7 +4840,7 @@ f (object&amp; o, const xercesc::DOMElement&amp; e)
<p>is mapped to:</p>
<pre class="c++">
-class object: xml_schema::type
+class object: public xml_schema::type
{
public:
// Type definitions.
@@ -4594,14 +5081,138 @@ f (object&amp; o, const xercesc::DOMAttr&amp; a)
<h2><a name="2.13">2.13 Mapping for Mixed Content Models</a></h2>
- <p>XML Schema mixed content models do not have a direct C++ mapping.
- Instead, information in XML instance documents, corresponding to
- a mixed content model, can be accessed using generic DOM nodes that
- can optionally be associated with object model nodes. See
- <a href="#5.1">Section 5.1, "DOM Association"</a> for more
- information about keeping association with DOM nodes.
- </p>
+ <p>For XML Schema types with mixed content models C++/Tree provides
+ mapping support only if the type is marked as ordered
+ (<a href="#2.8.4">Section 2.8.4, "Element Order"</a>). Use the
+ <code>--ordered-type-mixed</code> XSD compiler option to
+ automatically mark all types with mixed content as ordered.</p>
+
+ <p>For an ordered type with mixed content, C++/Tree adds an extra
+ text content sequence that is used to store the text fragments.
+ This text content sequence is also assigned the content id and
+ its entries are included in the content order sequence, just
+ like elements. As a result, it is possible to capture the order
+ between elements and text fragments.</p>
+
+ <p>As an example, consider the following schema that describes text
+ with embedded links:</p>
+
+ <pre class="xml">
+&lt;complexType name="anchor">
+ &lt;simpleContent>
+ &lt;extension base="string">
+ &lt;attribute name="href" type="anyURI" use="required"/>
+ &lt;/extension>
+ &lt;/simpleContent>
+&lt;/complexType>
+
+&lt;complexType name="text" mixed="true">
+ &lt;sequence>
+ &lt;element name="a" type="anchor" minOccurs="0" maxOccurs="unbounded"/>
+ &lt;/sequence>
+&lt;/complexType>
+ </pre>
+
+ <p>The generated <code>text</code> C++ class will provide the following
+ API (assuming it is marked as ordered):</p>
+
+ <pre class="c++">
+class text: public xml_schema::type
+{
+public:
+ // a
+ //
+ typedef anchor a_type;
+ typedef sequence&lt;a_type> a_sequence;
+ typedef a_sequence::iterator a_iterator;
+ typedef a_sequence::const_iterator a_const_iterator;
+
+ static const std::size_t a_id = 1UL;
+
+ const a_sequence&amp;
+ a () const;
+
+ a_sequence&amp;
+ a ();
+
+ void
+ a (const a_sequence&amp;);
+
+ // text_content
+ //
+ typedef xml_schema::string text_content_type;
+ typedef sequence&lt;text_content_type> text_content_sequence;
+ typedef text_content_sequence::iterator text_content_iterator;
+ typedef text_content_sequence::const_iterator text_content_const_iterator;
+
+ static const std::size_t text_content_id = 2UL;
+
+ const text_content_sequence&amp;
+ text_content () const;
+
+ text_content_sequence&amp;
+ text_content ();
+
+ void
+ text_content (const text_content_sequence&amp;);
+
+ // content_order
+ //
+ typedef xml_schema::content_order content_order_type;
+ typedef std::vector&lt;content_order_type> content_order_sequence;
+ typedef content_order_sequence::iterator content_order_iterator;
+ typedef content_order_sequence::const_iterator content_order_const_iterator;
+
+ const content_order_sequence&amp;
+ content_order () const;
+
+ content_order_sequence&amp;
+ content_order ();
+
+ void
+ content_order (const content_order_sequence&amp;);
+
+ ...
+};
+ </pre>
+
+ <p>Given this interface we can iterate over both link elements
+ and text in content order. The following code fragment converts
+ our format to plain text with references.</p>
+
+ <pre class="c++">
+const text&amp; t = ...
+
+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&amp; a (t.a ()[i->index]);
+ cerr &lt;&lt; a &lt;&lt; "[" &lt;&lt; a.href () &lt;&lt; "]";
+ break;
+ }
+ case text::text_content_id:
+ {
+ const xml_schema::string&amp; s (t.text_content ()[i->index]);
+ cerr &lt;&lt; s;
+ break;
+ }
+ default:
+ {
+ assert (false); // Unknown content id.
+ }
+ }
+}
+ </pre>
+ <p>For the complete working code that shows the use of mixed content
+ in ordered types refer to the <code>order/mixed</code> example in
+ the <code>examples/cxx/tree/</code> directory in the XSD
+ distribution.</p>
<!-- Parsing -->
@@ -5835,7 +6446,7 @@ XMLPlatformUtils::Terminate ();
<p>Maintaining DOM association is normally useful when the application
needs access to XML constructs that are not preserved in the
- object model, for example, text in the mixed content model.
+ object model, for example, XML comments.
Another useful aspect of DOM association is the ability of the
application to navigate the document tree using the generic DOM
interface (for example, with the help of an XPath processor)
@@ -5845,7 +6456,7 @@ XMLPlatformUtils::Terminate ();
be ignored during serialization. If you need to not only access
but also modify some aspects of XML that are not preserved in
the object model, then type customization with custom parsing
- constructs and serialization operators should be used instead.</p>
+ constructors and serialization operators should be used instead.</p>
<p>To request DOM association you will need to pass the
<code>xml_schema::flags::keep_dom</code> flag to one of the
diff --git a/doc/xsd-epilogue.1 b/doc/xsd-epilogue.1
index c5a2760..2b78ff7 100644
--- a/doc/xsd-epilogue.1
+++ b/doc/xsd-epilogue.1
@@ -21,6 +21,7 @@ options. A custom naming convention can be achieved using the
.BR --seq-modifier-regex ,
.BR --parser-regex ,
.BR --serializer-regex ,
+.BR --const-regex ,
.BR --enumerator-regex ,
and
.B --element-type-regex
@@ -96,6 +97,7 @@ The
.BR --seq-modifier-regex ,
.BR --parser-regex ,
.BR --serializer-regex ,
+.BR --const-regex ,
.BR --enumerator-regex ,
and
.B --element-type-regex
@@ -234,6 +236,9 @@ naming convention is selected:
.B /(.+)/parse\\\\u$1/
+The const category is used to create C++ constant names for the
+element/wildcard/text content ids in ordered types.
+
See also the REGEX AND SHELL QUOTING section below.
\"
diff --git a/doc/xsd-epilogue.xhtml b/doc/xsd-epilogue.xhtml
index 275224f..5f91450 100644
--- a/doc/xsd-epilogue.xhtml
+++ b/doc/xsd-epilogue.xhtml
@@ -16,6 +16,7 @@
<code><b>--seq-modifier-regex</b></code>,
<code><b>--parser-regex</b></code>,
<code><b>--serializer-regex</b></code>,
+ <code><b>--const-regex</b></code>,
<code><b>--enumerator-regex</b></code>, and
<code><b>--element-type-regex</b></code> options.
</p>
@@ -78,6 +79,7 @@
<code><b>--seq-modifier-regex</b></code>,
<code><b>--parser-regex</b></code>,
<code><b>--serializer-regex</b></code>,
+ <code><b>--const-regex</b></code>,
<code><b>--enumerator-regex</b></code>, and
<code><b>--element-type-regex</b></code> options allow you to
specify extra regular expressions for each name category in
@@ -184,6 +186,9 @@
<p><code><b>/(.+)/parse\u$1/</b></code></p>
+ <p>The const category is used to create C++ constant names for the
+ element/wildcard/text content ids in ordered types.</p>
+
<p>See also the REGEX AND SHELL QUOTING section below.</p>
<h1>TYPE MAP</h1>
diff --git a/examples/cxx/tree/README b/examples/cxx/tree/README
index ee91b43..569bf11 100644
--- a/examples/cxx/tree/README
+++ b/examples/cxx/tree/README
@@ -17,6 +17,10 @@ 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.
@@ -45,7 +49,7 @@ caching
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
+ into an application and then use it with the C++/Tree mapping to
parse and validate XML documents.
performance
@@ -68,7 +72,7 @@ streaming
that are too large to fit into memory.
compression
- Shows how to compress an XML document during serialization and decompress
+ Shows how to compress an XML document during serialization and decompress
it during parsing using the zlib library.
binary/
diff --git a/examples/cxx/tree/makefile b/examples/cxx/tree/makefile
index 728860b..688dfd5 100644
--- a/examples/cxx/tree/makefile
+++ b/examples/cxx/tree/makefile
@@ -5,12 +5,11 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
all_examples := binary caching embedded custom hello library messaging \
-mixed multiroot performance polymorphism streaming wildcard compression \
-xpath
-
+mixed multiroot order performance polymorphism streaming wildcard \
+compression xpath
build_examples := binary caching embedded custom hello library messaging \
-mixed multiroot performance polymorphism streaming wildcard
+mixed multiroot order performance polymorphism streaming wildcard
ifeq ($(xsd_with_zlib),y)
build_examples += compression
diff --git a/examples/cxx/tree/mixed/README b/examples/cxx/tree/mixed/README
index 9ab3309..fc23faa 100644
--- a/examples/cxx/tree/mixed/README
+++ b/examples/cxx/tree/mixed/README
@@ -1,8 +1,12 @@
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
+examples in the custom/ directory, in particular, custom/mixed and
custom/wildcard.
In this example we use mixed content model to describe text with
diff --git a/examples/cxx/tree/mixed/text.xml b/examples/cxx/tree/mixed/text.xml
index 69abe8f..9d70397 100644
--- a/examples/cxx/tree/mixed/text.xml
+++ b/examples/cxx/tree/mixed/text.xml
@@ -2,7 +2,7 @@
<!--
-file : examples/cxx/tree/text/text.xml
+file : examples/cxx/tree/mixed/text.xml
author : Boris Kolpackov <boris@codesynthesis.com>
copyright : not copyrighted - public domain
diff --git a/examples/cxx/tree/order/README b/examples/cxx/tree/order/README
new file mode 100644
index 0000000..7125a2d
--- /dev/null
+++ b/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/examples/cxx/tree/order/element/README b/examples/cxx/tree/order/element/README
new file mode 100644
index 0000000..19f2381
--- /dev/null
+++ b/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/examples/cxx/tree/order/element/driver.cxx b/examples/cxx/tree/order/element/driver.cxx
new file mode 100644
index 0000000..0ea6d6f
--- /dev/null
+++ b/examples/cxx/tree/order/element/driver.cxx
@@ -0,0 +1,147 @@
+// file : examples/cxx/tree/order/element/driver.cxx
+// copyright : not copyrighted - public domain
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <xercesc/dom/DOM.hpp>
+#include <xercesc/util/PlatformUtils.hpp>
+
+#include "transactions.hxx"
+
+// The following string class keeps us sane when working with Xerces.
+// Include it after the generated header in order to get only char or
+// wchar_t version depending on how you compiled your schemas.
+//
+#include <xsd/cxx/xml/string.hxx>
+
+using std::cerr;
+using std::endl;
+
+int
+main (int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " transactions.xml" << endl;
+ return 1;
+ }
+
+ using namespace xercesc;
+
+ int r (0);
+
+ // The Xerces-C++ DOM objects that will be used to store the
+ // content matched by the wildcard "out-lives" the call to the
+ // parsing function. Therefore we need to initialize the
+ // Xerces-C++ runtime ourselves.
+ //
+ XMLPlatformUtils::Initialize ();
+
+ try
+ {
+ using namespace transactions;
+
+ // Parse the batch.
+ //
+ std::auto_ptr<batch> b (
+ batch_ (argv[1], xml_schema::flags::dont_initialize));
+
+ // Print what we've got in content order.
+ //
+ for (batch::content_order_const_iterator i (b->content_order ().begin ());
+ i != b->content_order ().end ();
+ ++i)
+ {
+ switch (i->id)
+ {
+ case batch::balance_id:
+ {
+ const balance& t (b->balance ()[i->index]);
+ cerr << t.account () << " balance" << endl;
+ break;
+ }
+ case batch::withdraw_id:
+ {
+ const withdraw& t (b->withdraw ()[i->index]);
+ cerr << t.account () << " withdraw " << t.amount () << endl;
+ break;
+ }
+ case batch::deposit_id:
+ {
+ const deposit& t (b->deposit ()[i->index]);
+ cerr << t.account () << " deposit " << t.amount () << endl;
+ break;
+ }
+ case batch::any_id:
+ {
+ namespace xml = xsd::cxx::xml;
+
+ const DOMElement& e (b->any ()[i->index]);
+ cerr << xml::transcode<char> (e.getLocalName ()) << endl;
+ break;
+ }
+ default:
+ {
+ assert (false); // Unknown content id.
+ }
+ }
+ }
+
+ cerr << endl;
+
+ // Modify the transaction batch. First remove the last transaction.
+ // Note that we have to update both the content itself and content
+ // order sequences.
+ //
+ batch::content_order_sequence& co (b->content_order ());
+
+ co.pop_back ();
+ b->withdraw ().pop_back ();
+
+ // Now add a few more transactions. Again we have to add both the
+ // content and its ordering. The order information consists of the
+ // content id and, in case of a sequence, the index.
+ //
+ b->deposit ().push_back (deposit (123456789, 100000));
+ co.push_back (
+ batch::content_order_type (
+ batch::deposit_id, b->deposit ().size () - 1));
+
+ // The next transaction we add at the beginning of the batch.
+ //
+ b->balance ().push_back (balance (123456789));
+ co.insert (co.begin (),
+ batch::content_order_type (
+ batch::balance_id, b->balance ().size () - 1));
+
+ // Note also that when we merely modify the content of one
+ // of the elements in place, we don't need to update its
+ // order. For example:
+ //
+ b->deposit ()[0].amount (2000000);
+
+ // Serialize the modified transaction batch back to XML.
+ //
+ xml_schema::namespace_infomap map;
+
+ map[""].name = "http://www.codesynthesis.com/transactions";
+ map[""].schema = "transactions.xsd";
+ map["te"].name = "http://www.codesynthesis.com/transactions-extras";
+
+ batch_ (std::cout,
+ *b,
+ map,
+ "UTF-8",
+ xml_schema::flags::dont_initialize);
+ }
+ catch (const xml_schema::exception& e)
+ {
+ cerr << e << endl;
+ r = 1;
+ }
+
+ XMLPlatformUtils::Terminate ();
+ return r;
+}
diff --git a/examples/cxx/tree/order/element/makefile b/examples/cxx/tree/order/element/makefile
new file mode 100644
index 0000000..49478fc
--- /dev/null
+++ b/examples/cxx/tree/order/element/makefile
@@ -0,0 +1,100 @@
+# file : examples/cxx/tree/order/element/makefile
+# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make
+
+xsd := transactions.xsd
+cxx := driver.cxx
+
+obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o))
+dep := $(obj:.o=.o.d)
+
+driver := $(out_base)/driver
+install := $(out_base)/.install
+dist := $(out_base)/.dist
+dist-win := $(out_base)/.dist-win
+clean := $(out_base)/.clean
+
+# Import.
+#
+$(call import,\
+ $(scf_root)/import/libxerces-c/stub.make,\
+ l: xerces_c.l,cpp-options: xerces_c.l.cpp-options)
+
+# Build.
+#
+$(driver): $(obj) $(xerces_c.l) -lnsl
+
+$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd
+$(obj) $(dep): $(xerces_c.l.cpp-options)
+
+genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx)
+gen := $(addprefix $(out_base)/,$(genf))
+
+$(gen): xsd := $(out_root)/xsd/xsd
+$(gen): xsd_options += --generate-serialization --generate-wildcard \
+--ordered-type batch
+$(gen): $(out_root)/xsd/xsd
+
+$(call include-dep,$(dep),$(obj),$(gen))
+
+# Convenience alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Install & Dist.
+#
+dist-common := $(out_base)/.dist-common
+
+$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base))
+
+$(install):
+ $(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README)
+ $(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx)
+ $(call install-data,$(src_base)/transactions.xsd,$(install_doc_dir)/xsd/$(path)/transactions.xsd)
+ $(call install-data,$(src_base)/transactions.xml,$(install_doc_dir)/xsd/$(path)/transactions.xml)
+
+$(dist-common):
+ $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx)
+ $(call install-data,$(src_base)/transactions.xsd,$(dist_prefix)/$(path)/transactions.xsd)
+ $(call install-data,$(src_base)/transactions.xml,$(dist_prefix)/$(path)/transactions.xml)
+
+$(dist): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README)
+
+$(dist-win): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+# Clean.
+#
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean))
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(gen): | $(out_base)/.gitignore
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver $(genf)
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+$(call include,$(bld_root)/install.make)
+$(call include,$(scf_root)/xsd/tree/xsd-cxx.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsd/makefile)
diff --git a/examples/cxx/tree/order/element/transactions.xml b/examples/cxx/tree/order/element/transactions.xml
new file mode 100644
index 0000000..5435980
--- /dev/null
+++ b/examples/cxx/tree/order/element/transactions.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/tree/order/element/transactions.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<batch xmlns="http://www.codesynthesis.com/transactions"
+ xmlns:te="http://www.codesynthesis.com/transactions-extras"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.codesynthesis.com/transactions transactions.xsd">
+ <deposit>
+ <account>123456789</account>
+ <amount>1000000</amount>
+ </deposit>
+
+ <balance>
+ <account>123456789</account>
+ </balance>
+
+ <te:block>
+ <account>123456789</account>
+ <amount>500000</amount>
+ </te:block>
+
+ <withdraw>
+ <account>123456789</account>
+ <amount>500000</amount>
+ </withdraw>
+</batch>
diff --git a/examples/cxx/tree/order/element/transactions.xsd b/examples/cxx/tree/order/element/transactions.xsd
new file mode 100644
index 0000000..54e9cc2
--- /dev/null
+++ b/examples/cxx/tree/order/element/transactions.xsd
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/tree/order/element/transactions.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://www.codesynthesis.com/transactions"
+ targetNamespace="http://www.codesynthesis.com/transactions"
+ elementFormDefault="qualified">
+
+ <xsd:complexType name="transaction">
+ <xsd:sequence>
+ <xsd:element name="account" type="xsd:unsignedInt"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="balance">
+ <xsd:complexContent>
+ <xsd:extension base="t:transaction"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="withdraw">
+ <xsd:complexContent>
+ <xsd:extension base="t:transaction">
+ <xsd:sequence>
+ <xsd:element name="amount" type="xsd:unsignedInt"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="deposit">
+ <xsd:complexContent>
+ <xsd:extension base="t:transaction">
+ <xsd:sequence>
+ <xsd:element name="amount" type="xsd:unsignedInt"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="batch">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="balance" type="t:balance"/>
+ <xsd:element name="withdraw" type="t:withdraw"/>
+ <xsd:element name="deposit" type="t:deposit"/>
+ <xsd:any namespace="##other" processContents="lax"/>
+ </xsd:choice>
+ </xsd:complexType>
+
+ <xsd:element name="batch" type="t:batch"/>
+
+</xsd:schema>
diff --git a/examples/cxx/tree/order/makefile b/examples/cxx/tree/order/makefile
new file mode 100644
index 0000000..63f1f3a
--- /dev/null
+++ b/examples/cxx/tree/order/makefile
@@ -0,0 +1,44 @@
+# file : examples/cxx/tree/order/makefile
+# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+all_examples := element mixed
+build_examples := element mixed
+
+default := $(out_base)/
+install := $(out_base)/.install
+dist := $(out_base)/.dist
+dist-win := $(out_base)/.dist-win
+clean := $(out_base)/.clean
+
+# Build.
+#
+$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples)))
+
+# Install & Dist.
+#
+$(install) $(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base))
+
+$(install): $(addprefix $(out_base)/,$(addsuffix /.install,$(all_examples)))
+ $(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README)
+
+$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples)))
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README)
+
+$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples)))
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+# Clean.
+#
+$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples)))
+
+$(call include,$(bld_root)/install.make)
+
+ifneq ($(filter $(MAKECMDGOALS),dist dist-win install),)
+$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile))
+else
+$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile))
+endif
diff --git a/examples/cxx/tree/order/mixed/README b/examples/cxx/tree/order/mixed/README
new file mode 100644
index 0000000..e66c1ad
--- /dev/null
+++ b/examples/cxx/tree/order/mixed/README
@@ -0,0 +1,45 @@
+This example shows how to use ordered types to capture mixed content
+text and to maintain order information between elements and text.
+
+In this example we use mixed content model to describe text with
+embedded links in the form:
+
+ This paragraph talks about <a href="uri">time</a>.
+
+The example transforms such text into plain text with references in
+the form:
+
+ This paragraph talks about time[uri].
+
+It also saves the modified text back to XML in order to verify the
+element and text order.
+
+The example consists of the following files:
+
+text.xsd
+ XML Schema which describes "text with links" instance documents.
+
+text.xml
+ Sample XML instance document.
+
+text.hxx
+text.cxx
+ C++ types that represent the given vocabulary as well as a set of
+ parsing and serialization functions. These are generated by XSD
+ from text.xsd. Note that the --ordered-type-mixed option is used
+ to indicate to the XSD compiler that all types with mixed content
+ should be automatically treated as ordered.
+
+driver.cxx
+ Driver for the example. It first calls one of the parsing functions
+ that constructs the object model from the input XML file. It then
+ iterates over the text and elements in the content order to convert
+ the document to its plain text representation. The driver then adds
+ another paragraph of text and a link to the object model while showing
+ how to maintain the content order. Finally, it saves the modified
+ text back to XML to verify that the content order is preserved in
+ the output document.
+
+To run the example on the sample XML instance document simply execute:
+
+$ ./driver text.xml
diff --git a/examples/cxx/tree/order/mixed/driver.cxx b/examples/cxx/tree/order/mixed/driver.cxx
new file mode 100644
index 0000000..9606b67
--- /dev/null
+++ b/examples/cxx/tree/order/mixed/driver.cxx
@@ -0,0 +1,89 @@
+// file : examples/cxx/tree/order/mixed/driver.cxx
+// copyright : not copyrighted - public domain
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include "text.hxx"
+
+using std::cerr;
+using std::endl;
+
+int
+main (int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " text.xml" << endl;
+ return 1;
+ }
+
+ try
+ {
+ std::auto_ptr<text> t (text_ (argv[1]));
+
+ // Print what we've got in content order.
+ //
+ for (text::content_order_const_iterator i (t->content_order ().begin ());
+ i != t->content_order ().end ();
+ ++i)
+ {
+ switch (i->id)
+ {
+ case text::a_id:
+ {
+ const anchor& a (t->a ()[i->index]);
+ cerr << a << "[" << a.href () << "]";
+ break;
+ }
+ case text::text_content_id:
+ {
+ const xml_schema::string& s (t->text_content ()[i->index]);
+ cerr << s;
+ break;
+ }
+ default:
+ {
+ assert (false); // Unknown content id.
+ }
+ }
+ }
+
+ cerr << endl;
+
+ // Modify the document. Note that we have to update both the content
+ // itself and content order sequences.
+ //
+ typedef text::content_order_type order_type;
+
+ text::content_order_sequence& co (t->content_order ());
+ text::text_content_sequence& tc (t->text_content ());
+
+ tc.push_back ("The last paragraph doesn't talk about ");
+ co.push_back (order_type (text::text_content_id, tc.size () - 1));
+
+ t->a ().push_back (anchor ("anything", "http://en.wikipedia.org"));
+ co.push_back (order_type (text::a_id, t->a ().size () - 1));
+
+ tc.push_back (" in particular.\n\n");
+ co.push_back (order_type (text::text_content_id, tc.size () - 1));
+
+ // Serialize the modified document back to XML.
+ //
+ xml_schema::namespace_infomap map;
+
+ map[""].schema = "text.xsd";
+
+ text_ (std::cout,
+ *t,
+ map,
+ "UTF-8",
+ xml_schema::flags::dont_pretty_print);
+ }
+ catch (const xml_schema::exception& e)
+ {
+ cerr << e << endl;
+ return 1;
+ }
+}
diff --git a/examples/cxx/tree/order/mixed/makefile b/examples/cxx/tree/order/mixed/makefile
new file mode 100644
index 0000000..3e3eb30
--- /dev/null
+++ b/examples/cxx/tree/order/mixed/makefile
@@ -0,0 +1,99 @@
+# file : examples/cxx/tree/order/mixed/makefile
+# copyright : Copyright (c) 2005-2014 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make
+
+xsd := text.xsd
+cxx := driver.cxx
+
+obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o))
+dep := $(obj:.o=.o.d)
+
+driver := $(out_base)/driver
+install := $(out_base)/.install
+dist := $(out_base)/.dist
+dist-win := $(out_base)/.dist-win
+clean := $(out_base)/.clean
+
+# Import.
+#
+$(call import,\
+ $(scf_root)/import/libxerces-c/stub.make,\
+ l: xerces_c.l,cpp-options: xerces_c.l.cpp-options)
+
+# Build.
+#
+$(driver): $(obj) $(xerces_c.l) -lnsl
+
+$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd
+$(obj) $(dep): $(xerces_c.l.cpp-options)
+
+genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx)
+gen := $(addprefix $(out_base)/,$(genf))
+
+$(gen): xsd := $(out_root)/xsd/xsd
+$(gen): xsd_options += --generate-serialization --ordered-type-mixed
+$(gen): $(out_root)/xsd/xsd
+
+$(call include-dep,$(dep),$(obj),$(gen))
+
+# Convenience alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Install & Dist.
+#
+dist-common := $(out_base)/.dist-common
+
+$(install) $(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base))
+
+$(install):
+ $(call install-data,$(src_base)/README,$(install_doc_dir)/xsd/$(path)/README)
+ $(call install-data,$(src_base)/driver.cxx,$(install_doc_dir)/xsd/$(path)/driver.cxx)
+ $(call install-data,$(src_base)/text.xsd,$(install_doc_dir)/xsd/$(path)/text.xsd)
+ $(call install-data,$(src_base)/text.xml,$(install_doc_dir)/xsd/$(path)/text.xml)
+
+$(dist-common):
+ $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx)
+ $(call install-data,$(src_base)/text.xsd,$(dist_prefix)/$(path)/text.xsd)
+ $(call install-data,$(src_base)/text.xml,$(dist_prefix)/$(path)/text.xml)
+
+$(dist): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README)
+
+$(dist-win): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+# Clean.
+#
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean))
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(gen): | $(out_base)/.gitignore
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver $(genf)
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+$(call include,$(bld_root)/install.make)
+$(call include,$(scf_root)/xsd/tree/xsd-cxx.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsd/makefile)
diff --git a/examples/cxx/tree/order/mixed/text.xml b/examples/cxx/tree/order/mixed/text.xml
new file mode 100644
index 0000000..815b76e
--- /dev/null
+++ b/examples/cxx/tree/order/mixed/text.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/tree/order/mixed/text.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<text xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="text.xsd">
+
+The first paragraph of this text talks about <a href="http://en.wikipedia.org/wiki/time">time</a>.
+
+And this paragraph talks about <a href="http://en.wikipedia.org/wiki/space">space</a>.
+
+</text>
diff --git a/examples/cxx/tree/order/mixed/text.xsd b/examples/cxx/tree/order/mixed/text.xsd
new file mode 100644
index 0000000..bfb868e
--- /dev/null
+++ b/examples/cxx/tree/order/mixed/text.xsd
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/tree/order/mixed/text.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsd:complexType name="anchor">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="href" type="xsd:anyURI" use="required"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="text" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="a" type="anchor" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="text" type="text"/>
+
+</xsd:schema>
diff --git a/libxsd/xsd/cxx/tree/elements.hxx b/libxsd/xsd/cxx/tree/elements.hxx
index 6270c40..89be61e 100644
--- a/libxsd/xsd/cxx/tree/elements.hxx
+++ b/libxsd/xsd/cxx/tree/elements.hxx
@@ -21,6 +21,7 @@
#include <map>
#include <string>
#include <memory> // std::auto_ptr/unique_ptr
+#include <cstddef> // std::size_t
#include <istream>
#include <sstream>
#include <cassert>
@@ -190,7 +191,6 @@ namespace xsd
unsigned long x_;
};
-
// Parsing properties. Refer to xsd/cxx/xml/elements.hxx for XML-
// related properties.
//
@@ -199,6 +199,44 @@ namespace xsd
{
};
+ /**
+ * @brief Content order sequence entry.
+ *
+ * @nosubgrouping
+ */
+ struct content_order
+ {
+ /**
+ * @brief Initialize an instance with passed id and index.
+ *
+ * @param id Content id.
+ * @param index Content index in the corresponding sequence.
+ */
+ content_order (std::size_t id, std::size_t index = 0)
+ : id (id), index (index)
+ {
+ }
+
+ /**
+ * @brief Content id.
+ */
+ std::size_t id;
+
+ /**
+ * @brief Content index.
+ */
+ std::size_t index;
+ };
+
+ bool
+ operator== (const content_order&, const content_order&);
+
+ bool
+ operator!= (const content_order&, const content_order&);
+
+ bool
+ operator< (const content_order&, const content_order&);
+
//@cond
// DOM user data keys.
diff --git a/libxsd/xsd/cxx/tree/elements.ixx b/libxsd/xsd/cxx/tree/elements.ixx
index 1098299..da8a83e 100644
--- a/libxsd/xsd/cxx/tree/elements.ixx
+++ b/libxsd/xsd/cxx/tree/elements.ixx
@@ -8,6 +8,27 @@ namespace xsd
{
namespace tree
{
+ // content_order_type
+ //
+
+ inline bool
+ operator== (const content_order& x, const content_order& y)
+ {
+ return x.id == y.id && x.index == y.index;
+ }
+
+ inline bool
+ operator!= (const content_order& x, const content_order& y)
+ {
+ return !(x == y);
+ }
+
+ inline bool
+ operator< (const content_order& x, const content_order& y)
+ {
+ return x.id < y.id || (x.id == y.id && x.index < y.index);
+ }
+
// type
//
diff --git a/libxsd/xsd/cxx/xml/dom/parsing-source.hxx b/libxsd/xsd/cxx/xml/dom/parsing-source.hxx
index 1c53928..fac1006 100644
--- a/libxsd/xsd/cxx/xml/dom/parsing-source.hxx
+++ b/libxsd/xsd/cxx/xml/dom/parsing-source.hxx
@@ -30,30 +30,47 @@ namespace xsd
{
namespace dom
{
- // Parser state object. Can be used for parsing element, attributes,
- // or both.
+ // Parser state object. Can be used for parsing elements (and
+ // optionally text), attributes, or both.
//
template <typename C>
class parser
{
public:
- parser (const xercesc::DOMElement& e, bool ep, bool ap);
+ parser (const xercesc::DOMElement& e, bool ep, bool tp, bool ap);
+ // Content parsing.
+ //
bool
- more_elements ()
+ more_content ()
{
- return next_element_ != 0;
+ return next_content_ != 0;
}
const xercesc::DOMElement&
cur_element ()
{
- return *static_cast<const xercesc::DOMElement*> (next_element_);
+ return *static_cast<const xercesc::DOMElement*> (next_content_);
+ }
+
+ const xercesc::DOMText&
+ cur_text ()
+ {
+ return *static_cast<const xercesc::DOMText*> (next_content_);
+ }
+
+ bool
+ cur_is_text ()
+ {
+ return next_content_->getNodeType () !=
+ xercesc::DOMNode::ELEMENT_NODE;
}
void
- next_element ();
+ next_content (bool text);
+ // Attribute parsing.
+ //
bool
more_attributes ()
{
@@ -86,7 +103,7 @@ namespace xsd
private:
const xercesc::DOMElement& element_;
- const xercesc::DOMNode* next_element_;
+ const xercesc::DOMNode* next_content_;
const xercesc::DOMNamedNodeMap* a_;
XMLSize_t ai_; // Index of the next DOMAttr.
diff --git a/libxsd/xsd/cxx/xml/dom/parsing-source.txx b/libxsd/xsd/cxx/xml/dom/parsing-source.txx
index 8eb4d6e..c789fa6 100644
--- a/libxsd/xsd/cxx/xml/dom/parsing-source.txx
+++ b/libxsd/xsd/cxx/xml/dom/parsing-source.txx
@@ -29,9 +29,9 @@ namespace xsd
//
template <typename C>
parser<C>::
- parser (const xercesc::DOMElement& e, bool ep, bool ap)
+ parser (const xercesc::DOMElement& e, bool ep, bool tp, bool ap)
: element_ (e),
- next_element_ (0),
+ next_content_ (0),
a_ (0),
ai_ (0)
{
@@ -39,10 +39,21 @@ namespace xsd
if (ep)
{
- for (next_element_ = e.getFirstChild ();
- next_element_ != 0 &&
- next_element_->getNodeType () != DOMNode::ELEMENT_NODE;
- next_element_ = next_element_->getNextSibling ()) /*noop*/;
+ for (next_content_ = e.getFirstChild ();;
+ next_content_ = next_content_->getNextSibling ())
+ {
+ if (next_content_ == 0)
+ break;
+
+ DOMNode::NodeType t (next_content_->getNodeType ());
+
+ if (t == DOMNode::ELEMENT_NODE)
+ break;
+
+ if (tp && (t == DOMNode::TEXT_NODE ||
+ t == DOMNode::CDATA_SECTION_NODE))
+ break;
+ }
}
if (ap)
@@ -54,14 +65,25 @@ namespace xsd
template <typename C>
void parser<C>::
- next_element ()
+ next_content (bool tp)
{
using xercesc::DOMNode;
- for (next_element_ = next_element_->getNextSibling ();
- next_element_ != 0 &&
- next_element_->getNodeType () != DOMNode::ELEMENT_NODE;
- next_element_ = next_element_->getNextSibling ())/*noop*/;
+ for (next_content_ = next_content_->getNextSibling ();;
+ next_content_ = next_content_->getNextSibling ())
+ {
+ if (next_content_ == 0)
+ break;
+
+ DOMNode::NodeType t (next_content_->getNodeType ());
+
+ if (t == DOMNode::ELEMENT_NODE)
+ break;
+
+ if (tp && (t == DOMNode::TEXT_NODE ||
+ t == DOMNode::CDATA_SECTION_NODE))
+ break;
+ }
}
// parse()
diff --git a/tests/cxx/tree/makefile b/tests/cxx/tree/makefile
index 43f806b..cd081e8 100644
--- a/tests/cxx/tree/makefile
+++ b/tests/cxx/tree/makefile
@@ -20,6 +20,7 @@ float \
list \
name-clash \
naming \
+order \
polymorphism \
prefix \
test-template \
diff --git a/tests/cxx/tree/order/driver.cxx b/tests/cxx/tree/order/driver.cxx
new file mode 100644
index 0000000..01d8d9f
--- /dev/null
+++ b/tests/cxx/tree/order/driver.cxx
@@ -0,0 +1,65 @@
+// file : tests/cxx/tree/order/driver.cxx
+// copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+// Test ordered type support.
+//
+
+#include <memory> // std::auto_ptr/unique_ptr
+#include <cassert>
+#include <iostream>
+
+#include <xercesc/dom/DOM.hpp>
+#include <xercesc/util/PlatformUtils.hpp>
+
+#include "test.hxx"
+
+using namespace std;
+using namespace test;
+using namespace xercesc;
+
+int
+main (int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " test.xml" << endl;
+ return 1;
+ }
+
+ XMLPlatformUtils::Initialize ();
+
+ try
+ {
+ XSD_AUTO_PTR<root> r (root_ (argv[1], xml_schema::flags::dont_initialize));
+
+ root c (*r);
+ assert (c == *r);
+
+ for (root::t1_const_iterator j (r->t1 ().begin ());
+ j != r->t1 ().end (); ++j)
+ {
+ const t1_derived& d (*j);
+
+ for (t1_derived::content_order_const_iterator i (
+ d.content_order ().begin ()); i != d.content_order ().end (); ++i)
+ {
+ cout << i->id << ' ' << i->index << endl;
+ }
+ }
+
+ xml_schema::namespace_infomap map;
+
+ map["t"].name = "test";
+ map["t1"].name = "test1";
+
+ root_ (cout, *r, map, "UTF-8", xml_schema::flags::dont_initialize);
+ }
+ catch (xml_schema::exception const& e)
+ {
+ cerr << e << endl;
+ return 1;
+ }
+
+ XMLPlatformUtils::Terminate ();
+}
diff --git a/tests/cxx/tree/order/makefile b/tests/cxx/tree/order/makefile
new file mode 100644
index 0000000..0dff0f9
--- /dev/null
+++ b/tests/cxx/tree/order/makefile
@@ -0,0 +1,94 @@
+# file : tests/cxx/tree/order/makefile
+# copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+xsd := test.xsd
+cxx := driver.cxx
+
+obj := $(addprefix $(out_base)/,$(cxx:.cxx=.o) $(xsd:.xsd=.o))
+dep := $(obj:.o=.o.d)
+
+driver := $(out_base)/driver
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+
+# Import.
+#
+$(call import,\
+ $(scf_root)/import/libxerces-c/stub.make,\
+ l: xerces_c.l,cpp-options: xerces_c.l.cpp-options)
+
+
+# Build.
+#
+$(driver): $(obj) $(xerces_c.l)
+
+$(obj) $(dep): cpp_options := -I$(out_base) -I$(src_base) -I$(src_root)/libxsd
+$(obj) $(dep): $(xerces_c.l.cpp-options)
+
+genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.ixx) $(xsd:.xsd=.cxx)
+gen := $(addprefix $(out_base)/,$(genf))
+
+$(gen): xsd := $(out_root)/xsd/xsd
+$(gen): xsd_options += --generate-serialization --generate-wildcard \
+--generate-comparison \
+--ordered-type t1_base --ordered-type t1_derived \
+--ordered-type t2_base --ordered-type t2_derived \
+--ordered-type t3_type \
+--ordered-type t4_base --ordered-type t4_derived \
+--ordered-type t5_base --ordered-type t5_derived \
+--ordered-type t6_base --ordered-type t6_derived \
+--ordered-type t7_type
+$(gen): $(out_root)/xsd/xsd
+
+$(call include-dep,$(dep),$(obj),$(gen))
+
+# Convenience alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Test.
+#
+$(test): driver := $(driver)
+$(test): $(driver) $(src_base)/test.xml $(src_base)/output
+ $(call message,test $$1,$$1 $(src_base)/test.xml | diff -u $(src_base)/output -,$(driver))
+
+# Clean.
+#
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean))
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(gen): | $(out_base)/.gitignore
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver $(genf)
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+
+$(call include,$(bld_root)/cxx/standard.make) # cxx_standard
+ifdef cxx_standard
+$(gen): xsd_options += --std $(cxx_standard)
+$(call include,$(scf_root)/xsd/tree/xsd-cxx.make)
+endif
+
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsd/makefile)
diff --git a/tests/cxx/tree/order/output b/tests/cxx/tree/order/output
new file mode 100644
index 0000000..73442fe
--- /dev/null
+++ b/tests/cxx/tree/order/output
@@ -0,0 +1,92 @@
+2 0
+1 0
+1 1
+2 1
+3 0
+4 0
+3 1
+4 1
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<t:root xmlns:t="test" xmlns:t1="test1">
+ <t1>
+ <b>b1</b>
+ <a>a1</a>
+ <a>a2</a>
+ <b>b2</b>
+ <c>c1</c>
+ <d>d1</d>
+ <t1:e>e1</t1:e>
+ <d>d2</d>
+ <t1:f>f1</t1:f>
+ </t1>
+ <t2>
+ <b>b1</b>
+ <a>a1</a>
+ <b>b2</b>
+ <a>a2</a>
+ </t2>
+ <t3>
+ <a>a1</a>
+ <b>b1</b>
+ <c>c1</c>
+ <c>c2</c>
+ </t3>
+ <t3>
+ <a>a1</a>
+ <c>c1</c>
+ </t3>
+ <t4>
+ t1
+
+ <b>b1</b>
+ t2
+
+ <a>a1</a>
+ t3
+
+ <b>b2</b>
+ t4
+
+ <a>a2</a>
+ t5
+
+ <t1:d>d1</t1:d>
+ t6
+
+ <c>c1</c>
+ t7
+
+ </t4>
+ <t5a>
+ t5a
+ </t5a>
+ <t5b>
+ t1
+
+ <b>b1</b>
+ t2
+
+ <a>a1</a>
+ t3
+
+ <a>a2</a>
+ t4
+
+ <b>b2</b>
+ t5
+
+ </t5b>
+ <t6>
+ t6
+ </t6>
+ <t7>
+ t1
+
+ <t1:a>a1</t1:a>
+ t2
+
+ <t1:b>b1</t1:b>
+ t3
+
+ </t7>
+</t:root>
diff --git a/tests/cxx/tree/order/test.xml b/tests/cxx/tree/order/test.xml
new file mode 100644
index 0000000..cd82936
--- /dev/null
+++ b/tests/cxx/tree/order/test.xml
@@ -0,0 +1,71 @@
+<t:root xmlns:t="test"
+ xmlns:t1="test1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="test test.xsd">
+ <t1>
+ <b>b1</b>
+ <a>a1</a>
+ <a>a2</a>
+ <b>b2</b>
+ <c>c1</c>
+ <d>d1</d>
+ <t1:e>e1</t1:e>
+ <d>d2</d>
+ <t1:f>f1</t1:f>
+ </t1>
+ <t2>
+ <b>b1</b>
+ <a>a1</a>
+ <b>b2</b>
+ <a>a2</a>
+ </t2>
+ <t3>
+ <a>a1</a>
+ <b>b1</b>
+ <c>c1</c>
+ <c>c2</c>
+ </t3>
+ <t3>
+ <a>a1</a>
+ <c>c1</c>
+ </t3>
+ <t4>
+ t1
+ <b>b1</b>
+ t2
+ <a>a1</a>
+ t3
+ <b>b2</b>
+ t4
+ <a>a2</a>
+ t5
+ <t1:d>d1</t1:d>
+ t6
+ <c>c1</c>
+ t7
+ </t4>
+ <t5a>
+ t5a
+ </t5a>
+ <t5b>
+ t1
+ <b>b1</b>
+ t2
+ <a>a1</a>
+ t3
+ <a>a2</a>
+ t4
+ <b>b2</b>
+ t5
+ </t5b>
+ <t6>
+ t6
+ </t6>
+ <t7>
+ t1
+ <t1:a>a1</t1:a>
+ t2
+ <t1:b>b1</t1:b>
+ t3
+ </t7>
+</t:root>
diff --git a/tests/cxx/tree/order/test.xsd b/tests/cxx/tree/order/test.xsd
new file mode 100644
index 0000000..c30c027
--- /dev/null
+++ b/tests/cxx/tree/order/test.xsd
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test">
+
+ <!-- Test 1: general, with non-ordered intermediate. -->
+
+ <complexType name="t1_base">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="a" type="string"/>
+ <element name="b" type="string"/>
+ </choice>
+ </complexType>
+
+ <complexType name="t1_interm">
+ <complexContent>
+ <extension base="t:t1_base">
+ <sequence>
+ <element name="c" type="string" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="t1_derived">
+ <complexContent>
+ <extension base="t:t1_interm">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="d" type="string"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Test 2: empty base. -->
+
+ <complexType name="t2_base"/>
+
+ <complexType name="t2_derived">
+ <complexContent>
+ <extension base="t:t2_base">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="a" type="string"/>
+ <element name="b" type="string"/>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Test 3: element cardinalities. -->
+
+ <complexType name="t3_type">
+ <sequence>
+ <element name="a" type="string"/>
+ <element name="b" type="string" minOccurs="0"/>
+ <element name="c" type="string" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+
+ <!-- Test 4: mixed content, general. -->
+
+ <complexType name="t4_base" mixed="true">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="a" type="string"/>
+ <element name="b" type="string"/>
+ </choice>
+ </complexType>
+
+ <complexType name="t4_derived">
+ <complexContent mixed="true">
+ <extension base="t:t4_base">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="c" type="string"/>
+ <any namespace="##other" processContents="lax"/>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Test 5: mixed content, empty base. -->
+
+ <complexType name="t5_base" mixed="true"/>
+
+ <complexType name="t5_derived">
+ <complexContent mixed="true">
+ <extension base="t:t5_base">
+ <choice minOccurs="0" maxOccurs="unbounded">
+ <element name="a" type="string"/>
+ <element name="b" type="string"/>
+ </choice>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- Test 6: mixed content, empty base and derived. -->
+
+ <complexType name="t6_base" mixed="true"/>
+
+ <complexType name="t6_derived">
+ <complexContent mixed="true">
+ <extension base="t:t6_base"/>
+ </complexContent>
+ </complexType>
+
+ <!-- Test 7: mixed content wildcard only. -->
+
+ <complexType name="t7_type" mixed="true">
+ <sequence>
+ <any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <!-- Root -->
+
+ <complexType name="root">
+ <sequence>
+ <element name="t1" type="t:t1_derived" maxOccurs="unbounded"/>
+ <element name="t2" type="t:t2_derived" maxOccurs="unbounded"/>
+ <element name="t3" type="t:t3_type" maxOccurs="unbounded"/>
+ <element name="t4" type="t:t4_derived" maxOccurs="unbounded"/>
+ <element name="t5a" type="t:t5_base" maxOccurs="unbounded"/>
+ <element name="t5b" type="t:t5_derived" maxOccurs="unbounded"/>
+ <element name="t6" type="t:t6_derived" maxOccurs="unbounded"/>
+ <element name="t7" type="t:t7_type" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <element name="root" type="t:root"/>
+
+</schema>
diff --git a/tests/cxx/tree/wildcard/driver.cxx b/tests/cxx/tree/wildcard/driver.cxx
index 9d0945f..e2db827 100644
--- a/tests/cxx/tree/wildcard/driver.cxx
+++ b/tests/cxx/tree/wildcard/driver.cxx
@@ -9,6 +9,9 @@
#include <sstream>
#include <iostream>
+#include <xercesc/dom/DOM.hpp>
+#include <xercesc/util/PlatformUtils.hpp>
+
#include "test.hxx" // Get XSD_CXX11 defined.
#include <xsd/cxx/xml/string.hxx>
diff --git a/xsd/cxx/tree/elements.hxx b/xsd/cxx/tree/elements.hxx
index f3f9f66..6874e6a 100644
--- a/xsd/cxx/tree/elements.hxx
+++ b/xsd/cxx/tree/elements.hxx
@@ -6,6 +6,7 @@
#define CXX_TREE_ELEMENTS_HXX
#include <map>
+#include <set>
#include <deque>
#include <vector>
#include <sstream>
@@ -68,6 +69,54 @@ namespace CXX
String reason_;
};
+ // A set of potentially qualified XML Schema type names.
+ //
+ struct TypeNameSet
+ {
+ template <typename I>
+ TypeNameSet (I begin, I end)
+ {
+ for (; begin != end; ++begin)
+ insert (*begin);
+ }
+
+ void
+ insert (String const& name)
+ {
+ size_t p (name.rfind ('#'));
+
+ if (p == String::npos)
+ unames_.insert (name);
+ else
+ qnames_.insert (name);
+ }
+
+ bool
+ find (SemanticGraph::Type& t)
+ {
+ if (!unames_.empty ())
+ {
+ if (unames_.find (t.name ()) != unames_.end ())
+ return true;
+ }
+
+ if (!qnames_.empty ())
+ {
+ if (qnames_.find (t.scope ().name () + L"#" + t.name ()) !=
+ qnames_.end ())
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ typedef std::set<String> StringSet;
+
+ StringSet unames_;
+ StringSet qnames_;
+ };
+
//
//
class Context: public CXX::Context
@@ -157,6 +206,22 @@ namespace CXX
//
//
public:
+ static bool
+ ordered_p (SemanticGraph::Type const& t)
+ {
+ return t.context ().count ("ordered") &&
+ t.context ().get<bool> ("ordered");
+ }
+
+ // Check if we are generating mixed support for this type. We only
+ // do it for ordered types.
+ //
+ static bool
+ mixed_p (SemanticGraph::Complex const& c)
+ {
+ return c.mixed_p () && ordered_p (c);
+ }
+
bool
polymorphic_p (SemanticGraph::Type&);
@@ -1338,7 +1403,11 @@ namespace CXX
virtual void
traverse (SemanticGraph::Complex& c)
{
- names (c, names_);
+ if (c.mixed_p ())
+ v_ = false;
+
+ if (v_)
+ names (c, names_);
if (v_)
inherits (c, inherits_);
diff --git a/xsd/cxx/tree/fundamental-header.hxx b/xsd/cxx/tree/fundamental-header.hxx
index dbe7c9a..1145c0c 100644
--- a/xsd/cxx/tree/fundamental-header.hxx
+++ b/xsd/cxx/tree/fundamental-header.hxx
@@ -724,6 +724,17 @@ namespace CXX
bool serialization (options.generate_serialization ());
bool element_map (options.generate_element_map ());
+ {
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Content order sequence entry." << endl
+ << " */" << endl;
+
+ gen_typedef (c.get<String> ("content-order"),
+ "::xsd::cxx::tree::content_order");
+ }
+
if (options.generate_element_type ())
{
if (doxygen)
diff --git a/xsd/cxx/tree/generator.cxx b/xsd/cxx/tree/generator.cxx
index 5178bb1..f7eb1fa 100644
--- a/xsd/cxx/tree/generator.cxx
+++ b/xsd/cxx/tree/generator.cxx
@@ -24,6 +24,7 @@
#include <cxx/tree/counter.hxx>
#include <cxx/tree/validator.hxx>
#include <cxx/tree/name-processor.hxx>
+#include <cxx/tree/order-processor.hxx>
#include <cxx/tree/polymorphism-processor.hxx>
#include <cxx/tree/tree-forward.hxx>
@@ -234,6 +235,15 @@ namespace CXX
bool gen_cxx (!ops.generate_dep_only ());
+ // Process ordered types.
+ //
+ if (gen_cxx)
+ {
+ OrderProcessor proc;
+ if (!proc.process (ops, schema, file_path))
+ throw Failed ();
+ }
+
// Process names.
//
if (gen_cxx)
diff --git a/xsd/cxx/tree/name-processor.cxx b/xsd/cxx/tree/name-processor.cxx
index e34ae84..1f3844b 100644
--- a/xsd/cxx/tree/name-processor.cxx
+++ b/xsd/cxx/tree/name-processor.cxx
@@ -60,6 +60,7 @@ namespace CXX
seq_modifier_regex (seq_modifier_regex_),
parser_regex (parser_regex_),
serializer_regex (serializer_regex_),
+ const_regex (const_regex_),
enumerator_regex (enumerator_regex_),
element_type_regex (element_type_regex_)
{
@@ -231,6 +232,30 @@ namespace CXX
"serializer");
}
+ // Const regex.
+ //
+ {
+ if (fn == "knr")
+ {
+ const_regex.push_back ("/([^,]+),([^,]+),([^,]+)/$1_$2_$3/");
+ const_regex.push_back ("/([^,]+),([^,]+)/$1_$2/");
+ }
+ else if (fn == "lcc")
+ {
+ const_regex.push_back ("/([^,]+),([^,]+),([^,]+)/\\l$1_\\u$2_\\u$3/");
+ const_regex.push_back ("/([^,]+),([^,]+)/\\l$1\\u$2/");
+ }
+ else
+ {
+ // Java: all uppercase.
+ //
+ const_regex.push_back ("/([^,]+),([^,]+),([^,]+)/\\U$1_$2_$3/");
+ const_regex.push_back ("/([^,]+),([^,]+)/\\U$1_$2/");
+ }
+
+ compile_regex (options.const_regex (), const_regex, "const");
+ }
+
// Enumerator name regex.
//
{
@@ -267,6 +292,7 @@ namespace CXX
seq_modifier_regex (c.seq_modifier_regex),
parser_regex (c.parser_regex),
serializer_regex (c.serializer_regex),
+ const_regex (c.const_regex),
enumerator_regex (c.enumerator_regex),
element_type_regex (c.element_type_regex)
{
@@ -522,6 +548,7 @@ namespace CXX
RegexVector seq_modifier_regex_;
RegexVector parser_regex_;
RegexVector serializer_regex_;
+ RegexVector const_regex_;
RegexVector enumerator_regex_;
RegexVector element_type_regex_;
@@ -542,6 +569,7 @@ namespace CXX
RegexVector& seq_modifier_regex;
RegexVector& parser_regex;
RegexVector& serializer_regex;
+ RegexVector& const_regex;
RegexVector& enumerator_regex;
RegexVector& element_type_regex;
};
@@ -655,6 +683,9 @@ namespace CXX
if (Tree::Context::skip (m))
return;
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (m.scope ()));
+
size_t max (Tree::Context::max (m));
size_t min (Tree::Context::min (m));
@@ -662,7 +693,7 @@ namespace CXX
String const& b (m.context ().get<String> ("name"));
bool def_attr (m.default_p () &&
- m.is_a<SemanticGraph::Attribute> ());
+ m.is_a<SemanticGraph::Attribute> ());
// Accessors/modifiers. Note that we postpone inserting
// the names into the name_set to avoid over-escaping.
@@ -816,7 +847,7 @@ namespace CXX
process_regex (
s + L",default,value", accessor_regex, L"accessor")));
- m.context ().set ( "default-value", find_name (an, name_set_));
+ m.context ().set ("default-value", find_name (an, name_set_));
bool lit (false);
{
@@ -832,6 +863,18 @@ namespace CXX
}
}
}
+
+ // Element id.
+ //
+ if (m.is_a<SemanticGraph::Element> () && ordered_p (c))
+ {
+ String id (
+ escape (
+ process_regex (
+ s + L",id", const_regex, L"const")));
+
+ m.context ().set ("ordered-id-name", find_name (id, name_set_));
+ }
}
private:
@@ -857,6 +900,9 @@ namespace CXX
virtual void
traverse (SemanticGraph::Any& a)
{
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (a.scope ()));
+
size_t max (Tree::Context::max (a));
size_t min (Tree::Context::min (a));
@@ -972,6 +1018,18 @@ namespace CXX
//
a.context ().set ("member", find_name (b + L"_", name_set_));
+ // Wildcard id.
+ //
+ if (ordered_p (c))
+ {
+ String id (
+ escape (
+ process_regex (
+ s + L",id", const_regex, L"const")));
+
+ a.context ().set ("ordered-id-name", find_name (id, name_set_));
+ }
+
if (!has_wildcard_)
has_wildcard_ = true;
}
@@ -1057,17 +1115,17 @@ namespace CXX
virtual void
traverse (Type& c)
{
- SemanticGraph::Context& cc (c.context ());
+ SemanticGraph::Context& ctx (c.context ());
// We leave this set around to allow other mappings to use
// this information.
//
- cc.set ("cxx-tree-name-processor-stem-set", NameSet ());
- cc.set ("cxx-tree-name-processor-member-set", NameSet ());
+ ctx.set ("cxx-tree-name-processor-stem-set", NameSet ());
+ ctx.set ("cxx-tree-name-processor-member-set", NameSet ());
// Use processed name.
//
- String name (cc.get<String> ("name"));
+ String name (ctx.get<String> ("name"));
// If renamed name is empty then we are not generating
// anything for this type and name processing is not
@@ -1077,10 +1135,10 @@ namespace CXX
return;
NameSet& stem_set (
- cc.get<NameSet> ("cxx-tree-name-processor-stem-set"));
+ ctx.get<NameSet> ("cxx-tree-name-processor-stem-set"));
NameSet& member_set (
- cc.get<NameSet> ("cxx-tree-name-processor-member-set"));
+ ctx.get<NameSet> ("cxx-tree-name-processor-member-set"));
stem_set.insert (c.name ());
member_set.insert (name);
@@ -1136,6 +1194,116 @@ namespace CXX
Complex::names (c, names);
}
+ // Names for the mixed content.
+ //
+ if (mixed_p (c))
+ {
+ // Check if we already have the mixed content down inheritance
+ // hierarchy.
+ //
+ using SemanticGraph::Complex;
+
+ for (Complex* p (&c); p->inherits_p ();)
+ {
+ if (Complex* b = dynamic_cast<Complex*> (
+ &p->inherits ().base ()))
+ {
+ if (mixed_p (*b))
+ {
+ SemanticGraph::Context& bctx (b->context ());
+ ctx.set ("mixed-type", bctx.get<String> ("mixed-type"));
+ ctx.set ("mixed-const-iterator",
+ bctx.get<String> ("mixed-const-iterator"));
+ ctx.set ("mixed-ordered-id-name",
+ bctx.get<String> ("mixed-ordered-id-name"));
+ ctx.set ("mixed-aname", bctx.get<String> ("mixed-aname"));
+ ctx.set ("mixed-member", bctx.get<String> ("mixed-member"));
+ ctx.set ("mixed-in-base", true);
+ break;
+ }
+
+ p = b;
+ }
+ else
+ break;
+ }
+
+ // If not, set up the names.
+ //
+ if (!ctx.count ("mixed-in-base"))
+ {
+ String s (find_name (L"text,content", stem_set));
+ String n (find_name (escape (s), member_set, false));
+
+ String an (find_name (
+ escape (process_regex (s,
+ seq_accessor_regex,
+ accessor_regex,
+ L"sequence accessor")),
+ member_set,
+ false));
+
+ String mn (find_name (
+ escape (process_regex (s,
+ seq_modifier_regex,
+ modifier_regex,
+ L"sequence modifier")),
+ member_set,
+ false));
+
+ ctx.set ("mixed-aname", an);
+ ctx.set ("mixed-mname", mn);
+
+ member_set.insert (name);
+
+ if (an != n)
+ member_set.insert (an);
+
+ if (mn != n && mn != an)
+ member_set.insert (mn);
+
+ // Types.
+ //
+ ctx.set (
+ "mixed-type",
+ find_name (
+ escape (process_regex (s + L",type", type_regex, L"type")),
+ member_set));
+
+ ctx.set (
+ "mixed-container",
+ find_name (
+ escape (process_regex (s + L",sequence", type_regex, L"type")),
+ member_set));
+
+ ctx.set (
+ "mixed-iterator",
+ find_name (
+ escape (process_regex (s + L",iterator", type_regex, L"type")),
+ member_set));
+
+ ctx.set (
+ "mixed-const-iterator",
+ find_name (
+ escape (
+ process_regex (s + L",const,iterator", type_regex, L"type")),
+ member_set));
+
+ // Text content id.
+ //
+ ctx.set (
+ "mixed-ordered-id-name",
+ find_name (
+ escape (
+ process_regex (s + L",id", const_regex, L"const")),
+ member_set));
+
+ // Data member.
+ //
+ ctx.set ("mixed-member", find_name (n + L"_", member_set));
+ }
+ }
+
// Names for wildcards.
//
if (options.generate_wildcard ())
@@ -1190,6 +1358,105 @@ namespace CXX
}
}
}
+
+ // Names for the order container.
+ //
+ if (ordered_p (c))
+ {
+ // Check if we already have the order container down
+ // inheritance hierarchy.
+ //
+ using SemanticGraph::Complex;
+
+ for (Complex* p (&c); p->inherits_p ();)
+ {
+ if (Complex* b = dynamic_cast<Complex*> (
+ &p->inherits ().base ()))
+ {
+ if (ordered_p (*b))
+ {
+ SemanticGraph::Context& bctx (b->context ());
+ ctx.set ("order-type", bctx.get<String> ("order-type"));
+ ctx.set ("order-const-iterator",
+ bctx.get<String> ("order-const-iterator"));
+ ctx.set ("order-aname", bctx.get<String> ("order-aname"));
+ ctx.set ("order-member", bctx.get<String> ("order-member"));
+ ctx.set ("order-in-base", true);
+ break;
+ }
+
+ p = b;
+ }
+ else
+ break;
+ }
+
+ // If not, set up the names.
+ //
+ if (!ctx.count ("order-in-base"))
+ {
+ String s (find_name (L"content,order", stem_set));
+ String n (find_name (escape (s), member_set, false));
+
+ String an (find_name (
+ escape (process_regex (s,
+ seq_accessor_regex,
+ accessor_regex,
+ L"sequence accessor")),
+ member_set,
+ false));
+
+ String mn (find_name (
+ escape (process_regex (s,
+ seq_modifier_regex,
+ modifier_regex,
+ L"sequence modifier")),
+ member_set,
+ false));
+
+ ctx.set ("order-aname", an);
+ ctx.set ("order-mname", mn);
+
+ member_set.insert (name);
+
+ if (an != n)
+ member_set.insert (an);
+
+ if (mn != n && mn != an)
+ member_set.insert (mn);
+
+ // Types.
+ //
+ ctx.set (
+ "order-type",
+ find_name (
+ escape (process_regex (s + L",type", type_regex, L"type")),
+ member_set));
+
+ ctx.set (
+ "order-container",
+ find_name (
+ escape (process_regex (s + L",sequence", type_regex, L"type")),
+ member_set));
+
+ ctx.set (
+ "order-iterator",
+ find_name (
+ escape (process_regex (s + L",iterator", type_regex, L"type")),
+ member_set));
+
+ ctx.set (
+ "order-const-iterator",
+ find_name (
+ escape (
+ process_regex (s + L",const,iterator", type_regex, L"type")),
+ member_set));
+
+ // Data member.
+ //
+ ctx.set ("order-member", find_name (n + L"_", member_set));
+ }
+ }
}
};
@@ -1870,6 +2137,8 @@ namespace CXX
process_name (n, "buffer", "buffer");
process_name (n, "time,zone", "time-zone");
+ process_name (n, "content,order", "content-order");
+
if (options.generate_element_type ())
process_name (n, "element,type", "element-type");
diff --git a/xsd/cxx/tree/options.cli b/xsd/cxx/tree/options.cli
index ac126fe..026e4a1 100644
--- a/xsd/cxx/tree/options.cli
+++ b/xsd/cxx/tree/options.cli
@@ -51,6 +51,58 @@ namespace CXX
schemas that define the same polymorphic types."
};
+ // Ordered content.
+ //
+ NarrowStrings --ordered-type
+ {
+ "<type>",
+ "Indicate that element order in <type> is significant. An example
+ would be a complex type with unbounded choice as a content model
+ where the element order in XML has application-specific semantics.
+ For ordered types the compiler generates a special container data
+ member and a corresponding set of accessors and modifiers that are
+ used to capture the order of elements and, for mixed content, of
+ text.
+
+ The <type> argument is an XML Schema type name that can be optionally
+ qualified with a namespace in the \c{\i{namespace}\b{#}\i{name}} form.
+ Note also that you will need to specify this option when compiling
+ every schema file that has other ordered types derived from this
+ type."
+ };
+
+ bool --ordered-type-derived
+ {
+ "Automatically treat types derived from ordered bases as also
+ ordered. This is primarily useful if you would like to be able
+ to iterate over the complete content using the content order
+ container."
+ };
+
+ bool --ordered-type-mixed
+ {
+ "Automatically treat complex types with mixed content as ordered."
+ };
+
+ bool --ordered-type-all
+ {
+ "Indicate that element order in all types is significant."
+ };
+
+ NarrowString --order-container
+ {
+ "<type>",
+ "Specify a custom class template that should be used as a container
+ for the content order in ordered types instead of the default
+ \cb{std::vector}. See \cb{--ordered-type} for more information on
+ ordered type. This option is primarily useful if you need to
+ perform more complex lookups in the content order container, for
+ example by element id. In this case, a container like Boost
+ multi-index may be more convenient. Note that if using a custom
+ container, you will also most likely need to include the relevant
+ headers using the \cb{--hxx-prologue*} options."
+ };
+
// Features.
//
bool --generate-serialization
@@ -299,6 +351,14 @@ namespace CXX
the NAMING CONVENTION section below for more information."
};
+ NarrowStrings --const-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions used to translate
+ XML Schema-derived names to C++ constant names. See the NAMING
+ CONVENTION section below for more information."
+ };
+
NarrowStrings --enumerator-regex
{
"<regex>",
diff --git a/xsd/cxx/tree/order-processor.cxx b/xsd/cxx/tree/order-processor.cxx
new file mode 100644
index 0000000..68eee8c
--- /dev/null
+++ b/xsd/cxx/tree/order-processor.cxx
@@ -0,0 +1,244 @@
+// file : xsde/cxx/tree/order-processor.cxx
+// copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#include <iostream>
+
+#include <cxx/tree/elements.hxx>
+#include <cxx/tree/order-processor.hxx>
+
+#include <xsd-frontend/semantic-graph.hxx>
+#include <xsd-frontend/traversal.hxx>
+
+using namespace std;
+
+namespace CXX
+{
+ namespace Tree
+ {
+ namespace
+ {
+ struct Member: Traversal::Element, Traversal::Any
+ {
+ Member (size_t count): count_ (count) {}
+
+ virtual void
+ traverse (SemanticGraph::Element& e)
+ {
+ if (Context::skip (e))
+ return;
+
+ e.context ().set ("ordered-id", count_++);
+ }
+
+ virtual void
+ traverse (SemanticGraph::Any& a)
+ {
+ a.context ().set ("ordered-id", count_++);
+ }
+
+ size_t count_;
+ };
+
+ //
+ //
+ struct Type: Traversal::Complex
+ {
+ Type (TypeNameSet& ordered_types, bool derived, bool mixed, bool all)
+ : ordered_types_ (ordered_types),
+ derived_ (derived),
+ mixed_ (mixed),
+ all_ (all)
+ {
+ }
+
+ virtual void
+ traverse (SemanticGraph::Complex& c)
+ {
+ SemanticGraph::Context& ctx (c.context ());
+
+ if (!ctx.count ("ordered"))
+ {
+ // First process our base.
+ //
+ if (c.inherits_p ())
+ {
+ SemanticGraph::Type& b (c.inherits ().base ());
+
+ if (!b.context ().count ("ordered"))
+ dispatch (b);
+ }
+
+ // See if our base (not necessarily immediate) is ordered.
+ //
+ using SemanticGraph::Complex;
+
+ Complex* b (0);
+
+ for (Complex* p (&c); p->inherits_p ();)
+ {
+ if ((b = dynamic_cast<Complex*> (&p->inherits ().base ())))
+ {
+ if (Context::ordered_p (*b))
+ break;
+
+ p = b;
+ }
+ else
+ break;
+ }
+
+ bool o (all_ ||
+ (derived_ && b != 0 && Context::ordered_p (*b)) ||
+ (mixed_ && c.mixed_p ()) ||
+ ordered_types_.find (c));
+ ctx.set ("ordered", o);
+
+ // Assign ids to elements and wildcards, calculate total count.
+ //
+ if (o)
+ {
+ size_t count (
+ b != 0 && Context::ordered_p (*b)
+ ? b->context ().get<size_t> ("ordered-count")
+ : 1);
+
+ ctx.set ("ordered-start", count);
+
+ Member m (count);
+ Traversal::Names n (m);
+ names (c, n);
+
+ // Assign content id for mixed text.
+ //
+ if (Context::mixed_p (c) && count == 1)
+ ctx.set ("mixed-ordered-id", m.count_++);
+
+ ctx.set ("ordered-count", m.count_);
+ }
+ }
+ }
+
+ private:
+ TypeNameSet& ordered_types_;
+ bool derived_;
+ bool mixed_;
+ bool all_;
+ };
+
+ // Go into sourced/included/imported schemas while making sure
+ // we don't process the same stuff more than once.
+ //
+ struct Uses: Traversal::Sources,
+ Traversal::Includes,
+ Traversal::Imports
+ {
+ Uses (char const* seen_key)
+ : seen_key_ (seen_key)
+ {
+ }
+
+ virtual void
+ traverse (SemanticGraph::Sources& sr)
+ {
+ SemanticGraph::Schema& s (sr.schema ());
+
+ if (!s.context ().count (seen_key_))
+ {
+ s.context ().set (seen_key_, true);
+ Traversal::Sources::traverse (sr);
+ }
+ }
+
+ virtual void
+ traverse (SemanticGraph::Includes& i)
+ {
+ SemanticGraph::Schema& s (i.schema ());
+
+ if (!s.context ().count (seen_key_))
+ {
+ s.context ().set (seen_key_, true);
+ Traversal::Includes::traverse (i);
+ }
+ }
+
+ virtual void
+ traverse (SemanticGraph::Imports& i)
+ {
+ SemanticGraph::Schema& s (i.schema ());
+
+ if (!s.context ().count (seen_key_))
+ {
+ s.context ().set (seen_key_, true);
+ Traversal::Imports::traverse (i);
+ }
+ }
+
+ private:
+ char const* seen_key_;
+ };
+
+ char const* seen_key = "cxx-tree-order-processor-seen";
+
+ bool
+ process_impl (options const& ops,
+ SemanticGraph::Schema& tu,
+ SemanticGraph::Path const&)
+ {
+ // Prepare a set of ordered types.
+ //
+ TypeNameSet ordered_types (ops.ordered_type ().begin (),
+ ops.ordered_type ().end ());
+
+ // Root schema in the file-per-type mode is just a bunch
+ // of includes without a namespace.
+ //
+ SemanticGraph::Schema::NamesIterator i (tu.names_begin ());
+
+ // Nothing to do if this is the XML Schema namespace.
+ //
+ if (i == tu.names_end () ||
+ i->named ().name () != L"http://www.w3.org/2001/XMLSchema")
+ {
+ // Note that we check first if this schema has already been
+ // processed which may happen in the file-per-type compilation
+ // mode.
+ //
+ if (!tu.context ().count (seen_key))
+ {
+ Traversal::Schema schema;
+ Uses uses (seen_key);
+
+ schema >> uses >> schema;
+
+ Traversal::Names schema_names;
+ Traversal::Namespace ns;
+ Traversal::Names ns_names;
+ Type type (ordered_types,
+ ops.ordered_type_derived (),
+ ops.ordered_type_mixed (),
+ ops.ordered_type_all ());
+
+ schema >> schema_names >> ns >> ns_names >> type;
+
+ // Some twisted schemas do recusive self-inclusion.
+ //
+ tu.context ().set (seen_key, true);
+
+ schema.dispatch (tu);
+ }
+ }
+
+ return true;
+ }
+ }
+
+ bool OrderProcessor::
+ process (options const& ops,
+ SemanticGraph::Schema& tu,
+ SemanticGraph::Path const& file)
+ {
+ return process_impl (ops, tu, file);
+ }
+ }
+}
diff --git a/xsd/cxx/tree/order-processor.hxx b/xsd/cxx/tree/order-processor.hxx
new file mode 100644
index 0000000..fa68d21
--- /dev/null
+++ b/xsd/cxx/tree/order-processor.hxx
@@ -0,0 +1,30 @@
+// file : xsde/cxx/tree/order-processor.hxx
+// copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef CXX_TREE_ORDER_PROCESSOR_HXX
+#define CXX_TREE_ORDER_PROCESSOR_HXX
+
+#include <xsd-frontend/semantic-graph.hxx>
+
+#include <xsd.hxx>
+#include <types.hxx>
+
+#include <cxx/tree/options.hxx>
+
+namespace CXX
+{
+ namespace Tree
+ {
+ class OrderProcessor
+ {
+ public:
+ bool
+ process (options const&,
+ XSDFrontend::SemanticGraph::Schema&,
+ XSDFrontend::SemanticGraph::Path const& file);
+ };
+ }
+}
+
+#endif // CXX_TREE_ORDER_PROCESSOR_HXX
diff --git a/xsd/cxx/tree/polymorphism-processor.cxx b/xsd/cxx/tree/polymorphism-processor.cxx
index fb96ba7..cbd2471 100644
--- a/xsd/cxx/tree/polymorphism-processor.cxx
+++ b/xsd/cxx/tree/polymorphism-processor.cxx
@@ -2,7 +2,6 @@
// copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC
// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
-#include <set>
#include <iostream>
#include <cxx/tree/elements.hxx>
@@ -19,59 +18,12 @@ namespace CXX
{
namespace
{
- struct TypeSet
- {
- template <typename I>
- TypeSet (I begin, I end)
- {
- for (; begin != end; ++begin)
- insert (*begin);
- }
-
- void
- insert (String const& name)
- {
- size_t p (name.rfind ('#'));
-
- if (p == String::npos)
- unames_.insert (name);
- else
- qnames_.insert (name);
- }
-
- bool
- find (SemanticGraph::Type& t)
- {
- if (!unames_.empty ())
- {
- if (unames_.find (t.name ()) != unames_.end ())
- return true;
- }
-
- if (!qnames_.empty ())
- {
- if (qnames_.find (t.scope ().name () + L"#" + t.name ()) !=
- qnames_.end ())
- return true;
- }
-
- return false;
- }
-
- private:
- typedef set<String> StringSet;
-
- StringSet unames_;
- StringSet qnames_;
- };
-
-
//
//
struct Type: Traversal::Type,
Traversal::Complex
{
- Type (TypeSet& poly_types)
+ Type (TypeNameSet& poly_types)
: poly_types_ (poly_types)
{
}
@@ -110,7 +62,7 @@ namespace CXX
}
private:
- TypeSet& poly_types_;
+ TypeNameSet& poly_types_;
};
struct FundType: Traversal::AnyType,
@@ -169,7 +121,7 @@ namespace CXX
Traversal::Fundamental::Entity,
Traversal::Fundamental::Entities
{
- FundType (TypeSet& poly_types, bool& valid)
+ FundType (TypeNameSet& poly_types, bool& valid)
: poly_types_ (poly_types), valid_ (valid)
{
}
@@ -493,13 +445,13 @@ namespace CXX
}
private:
- TypeSet& poly_types_;
+ TypeNameSet& poly_types_;
bool& valid_;
};
struct GlobalElement: Traversal::Element
{
- GlobalElement (TypeSet& poly_types,
+ GlobalElement (TypeNameSet& poly_types,
bool& valid,
const WarningSet& disabled_warnings)
: poly_types_ (poly_types), valid_ (valid), warning_ (true)
@@ -603,7 +555,7 @@ namespace CXX
}
private:
- TypeSet& poly_types_;
+ TypeNameSet& poly_types_;
bool& valid_;
bool warning_;
};
@@ -674,8 +626,8 @@ namespace CXX
// Prepare a set of polymorphic types.
//
- TypeSet poly_types (ops.polymorphic_type ().begin (),
- ops.polymorphic_type ().end ());
+ TypeNameSet poly_types (ops.polymorphic_type ().begin (),
+ ops.polymorphic_type ().end ());
// Root schema in the file-per-type mode is just a bunch
// of includes without a namespace.
diff --git a/xsd/cxx/tree/serialization-source.cxx b/xsd/cxx/tree/serialization-source.cxx
index 8cb3463..559a3cf 100644
--- a/xsd/cxx/tree/serialization-source.cxx
+++ b/xsd/cxx/tree/serialization-source.cxx
@@ -295,6 +295,11 @@ namespace CXX
if (skip (e))
return;
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (e.scope ()));
+
+ bool ordered (ordered_p (c));
+
String const& aname (eaname (e));
String ns (e.qualified_p () ? e.namespace_ ().name () : "");
String type (scope + L"::" + etype (e));
@@ -311,9 +316,14 @@ namespace CXX
os << "// " << comment (e.name ()) << endl
<< "//" << endl;
+ if (ordered)
+ os << "case " << scope << "::" <<
+ e.context ().get<String> ("ordered-id-name") << ":"
+ << "{";
+
if (poly)
{
- os << "{"
+ os << (ordered ? "" : "{")
<< "::xsd::cxx::tree::type_serializer_map< " << char_type
<< " >& tsm (" << endl
<< "::xsd::cxx::tree::type_serializer_map_instance< " <<
@@ -325,15 +335,22 @@ namespace CXX
{
// sequence
//
- os << "for (" << scope << "::" << econst_iterator (e) << endl
- << "b (i." << aname << " ().begin ()), " <<
- "n (i." << aname << " ().end ());" << endl
- << "b != n; ++b)"
- << "{";
+ if (ordered)
+ os << "const " << type << "& x (i." << aname <<
+ " ()[b->index]);"
+ << endl;
+ else
+ os << "for (" << scope << "::" << econst_iterator (e) << endl
+ << "b (i." << aname << " ().begin ()), " <<
+ "n (i." << aname << " ().end ());" << endl
+ << "b != n; ++b)"
+ << "{";
+
+ char const* x (ordered ? "x" : "*b");
if (poly)
{
- os << "if (typeid (" << type << ") == typeid (*b))"
+ os << "if (typeid (" << type << ") == typeid (" << x << "))"
<< "{"
<< xerces_ns << "::DOMElement& s (" << endl
<< "::xsd::cxx::xml::dom::create_element (" << endl
@@ -341,14 +358,14 @@ namespace CXX
<< (ns ? strlit (ns) + L",\n" : L"")
<< "e));"
<< endl
- << "s << *b;"
+ << "s << " << x << ";"
<< "}"
<< "else" << endl
<< "tsm.serialize (" << endl
<< strlit (e.name ()) << "," << endl
<< strlit (ns) << "," << endl
<< (e.global_p () ? "true" : "false") << ", " <<
- (e.qualified_p () ? "true" : "false") << ", e, *b);";
+ (e.qualified_p () ? "true" : "false") << ", e, " << x << ");";
}
else
{
@@ -363,30 +380,29 @@ namespace CXX
{
case st_other:
{
- os << "s << *b;";
+ os << "s << " << x << ";";
break;
}
case st_double:
{
- os << "s << " << as_double_type << " (*b);";
+ os << "s << " << as_double_type << " (" << x << ");";
break;
}
case st_decimal:
{
- os << "s << " << as_decimal_type << " (*b);";
+ os << "s << " << as_decimal_type << " (" << x << ");";
break;
}
}
}
-
- os << "}";
}
else if (min (e) == 0)
{
// optional
//
- os << "if (i." << aname << " ())"
- << "{";
+ if (!ordered)
+ os << "if (i." << aname << " ())"
+ << "{";
if (poly)
{
@@ -436,8 +452,6 @@ namespace CXX
}
}
}
-
- os << "}";
}
else
{
@@ -465,8 +479,10 @@ namespace CXX
}
else
{
- os << "{"
- << xerces_ns << "::DOMElement& s (" << endl
+ if (!ordered)
+ os << "{";
+
+ os << xerces_ns << "::DOMElement& s (" << endl
<< "::xsd::cxx::xml::dom::create_element (" << endl
<< strlit (e.name ()) << "," << endl
<< (ns ? strlit (ns) + L",\n" : L"")
@@ -491,13 +507,26 @@ namespace CXX
break;
}
}
-
- os << "}";
}
}
- if (poly)
+ if (ordered)
+ {
+ // See comment for bool text (false); below.
+ //
+ if (mixed_p (c) && c.context ().get<size_t> ("ordered-start") != 1)
+ os << "text = true;";
+
+ os << "continue;"
+ << "}";
+ }
+ else
+ {
os << "}";
+
+ if (poly && (max (e) != 1 || min (e) == 0))
+ os << "}"; // There is no extra block for poly one.
+ }
}
private:
@@ -514,48 +543,77 @@ namespace CXX
virtual void
traverse (Type& a)
{
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (a.scope ()));
+
+ bool ordered (ordered_p (c));
+
String const& aname (eaname (a));
os << "// " << ename (a) << endl
<< "//" << endl;
+ if (ordered)
+ os << "case " << scope << "::" <<
+ a.context ().get<String> ("ordered-id-name") << ":";
+
if (max (a) != 1)
{
// sequence
//
- os << "for (" << scope << "::" << econst_iterator (a) << endl
- << "b (i." << aname << " ().begin ()), " <<
- "n (i." << aname << " ().end ());" << endl
- << "b != n; ++b)"
- << "{"
+ if (!ordered)
+ os << "for (" << scope << "::" << econst_iterator (a) << endl
+ << "b (i." << aname << " ().begin ()), " <<
+ "n (i." << aname << " ().end ());" << endl
+ << "b != n; ++b)";
+
+ os << "{"
<< "e.appendChild (" << endl
<< "e.getOwnerDocument ()->importNode (" << endl
<< "const_cast< " << xerces_ns <<
- "::DOMElement* > (&(*b)), true));"
- << "}";
+ "::DOMElement* > (&(" <<
+ (ordered ? (L"i." + aname + L" ()[b->index]") : L"*b") <<
+ ")), true));";
}
else if (min (a) == 0)
{
// optional
//
- os << "if (i." << aname << " ())"
- << "{"
+ if (!ordered)
+ os << "if (i." << aname << " ())";
+
+ os << "{"
<< "e.appendChild (" << endl
<< "e.getOwnerDocument ()->importNode (" << endl
<< "const_cast< " << xerces_ns << "::DOMElement* > (&(*i." <<
- aname << " ())), true));"
- << "}";
+ aname << " ())), true));";
}
else
{
// one
//
+ if (ordered)
+ os << "{";
+
os << "e.appendChild (" << endl
<< "e.getOwnerDocument ()->importNode (" << endl
<< "const_cast< " << xerces_ns << "::DOMElement* > (&(i." <<
aname << " ())), true));"
<< endl;
}
+
+ if (ordered)
+ {
+ // See comment for bool text (false); below.
+ //
+ if (mixed_p (c) && c.context ().get<size_t> ("ordered-start") != 1)
+ os << "text = true;";
+
+ os << "continue;";
+ }
+
+ if (ordered || max (a) != 1 || min (a) == 0)
+ os << "}";
}
private:
@@ -702,6 +760,8 @@ namespace CXX
virtual void
traverse (Type& c)
{
+ SemanticGraph::Context& ctx (c.context ());
+
String name (ename (c));
// If renamed name is empty then we do not need to generate
@@ -740,22 +800,107 @@ namespace CXX
}
{
+ bool o (ordered_p (c));
+ size_t start, count;
+
+ if (o)
+ {
+ start = ctx.get<size_t> ("ordered-start");
+ count = ctx.get<size_t> ("ordered-count");
+
+ if (start != count)
+ {
+ String const& ci (ctx.get<String> ("order-const-iterator"));
+ String const& an (ctx.get<String> ("order-aname"));
+
+ // If we have mixed content and a base, then we have to
+ // skip the text content until we serialize one of "our"
+ // elements.
+ //
+ if (mixed_p (c) && start != 1)
+ os << "bool text (false);"
+ << endl;
+
+ os << "for (" << name << "::" << ci << endl
+ << "b (i." << an << " ().begin ()), n (i." << an <<
+ " ().end ());" << endl
+ << "b != n; ++b)"
+ << "{"
+ << "switch (b->id)"
+ << "{";
+ }
+ }
+
Traversal::Names names;
Any any (*this, name);
Element element (*this, name);
- Attribute attribute (*this, name);
names >> element;
- names >> attribute;
if (options.generate_wildcard ())
names >> any;
Complex::names (c, names);
+
+ if (o)
+ {
+ if (start != count)
+ {
+ if (mixed_p (c))
+ {
+ //@@ propagate mixed-ordered-id to derived
+
+ os << "// text_content" << endl
+ << "//" << endl
+ << "case " << name << "::" <<
+ ctx.get<String> ("mixed-ordered-id-name") << ":"
+ << "{";
+
+ // See the comment above.
+ //
+ if (start != 1)
+ os << "if (text)" << endl;
+
+ os << "e.appendChild (" << endl
+ << "e.getOwnerDocument ()->createTextNode (" << endl
+ << "::xsd::cxx::xml::string (" << endl
+ << "i." << ctx.get<String> ("mixed-aname") <<
+ " ()[b->index].c_str ()).c_str ()));";
+
+ // os << "e << i." << ctx.get<String> ("mixed-aname") <<
+ // " ()[b->index];";
+
+ os << "continue;"
+ << "}";
+ }
+
+ // Ignore content before our id range and stop serializing
+ // if we see anything past. This handles inheritance.
+ //
+ os << "default:"
+ << "{";
+
+ if (start != 1)
+ os << "if (b->id < " << start << "UL)" << endl
+ << "continue;";
+
+ os << "break;" // Stop (see break below).
+ << "}";
+
+ os << "}" // switch
+ << "break;" // Unknown element past our elements.
+ << "}"; // for
+ }
+ }
}
- os << "}";
+ {
+ Attribute attribute (*this, name);
+ Traversal::Names names (attribute);
+ Complex::names (c, names);
+ }
+ os << "}";
bool simple (true);
{
diff --git a/xsd/cxx/tree/tree-header.cxx b/xsd/cxx/tree/tree-header.cxx
index 83a2d1f..e6c2411 100644
--- a/xsd/cxx/tree/tree-header.cxx
+++ b/xsd/cxx/tree/tree-header.cxx
@@ -1076,7 +1076,7 @@ namespace CXX
}
bool def_attr (m.default_p () &&
- m.is_a<SemanticGraph::Attribute> ());
+ m.is_a<SemanticGraph::Attribute> ());
if (max (m) != 1)
{
@@ -1784,6 +1784,9 @@ namespace CXX
if (skip (m))
return;
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (m.scope ()));
+
String const& type (etype (m));
bool el (m.is_a<SemanticGraph::Element> ());
@@ -1826,7 +1829,7 @@ namespace CXX
else
{
os << "// " << comment (m.name ()) << endl
- << "// " << endl;
+ << "//" << endl;
}
// Typedefs.
@@ -1872,7 +1875,7 @@ namespace CXX
<< " */" << endl;
}
- // IntelliSense does not not like aliases and fully-qualified
+ // IntelliSense does not like aliases and fully-qualified
// names here.
//
if (!isense)
@@ -1941,6 +1944,24 @@ namespace CXX
os << " > " << etraits (m) << ";"
<< endl;
+
+ // Element id.
+ //
+ if (el && ordered_p (c))
+ {
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Element id used for capturing content " <<
+ "order." << endl
+ << " */" << endl;
+
+ SemanticGraph::Context& ctx (m.context ());
+
+ os << "static const ::std::size_t " <<
+ ctx.get<String> ("ordered-id-name") << " = " <<
+ ctx.get<size_t> ("ordered-id") << "UL;" << endl;
+ }
+
member_function_.traverse (m);
if (doxygen)
@@ -1970,6 +1991,9 @@ namespace CXX
virtual void
traverse (SemanticGraph::Any& a)
{
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (a.scope ()));
+
if (doxygen)
{
os << "/**" << endl
@@ -1990,7 +2014,7 @@ namespace CXX
else
{
os << "// " << ename (a) << endl
- << "// " << endl;
+ << "//" << endl;
}
// Typedefs.
@@ -2060,6 +2084,23 @@ namespace CXX
os << endl;
}
+ // Wildcard id.
+ //
+ if (ordered_p (c))
+ {
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Wildcard id used for capturing content " <<
+ "order." << endl
+ << " */" << endl;
+
+ SemanticGraph::Context& ctx (a.context ());
+
+ os << "static const ::std::size_t " <<
+ ctx.get<String> ("ordered-id-name") << " = " <<
+ ctx.get<size_t> ("ordered-id") << "UL;" << endl;
+ }
+
any_function_.traverse (a);
if (doxygen)
@@ -2095,7 +2136,7 @@ namespace CXX
else
{
os << "// " << ename (a) << endl
- << "// " << endl;
+ << "//" << endl;
}
if (doxygen)
@@ -2288,6 +2329,8 @@ namespace CXX
if (renamed_type (c, name) && !name)
return;
+ SemanticGraph::Context& ctx (c.context ());
+
bool has_members (has<Traversal::Member> (c));
bool hae (has<Traversal::Any> (c));
@@ -2295,6 +2338,9 @@ namespace CXX
bool gen_wildcard (options.generate_wildcard ());
+ bool mixed (mixed_p (c) && !ctx.count ("mixed-in-base"));
+ bool ordered (ordered_p (c) && !ctx.count ("order-in-base"));
+
bool simple (true);
{
IsSimpleType t (simple);
@@ -2344,18 +2390,149 @@ namespace CXX
//
names (c, names_);
- // dom_document accessors.
+ // Mixed content.
//
- if (edom_document_member_p (c))
+ if (mixed)
{
+ String const& type (ctx.get<String> ("mixed-type"));
+ String const& cont (ctx.get<String> ("mixed-container"));
+ String const& iter (ctx.get<String> ("mixed-iterator"));
+ String const& citer (ctx.get<String> ("mixed-const-iterator"));
- if (!doxygen)
- {
- os << "// DOMDocument for wildcard content." << endl
+ if (doxygen)
+ os << "/**" << endl
+ << " * @name " << comment ("text_content") << endl
+ << " *" << endl
+ << " * @brief Accessor and modifier functions for text " <<
+ "content." << endl
+ << " */" << endl
+ << "//@{" << endl;
+ else
+ os << "// text_content" << endl
<< "//" << endl;
- }
+
+ // Typedefs.
+ //
+ bool isense (options.generate_intellisense ());
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Text content type." << endl
+ << " */" << endl;
+
+ os << "typedef " << xs_string_type << " " << type << ";";
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Text content sequence container type." << endl
+ << " */" << endl;
+
+ os << "typedef ::xsd::cxx::tree::sequence< " << type <<
+ " > " << cont << ";";
+
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Text content iterator type." << endl
+ << " */" << endl;
+
+ // IntelliSense does not like aliases and fully-qualified
+ // names here.
+ //
+ if (!isense)
+ os << "typedef " << cont << "::iterator " << iter<< ";";
+ else
+ os << "typedef ::xsd::cxx::tree::sequence< " << type <<
+ " >::iterator " << iter << ";";
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Text content constant iterator type." << endl
+ << " */" << endl;
+
+ if (!isense)
+ os << "typedef " << cont << "::const_iterator " << citer<< ";";
+ else
+ os << "typedef ::xsd::cxx::tree::sequence< " << type <<
+ " >::const_iterator " << citer << ";";
+
+ os << endl;
+
+ // Content id.
+ //
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Text content id used for capturing content " <<
+ "order." << endl
+ << " */" << endl;
+
+ os << "static const ::std::size_t " <<
+ ctx.get<String> ("mixed-ordered-id-name") << " = " <<
+ ctx.get<size_t> ("mixed-ordered-id") << "UL;" << endl;
+
+ // Accessors and modifiers.
+ //
+ String const& aname (ctx.get<String> ("mixed-aname"));
+ String const& mname (ctx.get<String> ("mixed-mname"));
+
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Return a read-only (constant) reference " <<
+ "to the text" << endl
+ << " * content sequence." << endl
+ << " *" << endl
+ << " * @return A constant reference to the sequence " <<
+ "container." << endl
+ << " */" << endl;
+
+ os << "const " << cont << "&" << endl
+ << aname << " () const;"
+ << endl;
+
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Return a read-write reference to the " <<
+ "text content" << endl
+ << " * sequence." << endl
+ << " *" << endl
+ << " * @return A reference to the sequence container." << endl
+ << " */" << endl;
+
+ os << cont << "&" << endl
+ << aname << " ();"
+ << endl;
+
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Copy elements from a given sequence." << endl
+ << " *" << endl
+ << " * @param s A sequence to copy entries from." << endl
+ << " *" << endl
+ << " * For each element in @a s this function " <<
+ "add it to the sequence." << endl
+ << " * Note that this operation " <<
+ "completely changes the sequence and" << endl
+ << " * all old elements will be lost." << endl
+ << " */" << endl;
+
+ os << "void" << endl
+ << mname << " (const " << cont << "& s);"
+ << endl;
if (doxygen)
+ os << "//@}" << endl
+ << endl;
+ }
+
+ // dom_document accessors.
+ //
+ if (edom_document_member_p (c))
+ {
+ if (doxygen)
{
os << "/**" << endl
<< " * @brief Return a read-only (constant) reference " <<
@@ -2369,6 +2546,9 @@ namespace CXX
<< " * the raw XML content corresponding to wildcards." << endl
<< " */" << endl;
}
+ else
+ os << "// DOMDocument for wildcard content." << endl
+ << "//" << endl;
os << "const " << xerces_ns << "::DOMDocument&" << endl
<< edom_document (c) << " () const;"
@@ -2393,6 +2573,137 @@ namespace CXX
<< endl;
}
+ // Order container.
+ //
+ if (ordered)
+ {
+ String const& type (ctx.get<String> ("order-type"));
+ String const& cont (ctx.get<String> ("order-container"));
+ String const& iter (ctx.get<String> ("order-iterator"));
+ String const& citer (ctx.get<String> ("order-const-iterator"));
+
+ String const ct (options.order_container_specified ()
+ ? options.order_container ()
+ : "::std::vector");
+
+ if (doxygen)
+ os << "/**" << endl
+ << " * @name " << comment ("content_order") << endl
+ << " *" << endl
+ << " * @brief Accessor and modifier functions for content " <<
+ "order." << endl
+ << " */" << endl
+ << "//@{" << endl;
+ else
+ os << "// content_order" << endl
+ << "//" << endl;
+
+ // Typedefs.
+ //
+ bool isense (options.generate_intellisense ());
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Content order entry type." << endl
+ << " */" << endl;
+
+ os << "typedef " << ns_name (xs_ns ()) << "::" <<
+ xs_ns ().context ().get<String> ("content-order") << " " <<
+ type << ";";
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Content order sequence container type." << endl
+ << " */" << endl;
+
+ os << "typedef " << ct << "< " << type << " > " << cont << ";";
+
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Content order iterator type." << endl
+ << " */" << endl;
+
+ // IntelliSense does not like aliases and fully-qualified
+ // names here.
+ //
+ if (!isense)
+ os << "typedef " << cont << "::iterator " << iter<< ";";
+ else
+ os << "typedef " << ct << "< " << type << " >::iterator " <<
+ iter << ";";
+
+ if (doxygen)
+ os << endl
+ << "/**" << endl
+ << " * @brief Content order constant iterator type." << endl
+ << " */" << endl;
+
+ if (!isense)
+ os << "typedef " << cont << "::const_iterator " << citer<< ";";
+ else
+ os << "typedef " << ct << "< " << type <<
+ " >::const_iterator " << citer << ";";
+
+ os << endl;
+
+ // Accessors and modifiers.
+ //
+ String const& aname (ctx.get<String> ("order-aname"));
+ String const& mname (ctx.get<String> ("order-mname"));
+
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Return a read-only (constant) reference " <<
+ "to the content" << endl
+ << " * order sequence." << endl
+ << " *" << endl
+ << " * @return A constant reference to the sequence " <<
+ "container." << endl
+ << " */" << endl;
+
+ os << "const " << cont << "&" << endl
+ << aname << " () const;"
+ << endl;
+
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Return a read-write reference to the " <<
+ "content order" << endl
+ << " * sequence." << endl
+ << " *" << endl
+ << " * @return A reference to the sequence container." << endl
+ << " */" << endl;
+
+ os << cont << "&" << endl
+ << aname << " ();"
+ << endl;
+
+ if (doxygen)
+ os << "/**" << endl
+ << " * @brief Copy elements from a given sequence." << endl
+ << " *" << endl
+ << " * @param s A sequence to copy entries from." << endl
+ << " *" << endl
+ << " * For each element in @a s this function " <<
+ "add it to the sequence." << endl
+ << " * Note that this operation " <<
+ "completely changes the sequence and" << endl
+ << " * all old elements will be lost." << endl
+ << " */" << endl;
+
+ os << "void" << endl
+ << mname << " (const " << cont << "& s);"
+ << endl;
+
+ if (doxygen)
+ os << "//@}" << endl
+ << endl;
+ }
+
if (doxygen)
{
os << "/**" << endl
@@ -3042,7 +3353,7 @@ namespace CXX
// Data members and implementation functions.
//
- if (has_members || hae || (haa && gen_wildcard))
+ if (has_members || hae || (haa && gen_wildcard) || ordered || mixed)
{
os << "// Implementation." << endl
<< "//" << endl;
@@ -3052,9 +3363,10 @@ namespace CXX
<< "//@cond" << endl
<< endl;
- if (!options.suppress_parsing ())
+ if (!options.suppress_parsing () &&
+ (has_members || hae || (haa && gen_wildcard) || mixed))
{
- // parse (xercesc::DOMElement)
+ // parse ()
//
os << "protected:" << endl
<< "void" << endl
@@ -3082,7 +3394,7 @@ namespace CXX
}
}
- //
+ // DOM document.
//
if (edom_document_member_p (c))
{
@@ -3091,6 +3403,24 @@ namespace CXX
<< endl;
}
+ // Mixed text content.
+ //
+ if (mixed)
+ {
+ os << ctx.get<String> ("mixed-container") << " " <<
+ ctx.get<String> ("mixed-member") << ";"
+ << endl;
+ }
+
+ // Order container.
+ //
+ if (ordered)
+ {
+ os << ctx.get<String> ("order-container") << " " <<
+ ctx.get<String> ("order-member") << ";"
+ << endl;
+ }
+
//
//
names (c, names_data_);
@@ -3811,6 +4141,15 @@ namespace CXX
if (ctx.std >= cxx_version::cxx11)
ctx.os << "#include <utility> // std::move" << endl;
+ if (!ctx.options.ordered_type ().empty () ||
+ ctx.options.ordered_type_all ())
+ {
+ ctx.os << "#include <cstddef> // std::size_t" << endl;
+
+ if (!ctx.options.order_container_specified ())
+ ctx.os << "#include <vector>" << endl;
+ }
+
ctx.os << endl;
if (ctx.char_type == L"char" && ctx.char_encoding != L"custom")
diff --git a/xsd/cxx/tree/tree-inline.cxx b/xsd/cxx/tree/tree-inline.cxx
index 1c01e5a..e6ed756 100644
--- a/xsd/cxx/tree/tree-inline.cxx
+++ b/xsd/cxx/tree/tree-inline.cxx
@@ -891,6 +891,41 @@ namespace CXX
Complex::names (c, names);
+ // Mixed text content.
+ //
+ if (mixed_p (c) && !c.context ().count ("mixed-in-base"))
+ {
+ SemanticGraph::Context& ctx (c.context ());
+
+ String const& cont (ctx.get<String> ("mixed-container"));
+ String const& memb (ctx.get<String> ("mixed-member"));
+
+ String const& aname (ctx.get<String> ("mixed-aname"));
+ String const& mname (ctx.get<String> ("mixed-mname"));
+
+ os << inl
+ << "const " << name << "::" << cont << "& " <<
+ name << "::" << endl
+ << aname << " () const"
+ << "{"
+ << "return this->" << memb << ";"
+ << "}";
+
+ os << inl
+ << name << "::" << cont << "& " << name << "::" << endl
+ << aname << " ()"
+ << "{"
+ << "return this->" << memb << ";"
+ << "}";
+
+ os << inl
+ << "void " << name << "::" << endl
+ << mname << " (const " << cont << "& s)"
+ << "{"
+ << "this->" << memb << " = s;"
+ << "}";
+ }
+
// dom_document accessors.
//
if (edom_document_member_p (c))
@@ -900,14 +935,49 @@ namespace CXX
name << "::" << endl
<< edom_document (c) << " () const"
<< "{"
- << "return *" << edom_document_member (c) << ";"
+ << "return *this->" << edom_document_member (c) << ";"
<< "}";
os << inl
<< xerces_ns << "::DOMDocument& " << name << "::" << endl
<< edom_document (c) << " ()"
<< "{"
- << "return *" << edom_document_member (c) << ";"
+ << "return *this->" << edom_document_member (c) << ";"
+ << "}";
+ }
+
+ // Order container.
+ //
+ if (ordered_p (c) && !c.context ().count ("order-in-base"))
+ {
+ SemanticGraph::Context& ctx (c.context ());
+
+ String const& cont (ctx.get<String> ("order-container"));
+ String const& memb (ctx.get<String> ("order-member"));
+
+ String const& aname (ctx.get<String> ("order-aname"));
+ String const& mname (ctx.get<String> ("order-mname"));
+
+ os << inl
+ << "const " << name << "::" << cont << "& " <<
+ name << "::" << endl
+ << aname << " () const"
+ << "{"
+ << "return this->" << memb << ";"
+ << "}";
+
+ os << inl
+ << name << "::" << cont << "& " << name << "::" << endl
+ << aname << " ()"
+ << "{"
+ << "return this->" << memb << ";"
+ << "}";
+
+ os << inl
+ << "void " << name << "::" << endl
+ << mname << " (const " << cont << "& s)"
+ << "{"
+ << "this->" << memb << " = s;"
<< "}";
}
diff --git a/xsd/cxx/tree/tree-source.cxx b/xsd/cxx/tree/tree-source.cxx
index 036f7ae..110cb25 100644
--- a/xsd/cxx/tree/tree-source.cxx
+++ b/xsd/cxx/tree/tree-source.cxx
@@ -693,6 +693,9 @@ namespace CXX
if (skip (e))
return;
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (e.scope ()));
+
String const& member (emember (e));
String tr (etraits (e)); // traits type name
@@ -849,6 +852,27 @@ namespace CXX
}
}
+ // Capture order.
+ //
+ if (ordered_p (c))
+ {
+ SemanticGraph::Context& ctx (c.context ());
+
+ String const& t (ctx.get<String> ("order-type"));
+ String const& m (ctx.get<String> ("order-member"));
+
+ os << "this->" << m << ".push_back (" << endl
+ << t << " (" <<
+ e.context ().get<String> ("ordered-id-name");
+
+ // sequence
+ //
+ if (max (e) != 1)
+ os << ", " << "this->" << member << ".size () - 1";
+
+ os << "));";
+ }
+
os << "continue;";
// End of check block.
@@ -920,10 +944,11 @@ namespace CXX
{
String const& member (emember (a));
+ SemanticGraph::Complex& c (
+ dynamic_cast<SemanticGraph::Complex&> (a.scope ()));
+
String const& ns (a.definition_namespace ().name ());
- String const& dom_doc (
- edom_document (
- dynamic_cast<SemanticGraph::Complex&> (a.scope ())));
+ String const& dom_doc (edom_document (c));
os << "// " << ename (a) << endl
<< "//" << endl
@@ -1004,7 +1029,7 @@ namespace CXX
{
// sequence
//
- os << "this->" << member << " .push_back (r);";
+ os << "this->" << member << ".push_back (r);";
}
else if (min (a) == 0)
{
@@ -1019,6 +1044,31 @@ namespace CXX
os << "this->" << member << ".set (r);";
}
+ // Capture order.
+ //
+ if (ordered_p (c))
+ {
+ SemanticGraph::Context& ctx (c.context ());
+
+ String const& t (ctx.get<String> ("order-type"));
+ String const& m (ctx.get<String> ("order-member"));
+
+ os << "this->" << m << ".push_back (" << endl
+ << t << " (" <<
+ a.context ().get<String> ("ordered-id-name") << ", ";
+
+ if (max (a) != 1)
+ // sequence
+ //
+ os << "this->" << member << ".size () - 1";
+ else
+ // optional & one
+ //
+ os << "0";
+
+ os << "));";
+ }
+
os << "continue;";
// End of check block.
@@ -2042,6 +2092,9 @@ namespace CXX
virtual void
traverse (SemanticGraph::Complex& c)
{
+ if (mixed_p (c) && !c.context ().count ("mixed-in-base"))
+ has_el_ = true;
+
names (c);
if (!(has_el_ && has_at_))
@@ -2232,6 +2285,11 @@ namespace CXX
if (renamed_type (c, name) && !name)
return;
+ SemanticGraph::Context& ctx (c.context ());
+
+ bool mixed (mixed_p (c) && !ctx.count ("mixed-in-base"));
+ bool ordered (ordered_p (c) && !ctx.count ("order-in-base"));
+
bool string_based (false);
{
IsStringBasedType t (string_based);
@@ -2348,6 +2406,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
names (c, default_ctor_init_names_);
os << "{";
@@ -2403,6 +2467,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
names (c, ctor_names_);
os << "{";
@@ -2437,6 +2507,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
{
CtorMember t (*this, at);
Traversal::Names n (t);
@@ -2481,6 +2557,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
{
CtorMember t (*this, at);
Traversal::Names n (t);
@@ -2529,6 +2611,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
names (c, ctor_names_);
os << "{";
@@ -2568,6 +2656,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
{
CtorMember t (*this, at);
Traversal::Names n (t);
@@ -2616,6 +2710,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
{
CtorMember t (*this, at);
Traversal::Names n (t);
@@ -2673,6 +2773,8 @@ namespace CXX
" > ())";
}
+ // Cannot be mixed.
+
names (c, ctor_names_);
os << "{";
@@ -2714,6 +2816,8 @@ namespace CXX
" > ())";
}
+ // Cannot be mixed.
+
names (c, ctor_names_);
os << "{";
@@ -2752,6 +2856,8 @@ namespace CXX
" > ())";
}
+ // Cannot be mixed.
+
names (c, ctor_names_);
os << "{";
@@ -2795,6 +2901,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
names (c, ctor_names_);
os << "{";
@@ -2839,6 +2951,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
{
CtorMember t (*this, at);
Traversal::Names n (t);
@@ -2892,6 +3010,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
{
CtorMember t (*this, at);
Traversal::Names n (t);
@@ -2926,6 +3050,20 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ String const& m (ctx.get<String> ("mixed-member"));
+ os << "," << endl
+ << " " << m << " (x." << m << ", f, this)";
+ }
+
+ if (ordered)
+ {
+ String const& m (ctx.get<String> ("order-member"));
+ os << "," << endl
+ << " " << m << " (x." << m << ")";
+ }
+
{
CopyAny copy_any (*this, "x");
CopyMember copy_member (*this, "x");
@@ -2964,7 +3102,7 @@ namespace CXX
<< container << "* c)" << endl
<< ": " << base << " (e, f";
- if (he || ha || hae || (haa && gen_wildcard))
+ if (he || ha || hae || (haa && gen_wildcard) || mixed)
os << " | " << flags_type << "::base";
os << ", c)";
@@ -2977,6 +3115,12 @@ namespace CXX
" > ())";
}
+ if (mixed)
+ {
+ os << "," << endl
+ << " " << ctx.get<String> ("mixed-member") << " (this)";
+ }
+
names (c, element_ctor_names_);
os << "{";
@@ -2988,9 +3132,9 @@ namespace CXX
bool base_has_el (false), base_has_at (false);
// We are only interested in this information if we are
- // generating out own parse().
+ // generating our own parse().
//
- if (he || ha || hae || (haa && gen_wildcard))
+ if (he || ha || hae || (haa && gen_wildcard) || mixed)
{
if (c.inherits_p ())
{
@@ -2999,13 +3143,14 @@ namespace CXX
}
}
- //@@ throw if p is no exhausted at the end.
+ //@@ Throw if p is not exhausted at the end.
//
- if (he || ha || hae || (haa && gen_wildcard))
+ if (he || ha || hae || (haa && gen_wildcard) || mixed)
os << "if ((f & " << flags_type << "::base) == 0)"
<< "{"
<< parser_type << " p (e, " <<
- (he || hae || base_has_el ? "true, " : "false, ") <<
+ (he || hae || base_has_el || mixed_p (c) ? "true, " : "false, ") <<
+ (mixed_p (c) ? "true, " : "false, ") <<
(ha || (haa && gen_wildcard) || base_has_at ? "true" : "false")
<< ");"
<< "this->" << unclash (name, "parse") << " (p, f);"
@@ -3051,7 +3196,7 @@ namespace CXX
os << "}";
}
- if (he || ha || hae || (haa && gen_wildcard))
+ if (he || ha || hae || (haa && gen_wildcard) || mixed)
{
os << "void " << name << "::" << endl
<< unclash (name, "parse") << " (" <<
@@ -3066,17 +3211,45 @@ namespace CXX
os << "this->" << base << "::parse (p, f);"
<< endl;
- if (he || hae)
+ if (he || hae || mixed_p (c))
{
- os << "for (; p.more_elements (); p.next_element ())"
- << "{"
- << "const " << xerces_ns << "::DOMElement& i (" <<
- "p.cur_element ());"
- << "const " << qname_type << " n (" << endl
- << "::xsd::cxx::xml::dom::name< " << char_type << " > (i));"
- << endl;
+ bool m (mixed_p (c));
+
+ os << "for (; p.more_content (); p.next_content (" <<
+ (m ? "true" : "false") << "))"
+ << "{";
- names (c, names_element_);
+ if (m)
+ {
+ String const& ma (ctx.get<String> ("mixed-aname"));
+ String const& mi (ctx.get<String> ("mixed-ordered-id-name"));
+ String const& oa (ctx.get<String> ("order-aname"));
+ String const& ot (ctx.get<String> ("order-type"));
+
+ os << "if (p.cur_is_text ())"
+ << "{"
+ << "const " << xerces_ns << "::DOMText& t (" <<
+ "p.cur_text ());"
+ << "this->" << ma << " ().push_back (" << endl
+ << "::xsd::cxx::xml::transcode<" << char_type << "> (" <<
+ "t.getData (), t.getLength ()));"
+ << "this->" << oa << " ().push_back (" << endl
+ << ot << " (" << mi << "," << endl
+ << "this->" << ma << " ().size () - 1));"
+ << "continue;"
+ << "}";
+ }
+
+ if (he || hae)
+ {
+ os << "const " << xerces_ns << "::DOMElement& i (" <<
+ "p.cur_element ());"
+ << "const " << qname_type << " n (" << endl
+ << "::xsd::cxx::xml::dom::name< " << char_type << " > (i));"
+ << endl;
+
+ names (c, names_element_);
+ }
os << "break;"
<< "}";
@@ -3152,7 +3325,23 @@ namespace CXX
// Note that here we don't assign the DOMDocument that is
// used to hold wildcard fragments. Each document has its
// own copy.
+
+ // Mixed text content.
//
+ if (mixed)
+ {
+ String const& m (ctx.get<String> ("mixed-member"));
+ os << "this->" << m << " = x." << m << ";";
+ }
+
+ // Order container.
+ //
+ if (ordered)
+ {
+ String const& m (ctx.get<String> ("order-member"));
+ os << "this->" << m << " = x." << m << ";";
+ }
+
names (c, assign_names_);
os << "}"
@@ -3203,7 +3392,7 @@ namespace CXX
// Comparison operators.
//
if (options.generate_comparison () &&
- (he || ha || !c.inherits_p () ||
+ (he || ha || mixed || ordered || !c.inherits_p () ||
((hae || haa) && gen_wildcard)))
{
bool base_comp (false);
@@ -3214,8 +3403,8 @@ namespace CXX
test.dispatch (c.inherits ().base ());
}
- bool has_body (he || ha || base_comp ||
- ((hae || haa) && gen_wildcard));
+ bool has_body (he || ha || ordered || mixed || base_comp ||
+ ((hae || haa) && gen_wildcard));
os << "bool" << endl
<< "operator== (const " << name << "&" <<
@@ -3233,6 +3422,22 @@ namespace CXX
Complex::names (c, comparison_names_);
}
+ if (mixed)
+ {
+ String const& an (ctx.get<String> ("mixed-aname"));
+ os << "if (!(x." << an << " () == y." << an << " ()))" << endl
+ << "return false;"
+ << endl;
+ }
+
+ if (ordered)
+ {
+ String const& an (ctx.get<String> ("order-aname"));
+ os << "if (!(x." << an << " () == y." << an << " ()))" << endl
+ << "return false;"
+ << endl;
+ }
+
os << "return true;"
<< "}";
diff --git a/xsd/makefile b/xsd/makefile
index 06ea02c..d57022d 100644
--- a/xsd/makefile
+++ b/xsd/makefile
@@ -31,6 +31,7 @@ cxx_tun += cxx/tree/elements.cxx \
cxx/tree/validator.cxx \
cxx/tree/counter.cxx \
cxx/tree/name-processor.cxx \
+ cxx/tree/order-processor.cxx \
cxx/tree/polymorphism-processor.cxx \
cxx/tree/default-value.cxx \
cxx/tree/generator.cxx \
@@ -114,6 +115,7 @@ endif
$(gen): cli := $(cli)
$(gen): cli_options += \
-I $(src_base) \
+--generate-specifier \
--ostream-type ::std::wostream \
--exclude-base \
--suppress-undocumented \
diff --git a/xsd/options-parser.hxx b/xsd/options-parser.hxx
index 10456e1..0f370cd 100644
--- a/xsd/options-parser.hxx
+++ b/xsd/options-parser.hxx
@@ -14,8 +14,9 @@ namespace cli
struct parser<NarrowString>
{
static void
- parse (NarrowString& x, scanner& s)
+ parse (NarrowString& x, bool& xs, scanner& s)
{
+ xs = true;
const char* o (s.next ());
if (s.more ())