I had to spend some time this week working on XML schemas. The trouble with schemas is that you can go all out and implement an almost object-oriented inheritance hierarchy. Which is exactly what I did.
I unwittingly set foot into the rarefied area of substitutionGroups
and the like. And trying to find information when you don't know what to look for is a huge problem. So to save you the trouble and for my own future reference, here's what I learned. I could be wrong in several places, but it should be a good starting point for you.
This is what I was I had in mind. I needed a generic Object and a simple Collection-like container that could hold 1 or more Objects. And if you are not using XMLSpy...well good luck!
This is what the Object looks like:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.javaforu.com/schemas/lesson1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.javaforu.com/schemas/lesson1" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="GenericObjectType"></xs:complexType>
<xs:element name="GenericObject" type="GenericObjectType"></xs:element>
</xs:schema>
And this is what the Object Collection looks like:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.javaforu.com/schemas/lesson1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.javaforu.com/schemas/lesson1" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="GenericObjectCollectionType">
<xs:sequence>
<xs:element ref="GenericObject" maxOccurs="unbounded"></xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="GenericObjectCollection" type="GenericObjectCollectionType"></xs:element>
</xs:schema>
That was easy enough. What I need now is a Person object that inherits from Object.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.javaforu.com/schemas/lesson1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.javaforu.com/schemas/lesson1" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="PersonType">
<xs:complexContent>
<xs:extension base="GenericObjectType">
<xs:sequence>
<xs:element name="firstName" type="xs:string"></xs:element>
<xs:element name="lastName" type="xs:string"></xs:element>
<xs:element name="age" type="xs:positiveInteger"></xs:element>
<xs:element name="gender" type="xs:string"></xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="Person" type="PersonType" substitutionGroup="GenericObject"></xs:element>
</xs:schema>
Note the use of
substitutionGroup="GenericObject"
in the Person element. This means that I can create Person tags/elements where ever GenericObject tags are allowed. That's very cool!Here comes the clincher..If I need a special PersonCollection that only allows Person objects but still inherits from the GenericCollection, this is what I'd have to do:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.javaforu.com/schemas/lesson1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.javaforu.com/schemas/lesson1" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="PersonCollectionType">
<xs:complexContent>
<xs:restriction base="GenericObjectCollectionType">
<xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element ref="Person"></xs:element>
</xs:choice>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Now, pay attention: For some reason, I'm yet to discover why, you cannot just replace the ref to the GenericObject with a Person ref when you have an
unbounded
occurrence rule. Try it. It has to be wrapped in a choice
rule.And of course the
substitutionGroup="GenericObjectCollection"
will you use the PersonCollection where ever the GenericCollection is allowed.
<xs:element name="PersonCollection" substitutionGroup="GenericObjectCollection"></xs:element>
This is what a sample looks XML like:
<?xml version="1.0" encoding="UTF-8"?>
<DocRoot xmlns="http://www.javaforu.com/schemas/lesson1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.javaforu.com/schemas/lesson1 Lesson1.xsd">
<GenericObject></GenericObject>
<Person>
<firstName>sdsfxcv</firstName>
<lastName>xsdf</lastName>
<age>12</age>
<gender>m</gender>
</Person>
<GenericObjectCollection>
<GenericObject></GenericObject>
<Person>
<firstName>asd</firstName>
<lastName>fgdfgd</lastName>
<age>77</age>
<gender>f</gender>
</Person>
</GenericObjectCollection>
<PersonCollection>
<Person>
<firstName>abcd</firstName>
<lastName>def</lastName>
<age>20</age>
<gender>m</gender>
</Person>
</PersonCollection>
</DocRoot>
And the full schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.javaforu.com/schemas/lesson1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.javaforu.com/schemas/lesson1" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="GenericObjectType"/>
<xs:complexType name="GenericObjectCollectionType">
<xs:sequence>
<xs:element ref="GenericObject" maxOccurs="unbounded"></xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="DocRootType">
<xs:sequence>
<xs:element ref="GenericObject" minOccurs="0" maxOccurs="unbounded"></xs:element>
<xs:element ref="GenericObjectCollection" minOccurs="0" maxOccurs="unbounded"></xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="GenericObject" type="GenericObjectType"></xs:element>
<xs:element name="GenericObjectCollection" type="GenericObjectCollectionType"></xs:element>
<xs:element name="DocRoot" type="DocRootType"></xs:element>
<!---->
<xs:complexType name="PersonType">
<xs:complexContent>
<xs:extension base="GenericObjectType">
<xs:sequence>
<xs:element name="firstName" type="xs:string"></xs:element>
<xs:element name="lastName" type="xs:string"></xs:element>
<xs:element name="age" type="xs:positiveInteger"></xs:element>
<xs:element name="gender" type="xs:string"></xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="PersonCollectionType">
<xs:complexContent>
<xs:restriction base="GenericObjectCollectionType">
<xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element ref="Person"></xs:element>
</xs:choice>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:element name="Person" type="PersonType" substitutionGroup="GenericObject"></xs:element>
<xs:element name="PersonCollection" substitutionGroup="GenericObjectCollection"></xs:element>
</xs:schema>
If you find any mistakes or have any other such interesting bits of information to share, I'd love to hear it.
0 comments:
Post a Comment