An XML document is something like below:
<person_db> <person id="1"> <fname>john</fname> <lname>backus</lname> <dob>1995-12-10</dob> </person> <person id="2"> <fname>rick</fname> <lname>palmer</lname> <dob>2001-11-09</dob> </person> <person id="3"> <fname>neil</fname> <lname>cooks</lname> <dob>1998-11-10</dob> </person> </person_db>
Other than constraining the XML document to a structure like above, the XSD schema should specify following additional validation constraints, as well:
1) Each person's dob field should specify a date, which must be later than or equal to the date, 1900-01-01.
2) Each "person" element, should be sorted numerically according to "id" attribute, in an ascending fashion.
I wanted to achieve these validation objectives, completely with XSD 1.1 assertions. Here's the XSD 1.1 document, which I find that works fine, with Xerces-J:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="person_db"> <xs:complexType> <xs:sequence> <xs:element name="person" maxOccurs="unbounded" type="Person" /> </xs:sequence> <xs:assert test="every $p in person[position() lt last()] satisfies ($p/@id lt $p/following-sibling::person[1]/@id)" /> </xs:complexType> </xs:element> <xs:complexType name="Person"> <xs:sequence> <xs:element name="fname" type="xs:string" /> <xs:element name="lname" type="xs:string" /> <xs:element name="dob" type="xs:date" /> </xs:sequence> <xs:attribute name="id" type="xs:int" use="required" /> <xs:assert test="dob ge xs:date('1900-01-01')" /> </xs:complexType> </xs:schema>
Notes: It also seems, that above XSD validation requirements could be met, with following changes as well:
1. Remove assertion from the complex type, "Person".
2. Have an additional assertion on the element, "person_db" which will now look something like following:
<xs:assert test="every $p in person[position() lt last()] satisfies
($p/@id lt $p/following-sibling::person[1]/@id)" />
<xs:assert test="every $p in person satisfies ($p/dob ge xs:date('1900-01-01'))" />
i.e, we'll now have two assertions on the element, "person_db" (which are actually specified on the element's schema type).
Though, I seem to like the first solution as it seems elegant to me, and more logically in place.
I am happy, that this particular example worked fine as I expected, with Xerces.
I hope that this post was useful.
3 comments:
Thanks for the helpful post! I'm in a bit of a spot here. I have something like this:
<xs:element name="Clients">
<xs:complexType>
<xs:sequence>
<xs:element ref="Client" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Client">
<xs:complexType>
<xs:sequence>
<xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="ProfileInfo" type="ProfileInfoType" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="ProfileInfoType">
<xs:sequence>
<xs:element name="ProfileUsed" type="ProfileNames" minOccurs="1" maxOccurs="1"/>
<xs:element name="Category" type="CategoryType" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:assert test="((@ProfileUsed eq 'Profile2') or (@ProfileUsed eq 'Profile1' and fn:count(./Category) > 0 ) or (@ProfileUsed eq 'Profile3'))"/>
</xs:complexType>
<xs:simpleType name="ProfileNames">
<xs:restriction base="xs:string">
<xs:enumeration value="Profile1"/>
<xs:enumeration value="Profile2"/>
<xs:enumeration value="Profile3"/>
</xs:restriction>
</xs:simpleType>
Now in my XML instance if I have multiple clients, this assertion works correctly for the first client, but fails for the second client.
Any idea why?
Please ignore the earlier comment. I figured out the problem.
I'm glad, you found the answer.
Post a Comment