Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a schema for an unordered list of XML nodes, with occurrence constraints

Tags:

xml

xsd

Given an XML layout like this, I'm trying to create a XSD schema to validate it.

<RootNode>
  <ChildA />
  <ChildC />
  <ChildB />
  <ChildB />
  <ChildA />
</RootNode>

The requirements are as follows:

  • ChildA, ChildB and ChildC may occur in any order. (<xs:sequence> unsuitable)
  • ChildA is mandatory but may occur multiple times.
  • ChildB is optional and may occur multiple times.
  • ChildC is optional and may occur once only.

The technique I usually use to create an unordered list of nodes is to use a <xs:choice maxOccurs="unbounded"> with each possible node in the list, however, I am unable to create the minOccurs="1" constraint on ChildA and the maxOccurs="1" contraint on ChildC. (The # of occurances of the choice takes precedence over those of the elements here).

<xs:element name="RootNode">
  <xs:complexType>
    <xs:choice minOccurs="1" maxOccurs="unbounded">
      <xs:element name="ChildA" minOccurs="1"/>
      <xs:element name="ChildB" />
      <xs:element name="ChildC" maxOccurs="1"/>
    </xs:choice>
  </xs:complexType>
</xs:element>
like image 208
Mark H Avatar asked Aug 01 '10 17:08

Mark H


People also ask

How an XML schema can be created?

To create an XML schemaOn the menu bar, choose XML > Create Schema. An XML Schema document is created and opened for each namespace found in the XML file. Each schema is opened as a temporary miscellaneous file. The schemas can be saved to disk, added to your project, or discarded.

What is minOccurs and maxOccurs in XSD?

The minOccurs attribute specifies the minimum number of times that the element can occur. It can have a value of 0 or any positive integer. The maxOccurs attribute specifies the maximum number of times that the element can occur.

How do you make an element mandatory in XSD?

The "use" property in the XSD definition is used to specify if the attribute is optional or mandatory. To specify that an attribute must be present, use="required" (Note: use may also be set to "prohibited", but we'll come to that later).

What is element ref in XSD?

The ref attribute can include a namespace prefix. This attribute cannot be used if the parent element is the schema element. type. Optional. Specifies either the name of a built-in data type, or the name of a simpleType or complexType element.


1 Answers

Update: In XSD 1.1m some of the constraints on all-groups have been lifted. See the answers here and here.

Not a simple one but seems doable. Difficult part here is that Schema definitions must be deterministic. Approach I used was to visualize the problem by drawing a finite state automata of it and then to write a regular expression that corresponded that automata. It is not at all as complicated as it might sound. Still, using some other validation system would have likely provided simpler answer.

I have done some testing but missing out some special cases is easy. Please comment if you spot an error.

...and here is the code:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

    <!-- Schema for elements ChildA, ChildB and ChildC
        The requirements are as follows:
            * ChildA, ChildB and ChildC may occur in any order.
            * ChildA is mandatory but may occur multiple times.
            * ChildB is optional and may occur multiple times.
            * ChildC is optional and may occur once only.
    -->

    <xsd:element name="root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="ABC-container" type="ABC" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:complexType name="ABC">
        <xsd:sequence>
            <xsd:element name="ChildB" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:choice>
                <xsd:sequence maxOccurs="1">
                    <xsd:element name="ChildC" type="xsd:string"/>
                    <xsd:element name="ChildB" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
                    <xsd:element name="ChildA" type="xsd:string"/>
                    <xsd:sequence minOccurs="0" maxOccurs="unbounded">
                        <xsd:element name="ChildA" type="xsd:string" minOccurs="0"/>
                        <xsd:element name="ChildB" type="xsd:string" minOccurs="0"/>
                    </xsd:sequence>
                </xsd:sequence>
                <xsd:sequence maxOccurs="1">
                    <xsd:element name="ChildA" type="xsd:string" minOccurs="1"/>
                    <xsd:sequence minOccurs="0" maxOccurs="unbounded">
                        <xsd:element name="ChildA" type="xsd:string" minOccurs="0"/>
                        <xsd:element name="ChildB" type="xsd:string" minOccurs="0"/>
                    </xsd:sequence>
                    <xsd:sequence minOccurs="0" maxOccurs="1">
                        <xsd:element name="ChildC" type="xsd:string"/>
                        <xsd:sequence minOccurs="0" maxOccurs="unbounded">
                            <xsd:element name="ChildA" type="xsd:string" minOccurs="0"/>
                            <xsd:element name="ChildB" type="xsd:string" minOccurs="0"/>
                        </xsd:sequence>
                    </xsd:sequence>
                </xsd:sequence>
            </xsd:choice>
        </xsd:sequence>
    </xsd:complexType>

</xsd:schema>
like image 179
jasso Avatar answered Sep 28 '22 10:09

jasso