[xsd-users] Preserving element order in MusicXML?

Boris Kolpackov boris at codesynthesis.com
Wed May 28 10:03:55 EDT 2008


Hi Mario,

Mario Lang <mlang at delysid.org> writes:

> <measure>
>   <attributes>...</attributess>
>   <note>...</note><note>...</note>
>   <note>...</note><note>...</note>
>   <backup>...</backup>
>   <attributes>...</attributes>
>   <note>...</note>
> </measure>
> 
> would be a valid MusicXML snippet.
> 
> Currently, after xsdcxx serialisation of the above snippet, I get
> sonmething like:
> 
> <measure>
>   <note>...</note><note>...</note>
>   <note>...</note><note>...</note>
>   <note>...</note>
>   <backup>...</backup>
>   <attributes>...</attributess>
>   <attributes>...</attributes>
> </measure>
> 
> which is completely wrong in MusicXML context, since the elements 
> can be thought of like statements in a procedural program, they
> depend on the order of things being preserved.
> 
> [...]
> 
> I am beginning to suspect that this is actually a XML Schema limitation
> or a limitation in xsdcxx that I am hitting here.

This is a limitation of the C++/Tree mapping and it was a conscious
trade-off between ease of use and being able to retain certain
information that is sometimes required (like order). In essence,
C++/Tree mapping flattens the schema model and groups several
occurrences of the same element into a sequence. This works quite
well for data-centric XML vocabularies but sometimes is insufficient
for document-centric ones like XHTML or MusicXML.

There is another mapping, C++/Parser, that by design allows you
to capture the order information. It is, however, only supports
parsing (the serialization-supporting counterpart, C++/Serializer,
is on its way).


> <xs:complexType name="music-data">
>   <xs:sequence>
>     <xs:choice minOccurs="0" maxOccurs="unbounded">
>       <xs:element ref="note" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="backup" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="forward" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="direction" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="attributes" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="harmony" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="figured-bass" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="print" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="sound" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="barline" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="grouping" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="link" minOccurs="0" maxOccurs="unbounded"/>
>       <xs:element ref="bookmark" minOccurs="0" maxOccurs="unbounded"/>
>     </xs:choice>
>   </xs:sequence>
> </xs:complexType>
> <xs:element name="measure" type="music-data"/>
> 
> 
> Is it possible to express a schema for sturcture like above and
> use it with xsdcxx?  If so, what am I missing?

Since you have control over the schema, I can propose an elegant
workaround which will allow you to retain order and use the C++/Tree
mapping. It boils down to using XML Schema substitution groups to
represent various music data elements. Here is an outline:

<xs:complexType name="music-element" abstract="true">
<!-- Here you may want to put common data that each music 
     element must have, if any. -->
</xs:complexType>
<xs:element name="music-element" type="music-element" abstract="true"/>

<xs:complexType name="music-data">
  <xs:sequence>
    <xs:element ref="music-element" minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>
<xs:element name="measure" type="music-data"/>

<!-- define backup, forward, etc., in the same way: -->

<xs:complexType name="note">
  <xs:complexContent>
    <xs:extension base="music-element">
      <xs:sequence>
        ...
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>
<xs:element name="note" type="note" substitutionGroup="music-element"/>

In the OOP terms the above schema says that the music-data type 
contains a sequence of abstract music-element elements each of which
can be note, backup, forward, etc.

Once you compile this schema with the --generate-polymorphic option,
you will get a "polymorphic sequence" of music-element items in
the music-data type. While the static type in this sequence is
music-element, actual objects stored are note, backup, etc. You
can figure out which object it is by using, for example, dynamic_cast.
For more information on working with polymorphic object models
see Section 2.11, "Mapping for xsi:type and Substitution Groups"
in the C++/Tree Mapping Manual:

http://codesynthesis.com/projects/xsd/documentation/cxx/tree/manual/#2.11

Boris




More information about the xsd-users mailing list