[xsd-users] xsdcxx-musicxml

Mario Lang mlang at delysid.org
Mon Dec 8 09:12:16 EST 2014


Hi.

content_order was really what was (mostly) missing for xsdcxx to be
useful to generate a complete MusicXML binding for C++.  Parsing from,
and serializing to a DOM was the other thing that finally helped me to
solve the root element issue[1].  Thanks for these hints!

I have now pushed a project that uses xsdcxx to generate MusicXML bindings to GitHub:

  https://github.com/mlang/xsdcxx-musicxml

I have two outstanding issues to solve which I haven't quite figured out
yet:

 * How do I add a DOCTYPE to a serialized document?  Valid MusicXML documents
   sort of require a DTD to be stated.  Is there some way to tell the
   xsdcxx serializer (a bit like the properties class) that I want a !DOCTYPE to be
   generated as well?  Or do I serialize to a DOM document and somehow
   add the DOCTYPE later (oh how I hate the Xerces-C API!
   fgThisBarelyFitsOnASingleLineEvenThoughItIsJustOneConstant!).

 * More importantly, via schema validation, I have found another element
   in the MusicXML grammar that would require content_order for correct
   serialization.  However, contrary to the two elements which already use
   content_order, this one is not composed of interleaved containers.  Actually,
   every element is an optional.  It is just that xsdcxx somehow gets
   the serialiszation order wrong on output.  Now, to fix this, I have to
   enable content_order for this element, which vastly complicates
   client code for absolutely no reason.  I basically have to find a way
   to re-implement accessors such that content_order is handled.

   1. Do you think we might be able to work on getting xsdcxx to DTRT
      for this particular element type?  (The relevant XSD snippet is below.)

   2. If no, I will have to manually fix this up.  Either by writing all
      the content_order handling code required for this class (quite
      tedious), or, by manually implementing the part of the
      serialization code that is broken.  Second option is
      easier to do.  Is there actually a mechanism in xsdcxx to
      allow for manual override of particular implementations of the .cxx file?
      I.e., lets say I think I am smarter then the XSD compiler, can I
      selectively provide my own implementations?  I know I can edit the
      generated source, but that leads to all sorts of problems, since
      it is, generated :-).

Here is the evil complexType.  Note that it begins with a choice of
sequences, which is what I think gives xsdcxx a headache.
While there is at least one subelement which can be a sequence as well
(dot), all others are just optionals.  It should be possible to get the
serialization order right, since there is no interleaving of containers
possible at all.  I.e., I can have "<dot/><dot/>" but not
"<dot/><tie/><dot/>" or somesuch.  content_order *shouldn't* be
necessary for correct serialization.  The only other special thing about
this complexType is that some of its elements are mutually exclusive.
As the documentation states, "Thus grace notes do not have a duration
element. Cue notes have a duration element, as do forward elements, but
no tie elements." 

i.e., if a note element contains a cue element, it is not allowed to
contain a tie element. And if it contains a grace element, it is not
allowed to contain a duration element.  But these constraints, implied
by the complexType, are more a thing of valid internal state.  If the
input document is valid, and/or the object model has been created in a
valid state in regards to these constraints, serialization code should
just work, and generate a valid document.  Am I missing something (which
is very likely) or have I hit a corner case with xsdcxx here?  Can we
get this fixed?  To see how the manual fix looks, have a look at
743b7056adc0d25cf3a28980e30f58300239d410 in the xsdcxx-musicxml master
branch.

	<xs:complexType name="note">
		<xs:annotation>
			<xs:documentation>Notes are the most common type of MusicXML data. The MusicXML format keeps the MuseData distinction between elements used for sound information and elements used for notation information (e.g., tie is used for sound, tied for notation). Thus grace notes do not have a duration element. Cue notes have a duration element, as do forward elements, but no tie elements. Having these two types of information available can make interchange considerably easier, as some programs handle one type of information much more readily than the other. 

The dynamics and end-dynamics attributes correspond to MIDI 1.0's Note On and Note Off velocities, respectively. They are expressed in terms of percentages of the default forte value (90 for MIDI 1.0). The attack and release attributes are used to alter the starting and stopping time of the note from when it would otherwise occur based on the flow of durations - information that is specific to a performance. They are expressed in terms of divisions, either positive or negative. A note that starts a tie should not have a release attribute, and a note that stops a tie should not have an attack attribute. If a note is played only particular times through a repeat, the time-only attribute shows which times to play the note. The pizzicato attribute is used when just this note is sounded pizzicato, vs. the pizzicato element which changes overall playback between pizzicato and arco.</xs:documentation>
		</xs:annotation>
		<xs:sequence>
			<xs:choice>
				<xs:sequence>
					<xs:element name="grace" type="grace"/>
					<xs:group ref="full-note"/>
					<xs:element name="tie" type="tie" minOccurs="0" maxOccurs="2"/>
				</xs:sequence>
				<xs:sequence>
					<xs:element name="cue" type="empty">
						<xs:annotation>
							<xs:documentation>The cue element indicates the presence of a cue note.</xs:documentation>
						</xs:annotation>
					</xs:element>
					<xs:group ref="full-note"/>
					<xs:group ref="duration"/>
				</xs:sequence>
				<xs:sequence>
					<xs:group ref="full-note"/>
					<xs:group ref="duration"/>
					<xs:element name="tie" type="tie" minOccurs="0" maxOccurs="2"/>
				</xs:sequence>
			</xs:choice>
			<xs:element name="instrument" type="instrument" minOccurs="0"/>
			<xs:group ref="editorial-voice"/>
			<xs:element name="type" type="note-type" minOccurs="0"/>
			<xs:element name="dot" type="empty-placement" minOccurs="0" maxOccurs="unbounded">
				<xs:annotation>
					<xs:documentation>One dot element is used for each dot of prolongation. The placement element is used to specify whether the dot should appear above or below the staff line. It is ignored for notes that appear on a staff space.</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:element name="accidental" type="accidental" minOccurs="0"/>
			<xs:element name="time-modification" type="time-modification" minOccurs="0"/>
			<xs:element name="stem" type="stem" minOccurs="0"/>
			<xs:element name="notehead" type="notehead" minOccurs="0"/>
			<xs:element name="notehead-text" type="notehead-text" minOccurs="0"/>
			<xs:group ref="staff" minOccurs="0"/>
			<xs:element name="beam" type="beam" minOccurs="0" maxOccurs="8"/>
			<xs:element name="notations" type="notations" minOccurs="0" maxOccurs="unbounded"/>
			<xs:element name="lyric" type="lyric" minOccurs="0" maxOccurs="unbounded"/>
			<xs:element name="play" type="play" minOccurs="0"/>
		</xs:sequence>
		<xs:attributeGroup ref="x-position"/>
		<xs:attributeGroup ref="font"/>
		<xs:attributeGroup ref="color"/>
		<xs:attributeGroup ref="printout"/>
		<xs:attribute name="dynamics" type="non-negative-decimal"/>
		<xs:attribute name="end-dynamics" type="non-negative-decimal"/>
		<xs:attribute name="attack" type="divisions"/>
		<xs:attribute name="release" type="divisions"/>
		<xs:attribute name="time-only" type="time-only"/>
		<xs:attribute name="pizzicato" type="yes-no"/>
	</xs:complexType>

[1] MusicXML has two possible root elements, "score-partwise" and
"score-timewise".  Without going too much into detail, a partwise
document has parts at the top level, and measures inside, with all the
musical content inside of these measure elements.  A timewise document
has measure elements at the top level, part elements inside, and all the
music inside of part elements.  Aside from this difference, the
actual content elements are completely identical.  partwise documents
can automatically be converted to timewise documents, and vice
versa. There are XSL Transformations (quite simple) for doing that.
So my final approach to handling polymorphic root elements with MusicXML
is quite different from all the examples I have seen: Since the
transformation can be automated, I plan to just do that on the DOM
directly.  All I have to do is add yet another parsing helper function
which specifies *which* root element the user wants.  If the DOM already
has that root element, we just pass it on to the xsdcxx parsing code,
and if it is the wrong top level element, we apply the DOM
transformation and then pass it on to xsdcxx.  This way, I do not have
to use *any* of the polymorphism features of xsdcxx to handle the fact
that there are two possible root elements.

-- 
CYa,
  ⡍⠁⠗⠊⠕



More information about the xsd-users mailing list