Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define an XSD element which can be a dateTime or empty with an attribute

Tags:

xml

xsd

My question is almost exactly the same as this one, but for a xs:dateTime type rather than a user defined element.

An element in my XML (which I do not create) can look like:

<parent>
    ...
    <start>2012-01-01T00:00:00.000</start>
    <end>2013-01-01T00:00:00.000</end>
    ...
</parent>

-or-

<parent>
    ...
    <start reference="a string" />
    <end reference="a string" />
    ...
</parent>

In other words, within the parent element, the "start" and "end" fields can contain either a xs:dateTime value, or will be empty but have a "reference" attribute (either field might be one or the other within the parent, they're not necessarily both a reference or both a dateTime). I've tried all sorts of ways to represent this in an XSD, but have not found a solution. The closest I've come is (excerpted from a much larger XSD):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="DateOrRef">
    <xs:simpleContent>
<!--      <xs:extension base="xs:dateTime"> This does not validate-->
      <xs:extension base="xs:string">
        <xs:attribute type="xs:string" name="reference" use="optional"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:complexType name="parent">
    <xs:sequence>
        <xs:element minOccurs="0" name="start" type="DateOrRef" />
        <xs:element minOccurs="0" name="end" type="DateOrRef" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

which does validate, but does not restrict the node contents to be an xs:dateTime value. If I change the extension base type to a xs:dateTime instead of xs:string as in the commented out line, the empty elements will no longer validate because the dateTime type is not allowed to be empty.

How could I structure the XSD to validate these fields as xs:dateTime instead of xs:string?

like image 692
Sean Purcell Avatar asked Sep 13 '13 22:09

Sean Purcell


1 Answers

1 You can declare the element nillable (as suggested by Ben).

2 You can declare a simple type which is a union of xs:dateTime and the empty string. This is easiest to follow if we build it up in stages. First, declare a named simple type whose sole value is the empty string:

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

Then declare a union type whose members are xs:dateTime and empty-string:

<xs:simpleType name="dateTime-or-nothing">
  <xs:union memberTypes="xs:dateTime empty-string"/>
</xs:simpleType>

Then use dateTime-or-nothing as the basis for your extension step:

<xs:complexType name="DateOrRef">
  <xs:simpleContent>
    <xs:extension base="dateTime-or-nothing">
      <xs:attribute type="xs:string" 
                    name="reference" 
                    use="optional"/>
    </xs:extension>
  </xs:simpleContent>
</xs:complexType>

If the reference attribute should occur if and only if the element has no content, then you'll need an XSD 1.1 assertion to that effect (or an ancillary Schematron schema, or ad-hoc validation code at the application layer). XSD content models make it easy to say you must have either a dateTime or a reference, but only if each of those options is represented by a child element.

like image 181
C. M. Sperberg-McQueen Avatar answered Sep 28 '22 12:09

C. M. Sperberg-McQueen