Saturday, February 15, 2020

XML Schema 1.1 <assert> use cases with <choice> and <attribute>

I've been imagining that, what could be useful use cases of XML Schema (XSD) 1.1 <assert> construct.

According to the XSD 1.1 structures specification, "assertion components constrain the existence and values of related XML elements and attributes".

One of useful use cases possible for XSD 1.1 <assert> is, to constrain the standard behavior of XSD 1.0 / 1.1 <choice> construct. I'll attempt to write something about this, here on this blog post.

Below is an XSD schema example using the <choice> construct, that is correct for both 1.0 and 1.1 versions of XSD language:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="X">
       <xs:complexType>
          <xs:choice>
             <xs:element name="a" type="xs:string"/>
             <xs:element name="b" type="xs:string"/>
             <xs:element name="c" type="xs:string"/>
          </xs:choice>
       </xs:complexType>
    </xs:element>

</xs:schema>

The above schema document, ensures that following XML instance documents would be valid:

<X>
    <a>some string</a>
</X>

,

<X>
    <b>some string</b>
</X>

,

<X>
    <c>some string</c>
</X>

(essentially showing that, element 'X' can have only one of the elements 'a', 'b' or 'c' as a child element)

Lets see how the above XSD example, can be made a little different using XSD elements <attribute> and <assert>. Below is such a modified XSD document,

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="X">
       <xs:complexType>
          <xs:choice>
             <xs:element name="a" type="xs:string"/>
             <xs:element name="b" type="xs:string"/>
             <xs:element name="c" type="xs:string"/>
          </xs:choice>
          <xs:attribute name="isB" type="xs:boolean" use="required"/>
          <xs:assert test="if (@isB = true()) then b else not(b)"/>
       </xs:complexType>
    </xs:element>

</xs:schema>

The complete meaning of above XSD document is following,
1) The <choice> with three <element> declarations below it, essentially are the same constraints as the earlier XSD document has shown.
2) This schema additionally specifies, a mandatory boolean typed attribute named 'isB'.
3) The <assert> specifies that, if value of attribute 'isB' is true then element 'b' must be present as a child of element 'X'. If value of attribute 'isB' is false, then element 'X' cannot have element 'b' as its child but one of elements 'a' or 'c' would be a valid child of element 'X'.

The following XML instance documents would be valid according to above mentioned XSD document:

<X isB="1">
  <b>some string</b>
</X>

,

<X isB="0">
  <a>some string</a>
</X>

,

<X isB="0">
  <c>some string</c>
</X>

And, the following XML instance documents would be invalid according to the same XSD document:

<X isB="0">
  <b>some string</b>
</X>

,

<X isB="1">
  <a>some string</a>
</X>

,

<X isB="0">
  <d>some string</d>
</X>

Now lets consider another XSD example, where the schema document specifies a choice between three or more sequences. Below is mentioned such a schema document:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="X">
       <xs:complexType>
          <xs:choice>
             <xs:sequence>
                <xs:element name="a" type="xs:string"/>
                <xs:element name="b" type="xs:string"/>
             </xs:sequence>
             <xs:sequence>
        <xs:element name="p" type="xs:string"/>
        <xs:element name="q" type="xs:string"/>
             </xs:sequence>
             <xs:sequence>
        <xs:element name="x" type="xs:string"/>
        <xs:element name="y" type="xs:string"/>
             </xs:sequence>
          </xs:choice>
          <xs:attribute name="isSeqTwo" type="xs:boolean" use="required"/>
          <xs:assert test="if (@isSeqTwo = true()) then p else not(p)"/>
       </xs:complexType>
    </xs:element>

</xs:schema>

The complete meaning of above XSD document is following,
1) A <choice> is specified between three <sequence> elements. Therefore, element 'X' can have one of following sequences as its child: {a, b}, {p, q} or {x, y}.
2) This schema additionally specifies, a mandatory boolean typed attribute named 'isSeqTwo'.
3) The <assert> specifies that, if value of attribute 'isSeqTwo' is true then sequence {p, q} must be present as a child of element 'X'. If value of attribute 'isSeqTwo' is false, then element 'X' cannot have sequence {p, q} as its child but one of sequences {a, b} or {x, y} would be a valid child of element 'X'.

The following XML instance documents would be valid according to above mentioned XSD document:

<X isSeqTwo="1">
  <p>string1</p>
  <q>string2</q>
</X>

,

<X isSeqTwo="0">
  <a>string1</a>
  <b>string2</b>
</X>

,

<X isSeqTwo="0">
  <x>string1</x>
  <y>string2</y>
</X>

And, the following XML instance documents would be invalid according to the same XSD document:

<X isSeqTwo="0">
  <p>string1</p>
  <q>string2</q>
</X>

,

<X isSeqTwo="1">
  <a>string1</a>
  <b>string2</b>
</X>

,

<X isSeqTwo="0">
  <i>string1</i>
  <j>string2</j>
</X>


All the above examples, and any other XSD 1.0/1.1 constructs may be used with any standards compliant XSD validator.

That's about all I wanted to say, about this topic.