2
votes

I want to write XML Schema for XML file:

<root>
    <rate>10</rate>
    <rate></rate>
    <rate>15</rate>
    ...
</root>

<rate> minOccurs is 1, maxOccurs is unbounded. <rate> must have xs:integer type, but what to do with <rate></rate>? I don't want to write <rate xsi:nil="true"/>.

3

3 Answers

4
votes

Rather than one <rate> element with an xs:integer content, and another one without any content, you can only declare one <rate> element that accepts any integer value or nothing as its contents.

Practically, this can be done with the <xs:union> element:

<xs:simpleType name="emptyString">
  <xs:restriction base="xs:string">
    <xs:maxLength value="0"/>
  </xs:restriction>
</xs:simpleType>

<xs:element name="rate">
    <xs:simpleType>
        <xs:union memberTypes="xs:integer emptyString"/>
    </xs:simpleType>
</xs:element>

This will accept <rate/>, <rate></rate>, <rate>42</rate> (or any other xs:integer value), but not <rate>Hello, World!</rate>.

Note that for this to work, you must have set your prefix-less namespace in the schema to the same as your target namespace, or otherwise, emptyString in the memberTypes attribute will not be found. (Of course, you can instead also define a prefix for your target namespace and use that.)

I have omitted any explanations on how to write the complete schema and how to use maxOccurs etc. because from your question I figure you already know how to do that. Please let me know if you need any further information on this.

1
votes

An alternative to O.R.Mapper's approach is to declare the type of the element as a list of integers with maxLength=1.

<xs:element name="rate">
    <xs:simpleType>
       <xs:restriction base="listOfInteger">
          <xs:maxLength value="1"/>
       </xs:restriction>
    </xs:simpleType>
</xs:element>

<xs:simpleType name="listOfInteger">
  <xs:list itemType="xs:integer"/>
</xs:simpleType>

I tend to prefer this approach to using a union of (integer, zero-length-string) as it's easier to handle in schema-aware XQuery and XSLT applications. It might also work better if you are using data binding using JAXB, I don't know.

0
votes

I would write the XML schema as you intend it to be used. Since you will be using a C++ code generator this will make things much easier (I'm the EclipseLink JAXB (MOXy) lead, so I have experience with this on the Java side).

<xs:element name="root">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="rate" type="xs:integer" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

Since you anticipate receiving invalid data, you have the following options:

  1. Your object-to-XML solution will handle this invalid data for you automatically in a desired way. JAXB for example is designed to be tolerant of bad data.
  2. Your object-to-XML solution provides you a mechanism to handle bad data that you can leverage to solve your problem. JAXB for example provides the ValidationEventHandler mechanism.