xsd: How to extend a type with an unordered list of elements - xsd

This is a part of my xml schema
<xs:complexType name="Friend">
<xs:all>
<xs:element name="name" type="xs:string" />
<xs:element name="phone" type="xs:string" />
<xs:element name="address" type="xs:string" />
</xs:all>
</xs:complexType>
<xs:complexType name="Coworker">
<xs:all>
<xs:element name="name" type="xs:string" />
<xs:element name="phone" type="xs:string" />
<xs:element name="office" type="xs:string" />
</xs:all>
</xs:complexType>
For better maintainability, I would like to have the shared attributes in an (abstract) super type or something like that. But more important, I want that all elements are unordered and also optional.
Is this possible, and what is the best way to do it?

You have to limit yourself a little bit, some of the things you are trying to do are not possible in XML Schema.
Suppose you introduce a complex type called Person to be a super-type of Friend and Coworker. Here are your options:
Replace xs:all with xs:sequence, remove name and phone from the sub-types, add to the super-type, and add inheritance. Your elements now have to be ordered, but you can make them individually optional. It is illegal to use xs:all in type hierarchies in XML Schema, because the processor cannot tell where the parent content model stops and the child content model starts.
Replace xs:all with <xs:choice maxOccurs="unbounded"> in both types, and add your inheritance. Then your elements become unordered again, but they may repeat.
So in conclusion: given your type names up there, I would guess that your requirements will not be exactly met. I would go for the first option: insisting on arbitrary element order is often not as useful as it seems.

One-and-half year after this question and the accepted answer were posted, XSD 1.1 was published. In this version it is possible to specify what the OP asked for because a number of restriction on xs:all were lifted. One of them is that it is now possible to extend an xs:all.
Using XSD 1.1 you can specify the following:
<xs:complexType name="Person" abstract="true">
<xs:all>
<xs:element name="name" type="xs:string" minOccurs="0" />
<xs:element name="phone" type="xs:string" minOccurs="0" />
</xs:all>
</xs:complexType>
<xs:complexType name="Friend">
<xs:complexContent>
<xs:extension base="Person">
<xs:all>
<xs:element name="address" type="xs:string" minOccurs="0" />
</xs:all>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Coworker">
<xs:complexContent>
<xs:extension base="Person">
<xs:all>
<xs:element name="office" type="xs:string" minOccurs="0" />
</xs:all>
</xs:extension>
</xs:complexContent>
</xs:complexType>
This defines the following types:
Person: an abstract type with optional unordered name and phone elements;
Friend: extends Person adding an optional address element to the list of unordered elements;
Coworker: extends Coworker adding an optional office element to the list of unordered elements.
Note that this solution does not work for every XML processor: even though 8 years have passed since the publication of XSD 1.1, a lot of processors still only support XSD 1.0.

Related

Unique constraint on a complexType instead of an element

I have the following XSD structure:
<xs:schema xmlns:ns="http://abc/">
...
<xs:element name="abc">
<xs:complexType>
<xs:sequence>
<xs:element ref="map"/>
</xs:sequence>
</xs:complexType>
</xs:element>
...
<xs:element name="map">
<xs:complexType>
<xs:sequence>
<xs:element name="entry" type="ns:MapEntryType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:unique name="entry">
<xs:selector xpath="entry"/>
<xs:field xpath="key"/>
</xs:unique>
</xs:element>
<xs:complexType name="MapEntryType">
<xs:sequence>
<xs:element name="key" type="xs:string"/>
<xs:element name="value" type="xs:anyType"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
This is doing its job.
The map element now has to be called something different based on whichever is the wrapper, so the name is sometimes map, sometimes properties, sometimes options, etc.
Therefore I want to genericize the map element.
I tried doing the following:
Making map a xs:complexType and changing ref to type.
This resulted in xs:unique not being accepted and failed
Making map a xs:complexType, changing ref to type and moving the xs:unique constraint to the element definitions.
This worked but resulted in the XSD having a lot of xs:unique present in the document.
Isn't there a way to simply tell that I want a specific structure and it containing unique elements without having to repeat the unique constraint everywhere?
As Petru Gardea said in his answer
Both XSD 1.0 and 1.1 place the identity constraints under an element
So you have to add xs:unique to every element, but if you are using XSD 1.1 you can define only once a complete xs:unique and then in the rest of the elements use xs:unique ref="name". This is not valid for you as you are using XSD 1.0, but I let it here for future XSD 1.1 users that find this good question.
Example (namespaces removed for clarity):
<xs:element name="map">
<xs:complexType>
<xs:sequence>
<xs:element name="entry" type="MapEntryType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- Only completely defined once -->
<xs:unique name="uniqueEntry">
<xs:selector xpath="entry"/>
<xs:field xpath="key"/>
</xs:unique>
</xs:element>
<xs:element name="hashMap">
<xs:complexType>
<xs:sequence>
<xs:element name="entry" type="MapEntryType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- Referenced here and every other time -->
<xs:unique ref="uniqueEntry"/>
</xs:element>
Short answer, it is not possible. Both XSD 1.0 and 1.1 place the identity constraints under an element; a constraint cannot be globally defined, therefore there is no "reuse" per se, other than that of the enclosing element. Given your scenario (different element names for different needs) it is not possible to reuse.

Reference another XML parent complexType?

How should I reference another complexType in xml, as element or as attribute over my own defined Key? What is the correct approach to model the following self-reference? Is the first approach even possible, or does it lead to infinite self-referencing?
<xs:complexType name="Category">
<xs:sequence>
<xs:element name="ParentCategory" type="Category" minOccurs="1" maxOccurs="1"></xs:element>
<xs:element name="ChildCategory" type="Category" minOccurs="0" maxOccurs="unbounded"></xs:element>
</xs:sequence>
<xs:attribute name="CategoryName" type="xs:string"></xs:attribute>
</xs:complexType>
or
<xs:complexType name="Category">
<xs:sequence>
<xs:element name="ChildCategory" type="Category" minOccurs="0" maxOccurs="unbounded"></xs:element>
</xs:sequence>
<xs:attribute name="CategoryName" type="xs:string"></xs:attribute>
<xs:attribute name="ParentCategory" type="xs:string"></xs:attribute>
</xs:complexType>
I'm a bit confused - since I want to be object oriented, but am not sure how this would look like in XML. Wouldn't the reference of ParentCategory as a Category-type require me to again write a Category-type in XML that itself has a ParentCategory child-element, etc... leading to infinite type-referencing.
There's no issue referencing an element of the same type as part of the type definition, so your first example is fine from that point of view. Trying to reference the parent is a bit odd though, you shouldn't really need to do this... XML is hierarchical after all.
<xs:complexType name="Category">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="ChildCategory" type="Category"/>
</xs:sequence>
<xs:attribute name="CategoryName" type="xs:string"/>
</xs:complexType>
The Category type references itself recursively, allowing for 0 or more ChildCategory elements. This should do what you need (there's nothing wrong with recursive type referencing in the XML Schema).
If you need to refer to the parent Category in your document, it's easy enough to chain to the parent node in any DOM implementation or with XPath.

xml schema: restricting occurrences to sibling element sequence cardinality

Given:
<xs:complexType name="SymbolsList" final="">
<xs:sequence>
<xs:element name="symbol" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ComboList">
<xs:sequence>
<xs:element name="combo" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="symbol" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="comboName" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="symbolsList" type="SymbolsList">
<xs:unique name="uniqueSymbol">
<xs:selector xpath="./symbol" />
<xs:field xpath="#name" />
</xs:unique>
</xs:element>
<xs:element name="combosList" type="ComboList">
<xs:unique name="uniqueCombo">
<xs:selector xpath="./combo" />
<xs:field xpath="#comboName" />
</xs:unique>
</xs:element>
I believe this defines a list of symbols and a list of combinations of those symbols.
The each entry in the list of symbols must have a unique name, and each entry in the list of combos must have a unique comboName.
What I'd like to know is if there is a way for me to restrict the number of allowed occurrences in the combosList sequence to at least the number of symbols defined in the symbol list.
I guess I'm asking whether or not cardinality restriction can be variable and if so, how to associate it's limitation?
I also want to make it so that the comboList elements (a single combo) can only use names of symbols defined in the symbolList element.
I think I can pull of that last part. I can't find anything anywhere that talks about limiting caridinal sizes of disparate element sequences to greater than or equal to one or the other.
Perhaps it's not possible.
XSD requires cardinality to constraints to be specified literally in the declaration; the kind of dynamic calculation you have in mind is not in XSD's design space.
In XSD 1.1 you can add an assertion to some common ancestor of SymbolsList and CombosList that requires
count(CombosList/combo) ge count(SymbolsList/symbol)
XSD 1.1 is supported by Saxon EE and by Xerces J (in the latter case you have to look for the 1.1 distribution, or did last I looked). (One caveat: Note that Xerces J does not support all of XPath 2.0 in assertions, and I haven't actually checked to see whether this assertion is covered by the minimal subset of XPath XSD requires of conforming 1.1 implementations. Investigate further before sinking a lot of time here.)

XSD - Override element

I've a base class, marked as abstract:
<!-- TYPE: BASE CLASS -->
<xs:complexType name="BaseClass" abstract="true">
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="implementation" type="BaseClass" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
Now the class that inherits BaseClass and overrides 'implementation' with null:
<xs:complexType name="MyClass">
<xs:complexContent>
<xs:extension base="BaseClass"/>
</xs:complexContent>
</xs:complexType>
I've tried this but is invalid:
<xs:complexType name="MyClass">
<xs:complexContent>
<xs:extension base="BaseClass">
<xs:sequence>
<xs:element name="implementation" fixed="xs:nil"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Is there a way to do this?
Marking something as abstract in XSD schema basically means that it cannot appear in an instance document. It should be used with the substitutionGroup attribute.
For example
<xs:element name="replaceme" abstract="true" />
<xs:element name="replacement1" substitutionGroup="replaceme" />
<xs:element name="replacement2" substitutionGroup="replaceme" />
This means that in an instance document you would be forced to use either a "replacement1" or a "replacement2" element, ie the xsd is forcing you to substitute the "replaceme" element with one of the replacements from the substitution group.
So to achieve what you want you need to create a substitution group consisting of the types you want to use instead of your base type. I am not sure this is possible with complex types but give it a go.

XSD and plain text

I have a rest/xml service that gives me the following...
<verse-unit unit-id="38009001">
<marker class="begin-verse" mid="v38009001"/>
<begin-chapter num="9"/><heading>Judgment on Israel&apos;s Enemies</heading>
<begin-block-indent/>
<begin-paragraph class="line-group"/>
<begin-line/><verse-num begin-chapter="9">1</verse-num>The burden of the word of the <span class="divine-name">Lord</span> is against the land of Hadrach<end-line class="br"/>
<begin-line class="indent"/>and Damascus is its resting place.<end-line class="br"/>
<begin-line/>For the <span class="divine-name">Lord</span> has an eye on mankind<end-line class="br"/>
<begin-line class="indent"/>and on all the tribes of Israel,<footnote id="f1">
A slight emendation yields <i>
For to the <span class="divine-name">Lord</span> belongs the capital of Syria and all the tribes of Israel
</i>
</footnote><end-line class="br"/>
</verse-unit>
I used visual studio to generate a schema from this and used XSD.EXE to generate classes that I can use to deserialize this mess into programmable stuff.
I got everything to work and it is deserialized perfectly (almost).
The problem I have is with the random text mixed throughout the child nodes. The generated verse-unit objects gives me a list of objects (begin-line, begin-block-indent, etc), and also another list of string objects that represent the bits of string throughout the xml.
Here is my schema
<xs:element maxOccurs="unbounded" name="verse-unit">
<xs:complexType mixed="true">
<xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element name="marker">
<xs:complexType>
<xs:attribute name="class" type="xs:string" use="required" />
<xs:attribute name="mid" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="begin-chapter">
<xs:complexType>
<xs:attribute name="num" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="heading">
<xs:complexType mixed="true">
<xs:sequence minOccurs="0">
<xs:element name="span">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="class" type="xs:string" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="begin-block-indent" />
<xs:element name="begin-paragraph">
<xs:complexType>
<xs:attribute name="class" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="begin-line">
<xs:complexType>
<xs:attribute name="class" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="verse-num">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:unsignedByte">
<xs:attribute name="begin-chapter" type="xs:unsignedByte" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="end-line">
<xs:complexType>
<xs:attribute name="class" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="end-paragraph" />
<xs:element name="end-block-indent" />
<xs:element name="end-chapter" />
</xs:choice>
</xs:sequence>
<xs:attribute name="unit-id" type="xs:unsignedInt" use="required" />
</xs:complexType>
</xs:element>
WHAT I NEED IS THIS. I need the random text that is NOT surrounded by an xml node to be represented by an object so I know the order that everything is in.
I know this is complicated, so let me try to simplify it.
<field name="test_field_0">
Some text I'm sure you don't want.
<subfield>Some text.</subfield>
More text you don't want.
</field>
I need the xsd to generate a field object with items that can have either a text object, or a subfield object. I need to no where the random text is within the child nodes.
You can try Xml Schema Mixed Content, which is well explained here: http://www.w3schools.com/schema/schema_complex_mixed.asp
I don't know much about the .net side. But this somewhat older article says that mixed mode is basically supported by xsd.exe: http://msdn.microsoft.com/en-us/magazine/cc164135.aspx
Well your problem starts here:
<xs:element name="begin-line">
<xs:complexType>
<xs:attribute name="class" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
What this means is that a "begin line" type has an attribute called class (Which means the tag can have an attribute class like so: <begin-line class="lineclass">. However it is simply a type xs:string which means that all you get is a string.
I also don't know if this is an option, but if your XML could be made to have closing tags like this line for instance:
<begin-line class="indent"/>and Damascus is its resting place.<end-line class="br"/>
XML should be like this:
<begin-line class="indent"/>and Damascus is its resting place.</begin-line class="br">
I believe that if all the "line" tags were closed properly then the XSD generator might have a better time trying to derive what is inside the "begin-line" XML tag. Indeed if this is possible then you could rename begin-line to line and begin-chapter to chapter which should make your XML much more readable.
If it's not possible to update your code, then you are going to have to try your best with the string itself. I'm not sure if verses contain pure HTML, but if so you could parse the string inside the begin-line element as XML itself, using the library to jump between values and nodes (you might have to wrap a pair of tags around the string before trying to parse it though).

Resources