Tuesday, December 28, 2010

Schema based XML compare

David A. Lee (producer of XMLSH -- A command line shell for XML) raised an interesting discussion a while ago on XML-DEV mailing list, about how to do XML Schema aware XML document comparison. The whole of this discussion thread can be read here. Michael Kay suggested to use the XPath 2.0 function deep-equal (where the input document trees need to be validated by a schema -- to enable type-aware comparison, before doing a comparison by this function) for this kind of use case. Following Michael's idea I was playing with this concept using IBM's XPath 2.0 engine (which is XML Schema aware and is a component of WebSphere Application Server feature pack for XML). For the interest of readers, here's a minimal Java program illustrating this program design.
package com.ibm.xpath2;

import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;

import com.ibm.xml.xapi.XDynamicContext;
import com.ibm.xml.xapi.XFactory;
import com.ibm.xml.xapi.XPathExecutable;
import com.ibm.xml.xapi.XSequenceCursor;
import com.ibm.xml.xapi.XSequenceType;
import com.ibm.xml.xapi.XStaticContext;

public class XMLCompare {

    public static void main(String[] args) throws Exception {
        String dataDir = System.getProperty("dataDir.path");
  
        XFactory factory = XFactory.newInstance();
        factory.setValidating(XFactory.FULL_VALIDATION);
        factory.registerSchema(new StreamSource(dataDir + "/test.xsd"));
        
        XStaticContext staticContext = factory.newStaticContext();
        staticContext.declareVariable(new QName("doc1"), factory.getSequenceTypeFactory().                      documentNode(XSequenceType.OccurrenceIndicator.ONE));
        staticContext.declareVariable(new QName("doc2"), factory.getSequenceTypeFactory().                                      documentNode(XSequenceType.OccurrenceIndicator.ONE));
        XDynamicContext dynamicContext = factory.newDynamicContext();
        dynamicContext.bind(new QName("doc1"), new StreamSource(dataDir + "/test1.xml"));
        dynamicContext.bind(new QName("doc2"), new StreamSource(dataDir + "/test2.xml"));
                
        XPathExecutable executable = factory.prepareXPath("deep-equal($doc1, $doc2)", staticContext);
        XSequenceCursor result = executable.execute(dynamicContext);
        if (result.exportAsList().get(0).getBooleanValue()) {
           System.out.println("deep-equal == true");
        }
        else {
           System.out.println("deep-equal == false");
        }
    }
} 

Following are the XML and XML Schema documents used for the above example.

test1.xml
<test>10.00</test>
test2.xml
<test>10</test>

test.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="test" type="double" />
</schema>

For the above examples, if the schema type of element node "test" is xs:double then both the XML documents above are reported deep-equal (since the values 10 and 10.00 are same double values, and the element node was annotated with schema type xs:double and deep-equal function did a type aware comparison of XML documents). But if say the schema type of element node "test" is xs:string, then the XML documents shown above would be reported not deep-equal.

I hope that this post is useful.

Saturday, December 18, 2010

Apache Xerces-J 2.11.0 released

I am happy to extend the announcement made by Apache Xerces team few days ago, for the release of new version of Xerces-J (2.11.0) (ref http://markmail.org/message/oom75s3wpebfywh5). This Xerces release specifically improves compliance to the XML Schema 1.1 language (the detailed release notes for Xerces-J 2.11.0 are available at, http://xerces.apache.org/xerces2-j/releases.html).

On behalf of Xerces team I hope that this Xerces-J release would be found useful by the XML and XML Schema community.

Refrences to XML Schema language:
1. http://www.w3.org/XML/Schema (XML Schema WG Home Page)
2. http://www.w3.org/TR/xmlschema11-1/ (XML Schema 1.1 Structures specification)
3. http://www.w3.org/TR/xmlschema11-2/ (XML Schema 1.1 Datatypes specification)

Saturday, November 27, 2010

XML Schema 1.1: complexType restriction rules

I've been excited enough to write now about the new rules that have been specified in XML Schema 1.1 spec regarding type derivations between XML Schema complexType definitions and what is Xerces-J's (it's XML Schema 1.1 engine) current compliance about this area of XML Schema language. In this blog post I'm currently covering XML schema complexType restriction derivations. I'll try to write about complexType extensions sometime later. I thought that this post might find audience interested in this topic (anyone is invited to write a comment to this blog post, which will help me to learn more about type derivations between XML schema complex types -- "i'm interested in both restriction and extension derivations", and can also give Xerces team useful feedback to improve Xerces in desired and compliant ways). Below are my findings from the XML Schema 1.1 spec about this topic, and also Xerces's compliance status in this regard (I acknowledge that my understanding may yet not be complete about these areas of the XML Schema language :).

In XML Schema 1.0 language complex type restriction derivation rules are defined by schema particle restriction rules specified here, http://www.w3.org/TR/xmlschema-1/#coss-particle. There's a 5x5 table in this section which describes what constitute valid restrictions (and what schema type restrictions are forbidden) of XML schema particles.

In XML Schema 1.1 all of these complexType derivation rules are replaced by sections 3.4.6.3 Derivation Valid (Restriction, Complex) and 3.4.6.4 Content Type Restricts (Complex Content). In XML Schema 1.1 a mapping table (the 5x5 table) for particle restrictions is removed, and now a generic algorithm of subsumption relationship (a kind of containment or association relationship) of default bindings (which is an abstract notion for element and attributes declarations along with wild-card attributes "strict", "lax" and "skip") is specified. The XML Schema 1.1 complexType subsumption rules are simpler and easy to remember, than the corresponding type derivation rules from XML Schema 1.0 spec. My personal understanding so far is that, the improved default binding particle subsumption rules in XML Schema 1.1 make XML Schema 1.1 complexType restriction derivations largely compatible with corresponding type derivation rules in XML Schema 1.0, but the rules are now specified with better wordings.

Below are various XML schema complexType restriction cases I've studied so far (and these have corresponding implementations in Xerces; the upcoming Xerces-J 2.11.0 release would have these features), the characteristics of which are also described and I'm trying to discover more of the rules in these areas of XML Schema language.

xs:sequence, xs:choice and xs:all are possible compositors (which signify the notion of how we can compose schema particles in XML schema complexType definitions) in schema complexType's.

A) SEQUENCE TO SEQUENCE RESTRICTIONS
a.1 xs:element is derived from xs:any wild-card (both of these particles are part of an XML Schema sequence compositor). In this scenario cardinality of particles takes precedence than presence of a concrete element in derived type, when determining valid particle derivations.

For e.g <xs:element name="x" type="xs:string" minOccurs="0"/> is not a valid restriction of <xs:any processContents="lax" />, since the effective cardinality of element "x" (minOccurs="0" means that particle "x" is optional) is more than that of the wild-card particle (is mandatory).

a.2 There must be a similar (i.e X-to-X where X is a positive numerical value) mapping of particles from a schema 'base' to 'derived' type. i.e a derived type cannot have less number of particles than those in base type, and a particle in derived type must validly derive (i.e is subsumed validly as per rules specified in XML Schema 1.1 spec) from the corresponding particle in base schema type.

B) ALL TO SEQUENCE RESTRICTIONS
b.1 This is a valid schema compositor (and of particles in them) restriction (i.e ordered from unordered restriction).

For e.g sequence(b, a) and sequence(a, b) {order of particles in derived type doesn't matter} are valid restrictions of all(a, b).

b.2 Identity of particles (recognized by QName of the particles) is recognized by the XML schema validator, and corresponding such particles must obey rules of restriction by cardinality (i.e an optional characteristic of particle does not make particle a valid restriction of a mandatory particle, where QName's of corresponding such particles in base and derived types are same).

C) ALL TO ALL RESTRICTIONS
c.1 This is an unordered to unordered kind restriction. Concrete element particle is an valid derivation of a wild-card particle.

c.2 Cardinality of identical particles (having same QName's) in derived type must be same or less (which makes the derived particle validly derive from the corresponding particle from base type) than that in base type. Particle cardinalities take precedence over generic/concrete relationship between particles, when determining valid particle subsumptions.

c.3 Number of leaf particles (which are essentially xs:element and xs:any wild-card's) in derived and base types must be equal.

D) SEQUENCE TO ALL RESTRICTIONS
This is not a valid schema compositor restriction (i.e from ordered to unordered).

E) CHOICE TO SEQUENCE RESTRICTIONS
e.1 Here are few examples explaining some of the rules for this category.
  <xs:sequence>
     <xs:element name="c" type="xs:string" />
  </xs:sequence>

is a valid restriction of
  <xs:choice>  
     <xs:any processContents="lax" />
     <xs:element name="b" type="xs:string" />
  </xs:choice>

(the element particle "c" is subsumable by the wild-card)

e.2
  <xs:sequence>
     <xs:any processContents="lax" />
  </xs:sequence>

is not a valid restriction of
  <xs:choice>         
     <xs:element name="a" type="xs:string" />
     <xs:element name="b" type="xs:string" />
  </xs:choice>

This is so because a wild-card is not a valid subsumption of an element particle (i.e generic derivations from concrete elements is not a valid restriction, which in fact looks like an "type extension" concept).

F) SEQUENCE TO CHOICE RESTRICTIONS
Here's an example I can think over that correspond to use case of such kinds.
   
   <xs:restriction base="TYPE_BASE">
      <xs:choice>
         <xs:group ref="myGroup" />
      </xs:choice>
   </xs:restriction>
   
   is a valid restriction of
   
   <xs:complexType name="TYPE_BASE">
      <xs:group ref="myGroup" />
   </xs:complexType>
   
   <xs:group name="myGroup">
      <xs:sequence>
         <xs:element name="a" type="xs:string" />
         <xs:element name="b" type="xs:string" />
      </xs:sequence>
   </xs:group>

But this is not a useful schema type restriction, since the result of choice (i.e the schema particle produced from xs:choice) in derived type results only in one option, which is same as the contents of the sequence of the base type.

Other than the above example I cannot envision any other useful example for practical scenarios for "sequence to choice" restriction. I would imagine that schema authors must not bother much about "sequence to choice" restriction scenarios, as this doesn't looks a good and useful schema design scenario (but I don't deny that people may find valid uses of this as well :).

G) CHOICE TO CHOICE RESTRICTIONS
Here are few of the examples I can think of that satisfy this use-case (these I've found to be working fine with Xerces as well):

g.1 choice(a, c) is not a valid restriction of choice(a, b). Because element "c" in derived type doesn't have a corresponding element particle in the base type.

g.2
- choice(a, b) is a valid restriction of choice(a, wild-card processContents="lax"). If the wild-card can resolve to an element declaration that doesn't match element declaration "b", then this is NOT-A-VALID restriction.
- choice(a, b) is a valid restriction of choice(a, wild-card processContents="strict") if wild-card can resolve to an element decleration for "b" OTHER-WISE not.

g.3 choice(group name="myGroup", a) is a valid restriction of choice(group name="myGroup", xs:any processContents="lax"). Here model group instance is considered as a particle. But if the wild-card resolves to an element declaration that doesn't match element declaration "a", then this is NOT-A-VALID restriction.

g.4 choice(group name="myGroup", a) is not a valid restriction of choice(group name="myGroup", <xs:any/>). But this is a valid restriction if wild-card <xs:any> can find definition of element "a" which can derive (i.e is a valid subsumption) to element "a" in the derived type.

These are all the cases I can think of at the moment (enumerated A to G) which might occur for restriction between XML Schema 1.1 complexType's. I believe there would be few more complexType restriction cases which I'll try to post on this blog as I discover them.

I hope that this post was useful.

Saturday, October 23, 2010

XSD: schema type definition for empty XML content models

I'm inclined to write a little post, suggesting a correction (perhaps a better schema design) to an XML schema document I wrote in the blog post, http://mukulgandhi.blogspot.com/2010/07/xsd-11-xml-schema-design-approaches.html [1].

In this post [1], I suggested the following XML schema type definition for empty content models (I assume there would not be any attributes on an element):
  <xs:complexType name="EMPTY"> 
     <xs:complexContent> 
        <xs:restriction base="xs:anyType" /> 
     </xs:complexContent> 
  </xs:complexType>

Instead of the above schema type definition, I find the following (which is simpler I believe) schema type definition [2] (intending to constrain an XML element) to be better instead:
  <xs:element name="X">
    <xs:complexType/>
  </xs:element>

The element definition [2] above intends to validate an XML fragment like following:
<X/>

In the above example, I intend to suggest that there must not be any child nodes (and neither any XML attributes on an element) within element "X". Interestingly (nothing new really for people knowing XML schema language :) the XML Schema language, only allows constraining XML element and attribute nodes (and optionally these being XML namespace aware) and it doesn't bother about other XML infoset components like comments, processing-instructions and so on (which are present in XPath data model for example) [A] -- this means that any other kinds of nodes, than XML elements and attributes are ignored by XML Schema language and a compliant XML schema validator. This nature [A] of XML schema language is OK as I've learnt (there have been some nice discussions about all of this at XML-DEV list in recent past).

2010-10-26: Here's another variant for definition of empty XML content models.
  <xs:simpleType name="EMPTY">
     <xs:restriction base="xs:string">
        <xs:maxLength value="0"/>
     </xs:restriction>
  </xs:simpleType>

This defines an XML schema 'simpleType' -- and enforces content emptiness with the schema 'maxLength' facet on type xs:string, instead of a complex type as defined in the previous example. I'm more inclined to define element emptiness by an simpleType like above, since intent (and semantics) of schema simple types is never to define XML attributes, but those of complexType are.

I hope the corrections I've shared in this post is appreciated by folks who've read my earlier post cited above [1].

Sunday, October 10, 2010

XSD 1.1: XML schema design approaches cotd... PART 4

In this blog post i'm trying to describe (I find the subject matter here interesting enough to have a new blog post!) few more XML Schema (i'm trying to cook-up XSD 1.1 examples :) use-cases - using largely XSD 1.1 assertions which are now solvable with XML Schema 1.1 (for example constraining cardinality of XML Schema xs:list items as described below), and as per my view-point couldn't be solved with XML Schema 1.0.

I hope, XML Schema community might find few of the things here interesting.

This post can be considered the PART 4 of the XML Schema 1.1 design series that I started couple of weeks ago. The previous parts of this series are available here:

1) PART 1
2) PART 2
3) PART 3

I'm using latest XML Schema 1.1 code-base from Xerces-J SVN repos.

Use-case: (A)
The examples in this post illustrate, how we can constrain the cardinality of XML Schema 1.1 xs:list instance members, and optionally constraining (just to verify myself how XSD 1.1 assertions behave in various combinations) few aspects of list members (like for example that, list items need to be even integers).

Here's an XML instance document (this describes a simple enough list of integers encapsulated in an XML element "X"), which I'll use for illustrations in this post:

[XML 1] (named temp.xml)
  <X>2 4 6 5 10 3</X>

Below are few XML Schema 1.1 examples (with Schema 1.1 instructions highlighted with different color), and explanations from my point of view thereafter:

[XML Schema 1]
  <?xml version='1.0'?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   
    <xs:element name="X">
       <xs:complexType>
         <xs:simpleContent>
            <xs:restriction base="INT_LIST">
              <xs:assertion test="count($value) le 5" />
            </xs:restriction>
         </xs:simpleContent>
       </xs:complexType>
    </xs:element>
   
    <xs:complexType name="INT_LIST">
       <xs:simpleContent>
         <xs:restriction base="xs:anyType">
            <xs:simpleType>
               <xs:list itemType="xs:integer" />          
            </xs:simpleType>
            <xs:assert test="every $x in $value satisfies ($x mod 2 = 0)" />
         </xs:restriction>
       </xs:simpleContent> 
    </xs:complexType>

  </xs:schema>

[XML Schema 2]
  <?xml version='1.0'?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   
     <xs:element name="X">
        <xs:simpleType>
          <xs:restriction base="INT_LIST">
             <xs:assertion test="$value mod 2 = 0" />
          </xs:restriction>
        </xs:simpleType>
     </xs:element>
   
     <xs:simpleType name="INT_LIST">
       <xs:list itemType="xs:integer" />
     </xs:simpleType>

  </xs:schema>

[XML Schema 3]
  <?xml version='1.0'?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   
    <xs:element name="X">
      <xs:complexType>
        <xs:simpleContent>
          <xs:extension base="INT_LIST">
             <xs:assert test="count($value) le 5" />
          </xs:extension>
        </xs:simpleContent>
      </xs:complexType>
    </xs:element>
   
    <xs:simpleType name="INT_LIST">
       <xs:list itemType="xs:integer" />
    </xs:simpleType>

  </xs:schema>

Here are results of XML instance (of document [XML 1]) validation, with the specified schema's:

1. When XML document ([XML 1]) is validated by the schema [XML Schema 1], we get following validation outcomes with Xerces:
[Error] temp.xml:1:20: cvc-assertion.3.13.4.1: Assertion evaluation ('every $x in $value satisfies ($x mod 2 = 0)') for element 'X' with type 'INT_LIST' did not succeed.
[Error] temp.xml:1:20: cvc-assertion.3.13.4.1: Assertion evaluation ('count($value) le 5') for element 'X' with type '#anonymous' did not succeed.


2. When XML document ([XML 1]) is validated by the schema [XML Schema 2], we get following validation outcomes (with Xerces):
[Error] temp.xml:1:20: cvc-assertion.3.13.4.1: Assertion evaluation ('$value mod 2 = 0') for element 'X' with type '#anonymous' did not succeed. Assertion failed for an xs:list member value '5'.
[Error] temp.xml:1:20: cvc-assertion.3.13.4.1: Assertion evaluation ('$value mod 2 = 0') for element 'X' with type '#anonymous' did not succeed. Assertion failed for an xs:list member value '3'.


3. When XML document ([XML 1]) is validated by the schema [XML Schema 3], we get following validation outcomes (with Xerces):
[Error] temp.xml:1:20: cvc-assertion.3.13.4.1: Assertion evaluation ('count($value) le 5') for element 'X' with type '#anonymous' did not succeed.

Here's some quick analysis from my point of view, with regards to what I wanted to achieve with these use-cases (A):

The XML Schema 1.1 assertions XPath 2.0 context variable "$value" has a type annotation xs:anyAtomicType*.

1. The first validation result (1. above) illustrates that every item of xs:list needs to be an even integer, and number of list items are constrained to be maximum "5" (this is a sample "max" limit on number of list items).

2. I intended to use validation results 2. and 3. in combination doing an boolean "AND" of them, essentially to have same XML instance validation objective as case 1. The boolean "AND" of two schema validations can be achieved with for example, Java JAXP validation API. I wrote XML Schema document, [XML Schema 2] to have the XML Schema validator return each individual list item, which do not pass test of mathematical evenness (this was not entirely achieved with schema document [XML Schema 1] -- where the schema detected an evenness failure for whole list instance, but didn't report every individual list item which didn't pass evenness test).

I hope the intent of the use-case described here, and the solutions offered are explained clear enough for XML Schema audience.

Thanks for reading, and as usual I hope that this blog post was interesting!

Sunday, September 5, 2010

XSD 1.1: Xerces-J implementation updates

Over the past one or two months, there have been few interesting changes happening at Xerces-J XML Schema 1.1 implementation. I feel obliged to share these enhancements with the XML Schema community, and also with folks at Eclipse WTP (where we enhanced few "schema aware" components of PsychoPath XPath 2.0 engine, to support these recent Xerces enhancements -- I think we improved the design of typed values of XML element and attribute XDM nodes in PsychoPath XPath2 engine, in case the XDM node has a type annotation of kind XML Schema simpleType, with varieties list or union).

Here's a summary of XML Schema 1.1 implementation changes that have recently been completed with Xerces (available at Xerces SVN repos as of now), which are planned to be part of the Xerces-J 2.11.0 release, planned to take please during November 2010 time frame.

1. Xerces-J now has a complete implementation of XML Schema 1.1 conditional inclusion functionality. The Xerces-J 2.10.0 release had implementation of XML Schema 1.1 conditional inclusion vc:minVersion and vc:maxVersion attributes. Xerces-J now supports all of "conditional inclusion" attributes as specified by the XML Schema 1.1 spec. The "conditional inclusion" attributes that are now newly supported in Xerces-J are: vc:typeAvailable, vc:typeUnavailable, vc:facetAvailable and vc:facetUnavailable. All of XML Schema 1.1 built-in types and facets are now supported by Xerces-J related to XML Schema 1.1 "conditional inclusion" components.

2. There are few interesting changes that have happened to Xerces-J XML Schema 1.1 assertions implementation as well, that are planned to be part of Xerces-J 2.11.0 release. Xerces now has an improved assertions evaluation processing on XML Schema (1.1) simple types, with varieties 'list' and 'union'.

2.1 Enhancements to assertions evaluation on simpleType -> list:

Here's an example of XML Schema 1.1 assertions on an xs:list schema component:
[XML Schema 1]
   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

      <xs:element name="Example" type="EXAMPLE_LIST" />
   
      <xs:simpleType name="EXAMPLE_LIST">
         <xs:list>
            <xs:simpleType>
               <xs:restriction base="xs:integer">
                  <xs:assertion test="$value mod 2 = 0" />
               </xs:restriction>
            </xs:simpleType>
         </xs:list>
      </xs:simpleType>
   
   </xs:schema> 

If an XML instance document has a structure something like following:
[XML 1]
<Example>1 2 3</Example>

And if this XML instance document ([XML 1]) is validated by the above XML schema ([XML Schema 1]), Xerces-J would report error messages like following (assuming the name of XML document was, test.xml):
[Error] test.xml:1:25: cvc-assertion.3.13.4.1: Assertion evaluation ('$value mod 2 = 0') for element 'Example' with type '#anonymous' did not succeed. Assertion failed for an xs:list member value '1'.
[Error] test.xml:1:25: cvc-assertion.3.13.4.1: Assertion evaluation ('$value mod 2 = 0') for element 'Example' with type '#anonymous' did not succeed. Assertion failed for an xs:list member value '3'.


An assertion must evaluate on every 'simpleType -> list' item (which is validated by the itemType of xs:list) in an XML instance document. Xerces now does this, and needed error messages are displayed in case of schema assertion failures.

2.2 Enhancements to assertions evaluation on simpleType -> union:

Here's an example of XML Schema 1.1 assertions on an xs:union schema component:
[XML Schema 2]
   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   
      <xs:element name="Example">
         <xs:simpleType>
            <xs:union memberTypes="MYDATE xs:integer" />
         </xs:simpleType>
      </xs:element>
   
      <xs:simpleType name="MYDATE">
         <xs:restriction base="xs:date">
            <xs:assertion test="$value lt current-date()" />
         </xs:restriction>
      </xs:simpleType>

   </xs:schema>

If an XML instance document has a structure something like following:
[XML 2]
<Example>2010-12-05</Example>

And this instance document is validated by the schema document, [XML Schema 2] the following error message is displayed by Xerces:
[Error] temp.xml:1:30: cvc-assertion.union.3.13.4.1: Element 'Example' with value '2010-12-05' is not locally valid. One or more of the assertion facets on an element's schema type, with variety union, have failed.

Xerces tried to validate an atomic value '2010-12-05' both with schema types xs:integer and MYDATE. Since none of these types could successfully validate this atomic value, and an assertion failed in the process of these validation checks, the relevant assertion failure was reported by Xerces.

If the XML schema, [XML Schema 2] tries to validate the XML instance document:
<example>10</Example>

no validation failures are reported in this case, since an atomic value '10' conforms to the schema type xs:integer, which results in an overall validation success of the atomic value with an 'union' schema type.

I'm ending this blog post now. Stay tuned for more news here :)

And I hope, that this post was useful.

Saturday, July 17, 2010

XSD 1.1: XML schema design approaches cotd... PART 3

I'm continuing with the XML Schema design thoughts series, with the third part here. The first two parts are available here:
1) PART 1
2) PART 2

All the examples here have been tested with Xerces-J 2.10.0.

(I'm disclaiming in the beginning, that examples presented in this blog post are somewhat fictitious and may not serve a real life use-case. These examples are kind of cooked-up to only illustrate XML Schema 1.1 constructs, and some of design thinking behind them. I also refer at lot of places a phrase "element particles". This simply means XML elements, but "particles" is a formal term defined by the XML Schema spec, designating XML schema components having minOccurs and maxOccurs attributes -- if minOccurs/maxOccurs attributes are absent, then these have default values for the relevant schema components)

I'm presenting a sample 1.1 XML schema with corresponding XML document first, and then attempting trying to reflect on the inherent design from my point of view in these examples:

XML Schema 1.1 specific constructs are emphasized with a different color.

[XML1]
  <Book>
     <name>XML in a Nutshell</name>
     <ISBN>AB-1001</ISBN>
     <author>Jimmy</author>
     <NoPages>100</NoPages>
  </Book>

[XML Schema 1]
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
     <xs:element name="Book">
        <xs:complexType>
          <xs:complexContent>
            <xs:extension base="BOOK_FRAGMENT">
               <xs:openContent>
                 <xs:any processContents="lax" />
               </xs:openContent>
               <xs:assert test="not(* except (name, author, ISBN, NoPages)) and 
                                 (if (ISBN)
                                    then not(ISBN/*) 
                                    else true()) and 
                                 (if (NoPages) 
                                     then (not(NoPages/*) and (NoPages/text() castable as xs:positiveInteger))
                                     else true())" />    
            </xs:extension>
          </xs:complexContent>          
        </xs:complexType>
     </xs:element>
   
     <xs:complexType name="BOOK_FRAGMENT">
        <xs:sequence>
          <xs:element name="name" type="xs:string" />
          <xs:element name="author" type="xs:string" />
        </xs:sequence>
     </xs:complexType>

  </xs:schema>

The following use-case requirements motivated me to write this sample (I'm also trying to reflect on the schema design choices I've made, about which I surely invite comments from the readers -- if you've patience to read this post and respond!):
1. XML Schema 1.0 has a limitation that, when a complex type (having sequence or choice particles) is derived by extension then a derived complex type can only add element particles at the end of an element list (within the base type). Supposing that we want to re-use a complex type (having a sequence of element particles) by deriving it with extension, and need to add additional element particles say any-where in between the elements of the base type. This is what the above XML schema (XML Schema 1) example intends to do; and the above schema does indeed validates successfully the corresponding XML document presented above (XML1).

2. A key design decision in the above schema (XML Schema 1) is to use the XML Schema 1.1 "openContent" instruction (newly introduced in 1.1 version). The use of XSD 1.1 assertions here is optional, but is very practical to do so (which I'll try to explain!). An XML schema "openContent" instruction is essentially a wrapper around xs:any wild-card, producing the same effect as xs:any wild-card but has an interleave or a suffix appending behavior (please feel free to read the XML Schema 1.1 spec to learn more about XSD 1.1 open contents. Or perhaps if you want a lighter [but brilliant] explanation, you may read Roger L. Costello's XML Schema 1.1 write-up available here).
The XML Schema 1.1 spec defines an "openContent" instruction as following:
  <openContent
     id = ID
     mode = (none | interleave | suffix) : interleave
     {any attributes with non-schema namespace . . .}>
     Content: (annotation?, any?)
  </openContent>
It is an openContent instruction with "interleave" mode (which is the default openContent mode), which enables adding additional element particles interspersed between base type's element particles.

3. In the above example, the XML elements "ISBN" and "NoPages" are added to the base type's element particles which are not appended at the end of base type's elements, but can be added anywhere within the resulting XML content model. For this particular example, the placement of XML elements coming from the derived complex type are arbitrary, and is done to only illustrate the workings of "openContent" instruction in "interleave" mode.

4. It's interesting to see the benefit of XSD 1.1 assertions here. The assertions here are able to impose certain constraints on the resultant content model (otherwise the content model is kind-of wide open with no restrictions). The assertions in the above schema document (XML Schema 1) mean:
  a) The resulting content model can only have XML elements -> "name", "author", "ISBN" and "NoPages".
  b) The element "ISBN" needs to be an atomic string value, and the element "NoPages" needs to be an xs:positiveInteger value.

I'm presenting below another XML schema variant (than the example above -- XML Schema 1), which solves the same problem as described above, but in a slightly different way (with advantages and disadvantages described after the example):

[XML Schema 2]
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
      <xs:element name="Book">
         <xs:complexType>
            <xs:complexContent>
               <xs:extension base="BOOK_FRAGMENT">
                  <xs:openContent>
                     <xs:any processContents="strict"/>
                  </xs:openContent>
                  <xs:assert test="count(distinct-values(for $elem in (* except (name, author)) return $elem/name())) = count(for $elem in (* except (name, author)) return $elem/name())"/>       
               </xs:extension>
            </xs:complexContent>          
         </xs:complexType>
      </xs:element>
   
      <xs:complexType name="BOOK_FRAGMENT">
         <xs:sequence>
           <xs:element name="name" type="xs:string"/>
           <xs:element name="author" type="xs:string"/>
         </xs:sequence>
      </xs:complexType>
   
      <xs:element name="ISBN" type="xs:string" />
   
      <xs:element name="NoPages" type="xs:positiveInteger" />

   </xs:schema>

The example XML document for this schema (XML Schema 2) remains same (XML1). Here are the advantages (and unfortunately a little disadvantage as well, with a suggested workaround for the drawback...) of the sample, XML Schema 2:
1. Here we are using xs:any wild-card with processContents="strict" mode (the earlier example used the wild-card with "lax" mode) and providing the corresponding element declarations in the schema (the last two element declarations). This approach has advantage that, the content model of elements "ISBN" and "NoPages" are enforced natively by the XML schema engine, and the schema author doesn't have to implement the content model constraints herself/himself (for example, that an element is empty and has an atomic value) -- say via assertions. This approach is more robust, than trying to achieve the similar effect with assertions.

2. The assertion in schema document, [XML Schema 2] enforces that elements in the sequence could occur only once. This is accomplished by this simple algorithm:
count(distinct-values(names...)) = count(names...)

3. The only drawback I foresee with XML Schema 2, is that elements "ISBN" and "NoPages" are now global elements (which is necessary to have xs:any wild-card to work with processContents="strict" mode). This has implication that following XML documents would be reported valid as well, by the schema document XML Schema 2:
  <ISBN>AB-1001</ISBN>
AND
  <NoPages>100</NoPages>

This is a side-effect of schema document XML Schema 2, which I myself personally don't seem to like :(

To solve this limitation, I can imagine there could be a workaround as following:
We could perform two validations in sequence. One with the schema document, [XML Schema 2] (let's call this validation V1) and the second one with the following schema document (let's call this validation result V2):

[XML Schema 3]
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      
      <xs:element name="ISBN" type="xs:string" />
   
      <xs:element name="NoPages" type="xs:positiveInteger" />

  </xs:schema>

This is kind of a little validation pipeline. The complete/end-to-end (which usually means, that this has domain meaning) schema validation succeeds in entirety, if validation V1 succeeds but V2 doesn't (I imagine, that this kind-of pipeline operation could be enforced by a host language, like Java using the XML Schema JAXP APIs).

Thanks for reading!

I hope that this post is useful.