user2931279
user2931279

Reputation: 13

XML Schema for sequence order/restriction based on attribute value

Is it possible to define in XML Schema a sequence order/restriction based on attribute value? In XML, there is container node which keeps only item nodes. First item node is always delimiter, other item nodes must be only with attribute value category1 OR category2.

For example, valid documents is:

<root>
  <container>
    <item attr="delimiter">some_value</item>
    <item attr="category1">test1</item>
    <item attr="category1">test2</item>
    ....
  </container>

  <container>
    <item attr="delimiter">some_value</item>
    <item attr="category2">test3</item>
    ...
  </container>
<root>

In container node we can have item nodes only with category1 or category2.

Example of incorrect XML:

<root>
  <container>
    <item attr="delimiter">some_value</item>
    <item attr="category1">test1</item>
    <item attr="category2">test2</item>
  </container>

  <container>
    <item attr="delimiter">some_value</item>
    <item attr="category2">test3</item>
    <item attr="category1">test1</item>
  </container>
<root>

Is it possible in XSD?

Upvotes: 1

Views: 1002

Answers (1)

kjhughes
kjhughes

Reputation: 111630

To answer your question directly, yes, this is possible in XSD, however:

  1. It requires XSD 1.1 (see XSD 1.1 for Original XML below); it cannot be done in XSD 1.0:
  2. It is poor XML design. Better would be as follows, which could easily be represented in XSD 1.0:

    <root>
      <container>
        <delimiter>some_value</delimiter>
        <category1>test1</category1>
        <category1>test2</category1>
        ....
      </container>
    
      <container>
        <delimiter>some_value</delimiter>
        <category2>test3</category2>
        ...
      </container>
    </root>
    

XSD 1.1 for Requested, Original XML

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
  xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1">
  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="container" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="item" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute name="attr" use="required">
                        <xs:simpleType>
                          <xs:restriction base="xs:string">
                            <xs:enumeration value="delimiter"/>
                            <xs:enumeration value="category1"/>
                            <xs:enumeration value="category2"/>
                          </xs:restriction>
                        </xs:simpleType>
                      </xs:attribute>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:assert test="item[1]/@attr = 'delimiter' and
              ((every $i in item[position() > 1] satisfies $i/@attr = 'category1') or
               (every $i in item[position() > 1] satisfies $i/@attr = 'category2'))  "/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Upvotes: 3

Related Questions