Reputation: 93
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?
Upvotes: 9
Views: 25154
Reputation: 25054
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.
Upvotes: 12
Reputation: 1927
I don't think it's possible to validate those elements as xs:dateTime if they are empty. If you had control of the input XML, I would suggest that you could mark up the elements as "nil", and set the element to be nillable in the schema.
Doing so means that this fragment:
<parent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<start reference="a string" xsi:nil="true"/>
<end reference="a string" xsi:nil="true"/>
</parent>
...will validate against this schema:
<?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">
<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" nillable="true"/>
<xs:element minOccurs="0" name="end" type="DateOrRef" nillable="true"/>
</xs:sequence>
</xs:complexType>
<xs:element name="parent" type="parent"/>
</xs:schema>
Without being able to change the input XML, the best I could come up with is using one or more xs:assertion
elements to validate that the string matches the dateTime format, i.e. using the XPath "matches" function.
You could also declare an xs:simpleType
with an xs:restriction
and xs:pattern
that duplicates the validation of an xs:dateTime.
Upvotes: 0