2
votes

I would like to create an XML schema with the following constraints:

  • The root element shall be list.
  • list contains a set of node elements.
  • a node element can have a value attribute.
  • a node element can contain a value element.
  • a node element can have only (and exactly) one value attribute or value element.

Here is an example of a valid XML that verify above constraints:

<?xml version="1.0" ?>
<list>
    <node id="1" value="A" />
    <node id="2">
        <value>B</value>
    </node>
</list>

I tried the following XSD Schema:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="list">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="node" maxOccurs="unbounded" minOccurs="0">
          <xs:complexType mixed="true">
            <xs:sequence>
              <xs:element type="xs:string" name="value" minOccurs="0"/>
            </xs:sequence>
            <xs:attribute type="xs:byte" name="id" use="optional"/>
            <xs:attribute type="xs:string" name="value" use="optional"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

This XSD schema verify my first and the second constraint, but not the third one.

The following XML example is not valid according to my constraints, however, it is valid against my previous XSD schema.

<?xml version="1.0" ?>
<list>
    <node id="2" value="A" /> <!-- valid -->
    <node id="4">
        <value>D</value>
    </node><!-- valid -->
    <node id="1" /><!-- not valid, missing value -->
    <node id="3" value="B">
        <value>C</value>
    </node><!-- not valid, both attribute and element are declared -->
</list>

How can I change my schema to verify all my constraints?

Thanks in advance.

2

2 Answers

4
votes

This is not possible using XSD 1.0.

It should be possible with XSD 1.1 using assertions:

<xs:assert test="not(@value and value)"/>

that fails if @value and value are both present. To check that there is exactly one attribute or sub-element use:

<xs:assert test="count((value, @value))=1"/>

as suggested by Michael Kay in the comments.

It might be possible using some other XML validation technology like Schematron.

0
votes

You can create first type with required attribute and second type with required element. Then use choice compositor containing both types.