I am trying to document somebody else's hand-coded XML and I hope that XSD will help me do that. However, I am hampered by ignorance: I have no guarantee yet that XSD will work for the whole thing. (Feel free to tell me that something is bad coding style if it is, but I am just the documenter, not the developer.)
Anyway, the situation is that I have:
<items>
<item name="foo">
<coolThing>wah!</coolThing>
</item>
<item name="bar">
<needfulThing>address</needfulThing>
</item>
</items>
(Actual terms of course made up.) The <coolThing>
element can only occur in an <item name="foo">
container, and the <needfulThing>
element can only occur in an <item name="bar">
container.
How do I specify this in the XSD? The tutorial I'm looking at conveniently leaves this out.
Is it as simple as defining the assorted elements as children of the attribute declaration:
<xs:attribute name="foo" type="xs:string">
<xs:element name="coolThing" type="xs:string"/>
</xs:attribute>
(Stuff has been left out for clarity.) Of course, that wouldn't easily allow me to specify that <coolThing>
can occur in both <item name="foo">
and an <item name="baz">
elements, if that situation occurs.
Or am I missing something? (Quite likely.)
CodePudding user response:
Yes, you're missing that fundamentally XSD (and other XML schemas as well) are designed to associate an element with a type based on the name of the element, not the attributes of an element.
For this reason, using overly generic elements such as item
or object
or thing
that are differentiated via attributes such as name
is considered an anti-pattern. XSD 1.1 has an assertion mechanism that would allow expression of such constraints, but effectively you'd be re-implementing the natural containment constraints artificially via assertions — not where you want to be.
Specifically, instead of designing your XML elements generically,
<item name="foo"/>
have their element names convey their nature:
<foo/>
Then you'll find that normal content models available in XSD 1.0 are adequate to express your containment constraints.
CodePudding user response:
You can do this using XSD 1.1, with type alternatives. See for example XSD 1.1 alternative usage issue. This feature is explicitly designed to do what you want - make the type of an element depend on the value of an attribute, rather than on the element's name.
But you need an XSD 1.1 processor. There are three that I know of: Altova, Saxon, and Apache Xerces. Many widely-used XSD processors, such as Microsoft's, were never updated to XSD 1.1.