Doing More With XML Schemas (part 3) - A Day At The Supermarket
(Page 2 of 6 )
What's a supermarket got to with an XML schema, you ask wonderingly? Quite a lot, actually. You see, all supermarkets consist of aisles, with products placed neatly in each aisle for customers and employees alike. In an XML document, this design would be represented as follows:
<?xml version="1.0" encoding="UTF-8"?>
<supermarket name="MyMart"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<aisle
name="fruits" number="1">
<item code="001" quantity="230" price="1.00"/>
<item
code="002" quantity="121" price="2.45"/>
<item code="003" quantity="60" price="3.15"/>
</aisle>
<aisle
name="vegetables" number="2">
<item code="004" quantity="500" price="1.15"/>
<item
code="005" quantity="600" price="0.75"/>
</aisle>
</supermarket>
As you can see, I have a list of <aisle> elements, which in turn enclose multiple
<item> elements. Each <aisle> is associated with a "name" that represents the category of items in the aisle, and a "number", which is used for easy reference. Each <item> is associated with a "quantity" and a "price".
Writing an XML schema to validate the XML document instance above is child's play, especially considering the amount of practice I've had over the last couple of weeks.
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element
name="supermarket">
<xsd:complexType>
<xsd:sequence>
<xsd:element
name="aisle"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element
name="item"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension
base="xsd:string">
<xsd:attribute name="code" type="xsd:positiveInteger"/>
<xsd:attribute
name="quantity" type="xsd:positiveInteger"/>
<xsd:attribute name="price"
type="xsd:decimal"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute
name="name"
type="xsd:string"/>
<xsd:attribute
name="number" type="xsd:positiveInteger"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute
name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Now, let's suppose that, one fine day, the store manager decides to add a few
items to aisle 1. In the XML universe, he has two options available to him: he could add it to the existing <item> list for the appropriate aisle, or he could add another <aisle> element to the bottom of the document instance, reference it with the same aisle number, and attach the new items there.
<?xml version="1.0" encoding="UTF-8"?>
<supermarket name="MyMart"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<aisle
name="fruits" number="1">
<item code="001" quantity="230" price="1.00"/>
<item
code="002" quantity="121" price="2.45"/>
<item code="003" quantity="60" price="3.15"/>
</aisle>
<aisle
name="vegetables" number="2">
<item code="004" quantity="500" price="1.15"/>
<item
code="005" quantity="600" price="0.75"/>
</aisle>
<aisle name="fruits"
number="1">
<item code="014" quantity="200" price="1.35"/>
<item code="015"
quantity="300" price="0.55"/>
</aisle>
</supermarket>
With option two, the XML document instance doesn't look as clean as it did initially.
Proceeding along this path, it would soon have a number of different entries for the same <aisle> at different locations in the document tree. Obviously, this is a maintenance nightmare.
You can prevent this from happening via the very cool <xsd:unique> element - as in the revised schema below:
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element
name="supermarket">
<xsd:complexType>
<xsd:sequence>
<xsd:element
name="aisle"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element
name="item"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension
base="xsd:string">
<xsd:attribute name="code" type="xsd:positiveInteger"/>
<xsd:attribute
name="quantity" type="xsd:positiveInteger"/>
<xsd:attribute name="price"
type="xsd:decimal"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute
name="name"
type="xsd:string"/>
<xsd:attribute
name="number" type="xsd:positiveInteger"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute
name="name" type="xsd:string"/>
</xsd:complexType>
<xsd:unique name="NoRepeatAisle">
<xsd:selector
xpath="aisle"/>
<xsd:field xpath="@number"/>
</xsd:unique>
</xsd:element>
</xsd:schema>
I'm not going to get into a long-winded explanation of the entire schema above.
Instead, let me focus on the interesting part:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- snip -->
<xsd:unique
name="NoRepeatAisle">
<xsd:selector xpath="aisle"/>
<xsd:field xpath="@number"/>
</xsd:unique>
<!--
snip -->
</xsd:schema>
The <xsd:unique> element is what gets the ball rolling - it is used to impose
uniqueness constraints on an XML document instance. You can assign it a name - I've called mine "NoRepeatAisle" - to makes its function clearer.
The <xsd:unique> element encloses <xsd:selector> and <xsd:field> elements, which help to identify the unique components of the document. The "xpath" attribute of the <xsd:selector> element contains an XPath expression that helps to limit the scope within which the uniqueness constraint will be applied. In my case, this is restricted to all the <aisle> elements that are the children of the <supermarket> element only; if there exist any other <aisle> elements in the hierarchy, this constraint is not valid.
The second element component of the uniqueness constraint is the <xsd:field> element, which specifies which attribute values should be unique - in the example above, this is the value of the "number" attribute.
Next: Of Fruits And Vegetables >>
More XML Articles
More By Harish Kamath, (c) Melonfire