Home > Net >  XSD defining one positional mandatory element in an otherwise open list
XSD defining one positional mandatory element in an otherwise open list

Time:09-01

so I searched a lot and I cant find any solution. What I need is an XSD that defines that an element must have a specific element as first or last child but can otherwise have an random order of other given elements.

Example:

<a> <!-- Valid -->
  <b />
  <c1 />
  <c2 />
  <c3 />
</a>

<a> <!-- Valid -->
  <c2 />
  <c1 />
  <c3 />
  <b />
</a>

<a> <!-- Invalid -->
  <c2 />
  <b />
  <c1 />
  <c3 />
</a>

So basically I am trying to create an XSD that allowes c1,c2,c3 in random order and in random quantity but always must have one b either at the top or the bottom.

I know about xsd:all and xsd:sequence but I can't find anything that would fit my problem.

CodePudding user response:

With XSD 1.1 xs:all using an xs:assert:

<?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="a" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:all>
                            <xs:element name="b" minOccurs="0" maxOccurs="1"/>
                            <xs:element name="c1"/>
                            <xs:element name="c2"/>
                            <xs:element name="c3"/>
                        </xs:all>
                        <xs:assert id="b-is-first-or-last-child"
                            test="*[1] instance of element(b) or *[last()] instance of element(b)"/>
                    </xs:complexType>                
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

both Saxon-EE as well as Xerces flag the last a as invalid:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="schema2.xsd">
    <a> <!-- Valid -->
        <b />
        <c1 />
        <c2 />
        <c3 />
    </a>
    
    <a> <!-- Valid -->
        <c2 />
        <c1 />
        <c3 />
        <b />
    </a>
    
    <a> <!-- Invalid -->
        <c2 />
        <b />
        <c1 />
        <c3 />
    </a>
</root>

CodePudding user response:

I was able to solve this problem using a group element sequence.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:group name="children">
    <xs:choice>
      <xs:element name="c1" />
      <xs:element name="c2" />
      <xs:element name="c3" />
    </xs:choice>
  </xs:group>
  <xs:complexType name="aNode">
    <xs:choice>
      <xs:sequence>
        <xs:element name="b" minOccurs="1" maxOccurs="1" />
        <xs:group ref="children" minOccurs="1" maxOccurs="unbounded" />
      </xs:sequence>
      <xs:sequence>
        <xs:group ref="children" minOccurs="1" maxOccurs="unbounded" />
        <xs:element name="b" minOccurs="1" maxOccurs="1" />
      </xs:sequence>
    </xs:choice>
  </xs:complexType>
  <xs:complexType name="rootNode">
    <xs:sequence>
      <xs:element name="a" type="aNode" minOccurs="0" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
  <xs:element name="root" type="rootNode" />
</xs:schema>
  • Related