Sunday, July 29, 2018

Co-occurrence constraints and Conditional Type Assignment, with XML Schema 1.1

With respect to following article, that I wrote for XML.com : https://www.xml.com/articles/2018/05/29/co-occurrence-cta-xsd/ , I wish to add few more points to that article, via this blog post as mentioned below,

1) Using "if" control expressions in an XSD <assert>

The XPath 2.0 "if" expression is an useful facility for an <assert>. I'll explain this, via a XML schema validation example, as mentioned below.

XML Schema 1.1 document:

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

  <xs:element name="X">
     <xs:complexType>
        <xs:sequence>
           <xs:choice>
              <xs:element name="b" type="xs:integer"/>
              <xs:element name="c" type="xs:integer"/>
           </xs:choice>
           <xs:element name="a" type="xs:integer"/>
        </xs:sequence>
        <xs:attribute name="el" use="required">
           <xs:simpleType>
              <xs:restriction base="xs:string">
                 <xs:enumeration value="b"/>
                 <xs:enumeration value="c"/>
              </xs:restriction>
           </xs:simpleType>
        </xs:attribute>
        <xs:assert test="if (@el = 'b') then b else c"/>
     </xs:complexType>
  </xs:element>

</xs:schema>

(the XSD <choice> specifies, that either element "b" should occur or the element "c" should occur. this is further controlled by an <assert> constraint, which specifies that if value of attribute "el" is 'b' then element "b" should occur, otherwise element "c" should occur for the <choice>.)

Below are few XML instance documents, that can be validated with the above XSD document:

<X el="b">
  <b>100</b>
  <a>200</a>
</X>

(valid document)

<X el="b">
  <c>100</c>
  <a>200</a>
</X>

(invalid document, since the preceding-sibling of element "a" must be element "b")

<X el="p">
  <b>100</b>
  <a>200</a>
</X>

(invalid document, since the value of attribute "el" is not as per the simpleType definition of attribute "el". the <assert> would also fail.)

2) Using XSD <alternative> instead of <assert>

The XSD example mentioned in point 1) above, can easily be converted to an XSD document using <alternative> to solve the same use case. Below is a modified XSD 1.1 document, using <alternative> element solving the same use case as mentioned in point 1) above.

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

  <xs:element name="X">
     <xs:alternative test="@el = 'b'" type="B_type"/>
     <xs:alternative test="@el = 'c'" type="C_type"/>
     <xs:alternative type="xs:error"/>
  </xs:element>
  
  <xs:complexType name="B_type">
     <xs:sequence>
        <xs:element name="b" type="xs:integer"/>
        <xs:element name="a" type="xs:integer"/>
     </xs:sequence>
     <xs:attribute name="el" type="xs:string" use="required"/>
  </xs:complexType>
  
  <xs:complexType name="C_type">
     <xs:sequence>
        <xs:element name="c" type="xs:integer"/>
        <xs:element name="a" type="xs:integer"/>
     </xs:sequence>
     <xs:attribute name="el" type="xs:string" use="required"/>
  </xs:complexType>

</xs:schema>


2 comments:

Satish Botla said...

While trying to execute the above xsd. I am getting this error. I have xmlschema 1.0.14 version installed. Could you please help identify why I am seeing this issue.

>>> import xmlschema
>>> my_schema = xmlschema.XMLSchema('/home/centos/sample1.xsd')
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/xmlschema/validators/schema.py", line 360, in __init__
self.check_schema(root, self.namespaces)
File "/usr/local/lib/python3.6/site-packages/xmlschema/validators/schema.py", line 674, in check_schema
raise error
xmlschema.validators.exceptions.XMLSchemaChildrenValidationError: failed validating with XsdGroup(model='sequence', occurs=[1, 1]):

Reason: Unexpected child with tag 'xs:assert' at position 3.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python3.6/site-packages/xmlschema/validators/schema.py", line 362, in __init__
self.parse_error(e.reason, elem=e.elem)
File "/usr/local/lib/python3.6/site-packages/xmlschema/validators/xsdbase.py", line 168, in parse_error
raise error
xmlschema.validators.exceptions.XMLSchemaParseError: Unexpected child with tag 'xs:assert' at position 3:

Mukul Gandhi said...

I apologize, that I saw your comment late.

The XSD processor that you're using, doesn't seem to support XSD 1.1, and that's why you're getting errors that xs:assert element isn't recognized within your schema document. Two good XSD 1.1 processors that I'm aware of are, Apache Xerces and Saxon (there could be others as well) that you may use.