1
votes

We have an xml file that looks as follows. Note that our application supports all 3 of these cases:

<quantities>
  <quantity>8</quantity> <!-- case 1 -->
  <quantity></quantity>  <!-- case 2 -->
  <quantity/>            <!-- case 3 -->
</quantities>

We are now making an XML Schema for our customers to help them validate their files before they send them to our application.

<xs:element name="quantity" type="xs:double"/>

But the above XSD is too simple. It is a good validation for case 1, but it refuses case 2 and 3.

So, we tried to solve this using a custom type. A type that can be both a double but can also an empty string.

<xs:simpleType name="double-or-empty">
  <xs:union memberTypes="xs:double">
    <xs:simpleType>
      <xs:restriction base="xs:string">
        <xs:enumeration value=""/>
      </xs:restriction>
    </xs:simpleType>
  </xs:union>
</xs:simpleType>

<xs:element name="quantity" type="double-or-empty"/>

From a functional point, this is clearly an improvement, but it has its shortcomings. When we generate our java classes with java's xjc.exe tool. Then java will use a String to represent these fields. Which is very annoying. What we actually hoped for were (nullable) java.lang.Double fields.

An idea that we played with: To make an xsd file that marks this field as nillable.

<xs:element name="quantity" type="xs:double" nillable="true"/>

We learned that this still does not support case 2 and 3. This just adds 1 more case to it:

<quantities>
  <quantity xs:nil="true"/>
</quantities>

Multiple sources indicate that the use of xs:nil can break interoperability though. Then other sources claim that we should use a custom attribute e.g. <quantity null="true"/> These kinds of ideas are useless anyway because they force us to change an XML format that we have been using for a long time.

So, is there a way to keep the original format, and to steer the XJC tool to use Doubles here?

2

2 Answers

0
votes

Use xs:union to combine an empty string constraint with another constraint such as xs:double:

  <xs:simpleType name="double-or-empty">
    <xs:union>
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:length value="0"/>
        </xs:restriction>
      </xs:simpleType>
      <xs:simpleType>
        <xs:restriction base="xs:double"/>
      </xs:simpleType>
    </xs:union>
  </xs:simpleType>
0
votes

On the whole this looks more like an XJC problem than an XSD problem. But if the only way to achieve a solution is to keep trying different ways of defining the data in XSD until you find one that XJC handles better, then you might consider:

  • Declaring quantity with a default value (assuming that <quantity/> and <quantity></quantity> map to a default value and not to NULL or its logical equivalent).

  • Declaring the type of quantity as a list of xs:double values, with the length of the list constrained to be between zero and one. (One could use pattern to define that constraint, but I expect that the minLength and maxLength facets will do better here.)

  • Declaring the type of quantity as a union between xs:double and some type other than string which can accept an empty value. I think we're looking here for a base type which does not seem to XJC to have a lexical space that's a superset of the lexical space of xs:double. Perhaps a union of xs:double and a zero-length string of double? (Does the order matter to XJC? It appears not, since your declaration puts xs:double first, and that of kjhughes puts the empty string first; but I'd try reversing the order in his union, just in case.)

There may be other ways; these are the ones that come most readily to mind (after the ones you and kjhughes have already tried).