XSD: Adding Attributes and other Structures
Adding an Attribute
Lets take our address XML and add an attribute to address:
<address type="billing">
<address1>My Street</address1>
<address2>My Floor</address2>
<city>New York</city>
<state>NY</state>
<zip>10004</zip>
</address>
You'll see that address now has a "type" attribute. How do we handle that in our schema?
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="address1" type="xs:string" />
<xs:element name="address2" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string" />
<xs:element name="zip" type="xs:string" />
</xs:sequence>
<attribute name="type" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:schema>
Basically I just added the attribute within the complex type for the address, but below the sequence of sub elements. That is it.
Global Declarations
Often you want to create a global declaration (one that is not contained within another element - in the example above, address is the only global declaration with address1, address2, city, state and zip being local declarations within the address element). For example, let's say we have customer and order elements both of which contain addresses. We might have the following XML:
<firstName>Peter</firstName>
<address type="billing">
<address1>My Street</address1>
<address2>My Floor</address2>
<city>New York</city>
<state>NY</state>
<zip>10004</zip>
</address>
<orders>
<order total="$12">
<address type="billing">
<address1>My Street</address1>
<address2>My Floor</address2>
<city>New York</city>
<state>NY</state>
<zip>10004</zip>
</address>
</order>
</orders>
</customer>
To describe that, we'd use the following XSD:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="customer">
<xs:complexType>
<xs:sequence>
<xs:element name="firstname" type="xs:string" />
<xs:element ref="address" />
<xs:element ref="orders" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="address1" type="xs:string" />
<xs:element name="address2" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string" />
<xs:element name="zip" type="xs:string" />
</xs:sequence>
<attribute name="type" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:schema>
<xs:element name="orders">
<xs:complexType>
<xs:sequence>
<xs:element ref="order" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element ref="address" />
</xs:sequence>
<attribute name="total" type="xs:string" />
</xs:complexType>
</xs:element>
There are a couple of new concepts to consider in this XSD. Firstly have a look at the customer definition. Notice that a customer is a complex type (it has either attributes or sub elements - in this case sub-elements). Notice that it has a simple sub-element (firstName) which is just a string, but then it has "address" and "orders" both of which have a "ref" which means they are just references to elements defined elsewhere. I won't get into namespaces right now, but I will just say that they could refer to elements described either elsewhere in this document as a global element (if it was a local element, it wouldn't be available as a reference) or in other documents by using name spaces.
You Want How Many?
The second thing to notice is the sequence for the orders element. Orders is a collection element for containing 0..n "order" tags. This is implemented using the minOccurs and maxOccurs both of which can be set to 0, any positive integer or "unbounded" for unlimited. This supports not only cardinality definitions (equivalent to 0..1, 0..n, 1..1 and 1..n) but also specific bounds if a user can (for some reason) only have between 2 and 31 addresses.
For attributes, the syntax is a little different. Obviously you can't have more than one of an attribute within a given element, but you can add a setting: use="required|optional|prohibited".
Fixed and Default
If you want to force the value of an element or an attribute, you also have the options of "fixed" and "default". There is a nice table here that runs you through the fairly straighforward implications of the various options.
Adding Annotations You might also want to add annotations to your XSDs for documentation purposes (they can do more than just documentation, but this *is* XSD 101). Want to add a simple comment to your XSD? try:
<xs:documentation>
Comment goes here
</xs:documentation>
</xs:annotation>


