Sunday, March 21, 2010

playing again with XSD 1.1 assertions

Some time ago, XSLT folks (including me!) were discussing on XSL-List the design of an XML schema, describing a product catalog. This post has nothing to do with XSLT, except that an earlier discussion on XSL-List enkindled me with yet another XSD schema use-case, to try out the Xerces-J XSD 1.1 assertions implementation. I wrote the following XSD 1.1 schema use-case, with a desire to find out if Xerces-J XSD 1.1 assertion implementation would succeed, for this example (and to cause no surprise to readers, I'm pleased to say, that Xerces passes this example!).

So here goes this example.

XML document:
  <?xml version="1.0" encoding="UTF-8" ?>
  <product id="100">
    <shortname>Sun Press, Java Book</shortname>
    <description>Java Language: Design and Programming</description>
    <author>James Gosling</author>
    <price>
      <value effective="2000-10-10" format="hard cover">25</value>
      <value effective="2005-10-10" format="hard cover">20</value>
      <value effective="2009-10-10" format="pdf" freeware="true">0</value>
    </price>
  </product>
An XSD 1.1 schema validating the above XML document:
  <?xml version="1.0" encoding="UTF-8" ?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

   <xs:complexType name="Product">
     <xs:sequence>
       <xs:element name="shortName">
         <xs:simpleType>
           <xs:restriction base="xs:string">
             <xs:maxLength value="20"/>
           </xs:restriction>
         </xs:simpleType>
       </xs:element>
       <xs:element name="description" type="xs:string"/>
       <xs:element name="author" type="xs:string"/>
       <xs:element name="price">
         <xs:complexType>
           <xs:sequence>
             <xs:element name="value" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:double">
                      <xs:attribute name="effective" type="xs:date" use="required"/>
                      <xs:attribute name="freeware" type="xs:boolean"/>
                      <xs:attribute name="format" use="required">
                        <xs:simpleType>
                          <xs:restriction base="xs:string">
                            <xs:enumeration value="hard cover"/>
                            <xs:enumeration value="pdf"/>
                          </xs:restriction>
                        </xs:simpleType>
                      </xs:attribute>
                      <xs:assert test="@effective lt current-date()" />
                      <xs:assert test="if (@freeware eq true()) then (@format eq 'pdf' and . eq 0)
                                       else true()" />                    
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
             </xs:element>
           </xs:sequence>
           <xs:assert test="every $vl in value[position() lt last()] satisfies
                            ($vl gt $vl/following-sibling::value[1]) and 
                            ($vl/@effective lt $vl/following-sibling::value[1]/@effective)" />
         </xs:complexType>
       </xs:element>
     </xs:sequence>
     <xs:attribute name="ID" type="xs:positiveInteger" use="required"/>
   </xs:complexType>
   
   <xs:element name="product" type="Product"/>

  </xs:schema>

I don't wish to explain in detail the problem domain behind the above XML & XSD documents (I believe, readers familiar with XSD language & XML could easily understand the intent of the above example). In very shortest description, this example "illustrates a simple product catalog, describing a single product".
Here's a short explanation, about what the assertions -- highlighted with a different color (starting from assertion at top, to assertion at bottom) in above schema document are, intending to do:
1. The first assertion is checking, that the value of attribute "effective" (with a schema type, xs:date) is prior to today's date.
2. The second assertion is checking, that if value of attribute "freeware" is a boolean 'true', then value of attribute "format" must be 'pdf' & the numeric value of price should be 0.
3. The third assertion is checking, that price always reduces in future, & the effective date of the price is prior to the next price revision.

I enjoyed writing this example, and I'm glad that this worked with Xerces. The Eclipse/PsychoPath XPath 2.0 implementation (which is the underlying XPath 2 implementation, used by Xerces-J XSD 1.1 assertions implementation) also looks pretty compliant to the XPath 2 language.

I hope, that this post is useful.

2 comments:

David Carver said...

Great to see that PsychoPath is working well. Any update on when there will be an official Xerces-J 2.10 release?

Mukul Gandhi said...

I'm not aware about the exact date. It seems Xerces committers responsible for release, are still somewhat busy. But I'm expecting the 2.10.0 release sometime soon :)