1

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.)

kjhughes
  • 106,133
  • 27
  • 181
  • 240

2 Answers2

1

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.


Update: Michael Kay reminded me of another XSD 1.1 mechanism, which is less powerful than assertion but a better fit if you merely have to vary type per attribute value: Conditional Type Assignment...

If you're stuck with overly generic element names and seeking to write a schema after-the-fact, before XSD 1.1's assertions, consider XSD 1.1's Conditional Type Assignment, which allows type to be assigned based on an attribute value.

A full working example can be found here:

kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • 1
    Thank you. Since, as I said, I have no control over this design, XSD is not the answer. You have saved me hours of trouble! – John McMullen Oct 20 '21 at 16:26
  • XSD 1.0 is not the answer. But XSD 1.1 might be, if you are able to use it. – Michael Kay Oct 20 '21 at 18:53
  • @MichaelKay: I should have mentioned CTA, which is generally inferior to better element name design in the first place, but here it should be a consideration since OP cannot change the design anyway, assuming, as you say, XSD 1.1 is an option. Thanks for the reminder. Answer updated. – kjhughes Oct 20 '21 at 20:29
  • Interestingly I see two popular designs for representing abstract syntax trees in XML, one uses element names for the node type and attributes for the operand role within the parent expression, the other does it the other way round. I don't think there's any intrinsic reason to prefer one over the other, other than the fact that XSD has much better support for the former design pattern. – Michael Kay Oct 20 '21 at 22:14
  • @MichaelKay: Agreed, my comment was meant to be scoped to XSD -- not a universal truth. – kjhughes Oct 20 '21 at 22:42
0

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.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164