Xpath result vs. xs:assert result

This should cover W3C XML Schema, Relax NG and DTD related problems.
twcook
Posts: 23

Xpath result vs. xs:assert result

Thu Mar 19, 2015 4:11 pm

XML Editor 16.1 using SaxonEE set for XML Schema 1.1

I want to insure that elements in a complexType that is a restriction of a base complexType, have the same number of enumerations. (Code below)

The sample below should fail this assert:

Code: Select all

<xs:assert test="count(//xs:element[@name='id-name']//xs:enumeration) eq count(//xs:element[@name='issuer']//xs:enumeration)
and
count(//xs:element[@name='issuer']//xs:enumeration) eq count(//xs:element[@name='assignor']//xs:enumeration)"></xs:assert>


because assignor has three enumerations and the other elements have two. Whether I put this in the base complexType or the restricted complexType it still shows the restriction as a valid schema.

If I execute this

Code: Select all

count(//xs:element[@name='id-name']//xs:enumeration) eq count(//xs:element[@name='issuer']//xs:enumeration) and
count(//xs:element[@name='issuer']//xs:enumeration) eq count(//xs:element[@name='assignor']//xs:enumeration)


in the XPath editor it fails as expected as well as passes when all three have two enumerations.

Sample restriction:

Code: Select all

 <xs:complexType name='mytype' xml:lang='en-US'>
    <xs:complexContent>
      <xs:restriction base='myBaseType'>
        <xs:sequence>
            <xs:element maxOccurs='1' minOccurs='1' name='id-name'>
              <xs:simpleType>
                <xs:restriction base='xs:string'>
                  <xs:enumeration value='URI'></xs:enumeration>
                  <xs:enumeration value='ID Number'></xs:enumeration>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element maxOccurs='1' minOccurs='1' name='issuer'>
              <xs:simpleType>
                <xs:restriction base='xs:string'>
                  <xs:enumeration value='Owner'/>
                  <xs:enumeration value='Owner'/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element maxOccurs='1' minOccurs='1' name='assignor'>
              <xs:simpleType>
                <xs:restriction base='xs:string'>
                  <xs:enumeration value='Owner'/>
                  <xs:enumeration value='Owner'/>
                  <xs:enumeration value='Owner'/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
          </xs:sequence>
        </xs:restriction>
      </xs:complexContent>
    </xs:complexType>


Am I missing something in the assert?

Thanks.
Patrik
Posts: 216
Location: Hamburg/Germany

Re: Xpath result vs. xs:assert result

Fri Mar 20, 2015 9:11 am

So you want to use the xs:assert to validate your schema and not to validate the xml described by your schema, right?

In this case the xs:assert would need to be placed in the xsd describing your xsd. Since you probably don't want to extend the stadard xsd for this you could do this with an additional schematron file instead. This could look like this:

Code: Select all

<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
   <ns uri="http://www.w3.org/2001/XMLSchema" prefix="xs"/>
   <pattern>
      <rule context="xs:restriction[@base = 'myBaseType']">
         <let name="CountIdName"   value="count(.//xs:element[@name='id-name']   //xs:enumeration)"/>
         <let name="CountIssuer"   value="count(.//xs:element[@name='issuer']   //xs:enumeration)"/>
         <let name="CountAssignor" value="count(.//xs:element[@name='assignor']//xs:enumeration)"/>
         <assert test="($CountIdName eq $CountIssuer) and ($CountIssuer = $CountAssignor)">
            Number of enumerations needs to be the same for elements
            id-name (<value-of select="$CountIdName"/>),
            issuer (<value-of select="$CountIssuer"/>) and
            assignor (<value-of select="$CountAssignor"/>).
         </assert>
      </rule>
   </pattern>
</schema>


Now you have to validate your xsd file with this schematron file. Unfortunatly you can't assign the schematron to the xsd (at least for me it did not work) to validate it automatically. I tested it with

Code: Select all

<?xml-model href="XsdValidation.sch" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>


However, you could define your own document type in oxygen by deriving a new one from "xml schema". Here you can add the schematron file in the validation tab and mark it as standard validation.
Now you need to find a way to associate your xsd with this new document type rather then the original xsml schema. For testing purpose I simply used the file name of the xsd as association rule. (A "real" solution would probably require a java class to identifier the document type - that's at least what I'm planing to do for the extended validtion of my ofn xsd files.)
When you makred document type as a higher priority than the original one you should get following message in your example when validating it:

Code: Select all

Number of enumerations needs to be the same for elements id-name (2), issuer (2) and assignor (3).


Patrik
twcook
Posts: 23

Re: Xpath result vs. xs:assert result

Fri Mar 20, 2015 1:41 pm

Thanks for the description. I think I need something more generic and flexible than using the schematron approach. I need to re-think some other aspects of the overall system.
Patrik
Posts: 216
Location: Hamburg/Germany

Re: Xpath result vs. xs:assert result

Fri Mar 20, 2015 9:45 pm

Note that you can use any xpath and call xslt function in the schematron rules. Thus, i can hardly imagine anything more flexible than that. Didn't test it but you could probably even implement a very generic schematron rule that actually evaluates an xpath expression written in the xsd. Then you could actually define rules in the xsd to be applied to itself...
twcook
Posts: 23

Re: Xpath result vs. xs:assert result

Fri Mar 20, 2015 11:28 pm

Patrik wrote:Note that you can use any xpath and call xslt function in the schematron rules. Thus, i can hardly imagine anything more flexible than that. Didn't test it but you could probably even implement a very generic schematron rule that actually evaluates an xpath expression written in the xsd. Then you could actually define rules in the xsd to be applied to itself...


Thanks. Your intuition is correct. You can store schematron in an appinfo section, according to this http://www.topologi.com/resources/schtrn_xsd_paper.html

So I will investigate schematron further.
Patrik
Posts: 216
Location: Hamburg/Germany

Re: Xpath result vs. xs:assert result

Sat Mar 21, 2015 9:57 pm

Yes, it's possible to embed schematron rules in xsd. But youÄll have the same problem as with the xs:assert: it applies to the xsml file you're validating rather the the schema itself.

For demonstration (and fun) I implemented a simple "DerivedAssert" you can add into the xml schema that is being evaluated by a schematron file:

DerivedAssert.sch:

Code: Select all

<schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" queryBinding="xslt2">
   
    <ns uri="http://www.w3.org/2001/XMLSchema"      prefix="xs"/>
    <ns uri="derivedAssert"                         prefix="da"/>
   
    <xsl:include href="DerivedAssert.xsl"/>
   
    <pattern>
        <rule context="xs:complexType/xs:complexContent/xs:restriction[@base = $DerivedAssertList/@type]">
            <assert test="da:CheckAssertion(.)">
                <value-of select="da:Message(.)"/>
            </assert>
        </rule>
    </pattern>
   
</schema>


DerivedAssert.xsl:

Code: Select all

<xsl:transform
    xmlns:xsl   = "http://www.w3.org/1999/XSL/Transform"
    xmlns:xs    = "http://www.w3.org/2001/XMLSchema"
    xmlns:saxon = "http://saxon.sf.net/"
    xmlns:da    = "derivedAssert"
    exclude-result-prefixes="#all"
    version="2.0">


    <xsl:variable name="DerivedAssertList" as="element()*">
        <xsl:apply-templates select="/" mode="DerivedAssertList"/>
    </xsl:variable>

    <xsl:template match="element() | document-node()" mode="DerivedAssertList">
        <xsl:apply-templates select="*" mode="#current"/>
    </xsl:template>

    <xsl:template match="xs:complexType/xs:annotation/xs:appinfo/DerivedAssert" mode="DerivedAssertList">
        <xsl:copy>
            <xsl:attribute name="type" select="parent::*/parent::*/parent::*/@name"/>
            <xsl:copy-of select="@test, @message"/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="da:CheckAssertion" as="xs:boolean">
        <xsl:param name="Restriction" as="element(xs:restriction)"/>
        <xsl:variable name="DerivedAssert" as="element()?" select="$DerivedAssertList[$Restriction/@base = @type]"/>
        <xsl:choose>
            <xsl:when test="exists($DerivedAssert)">
                <xsl:for-each select="$Restriction">    <!-- set context -->
                    <xsl:sequence select="xs:boolean(saxon:evaluate($DerivedAssert/@test))"/>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:sequence select="true()"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>
   
    <xsl:function name="da:Message" as="xs:string">
        <xsl:param name="Restriction" as="element(xs:restriction)"/>
        <xsl:variable name="DerivedAssert" as="element()?" select="$DerivedAssertList[$Restriction/@base = @type]"/>
        <xsl:sequence select="$DerivedAssert/@message"/>
    </xsl:function>
   
</xsl:transform>


Test-xsd:

Code: Select all

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">

    <xs:complexType name="myBaseType">
        <xs:annotation>
            <xs:appinfo>
                <DerivedAssert
                    test    = "count(.//xs:element[@name='issuer']//xs:enumeration) = count(.//xs:element[@name='assignor']//xs:enumeration)"
                    message = "Number of enumerations needs to be the same for elements issuer assignor."/>
            </xs:appinfo>
        </xs:annotation>
        <xs:sequence>
            <xs:element name="issuer"   type="xs:string"/>
            <xs:element name="assignor" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="myType">
        <xs:complexContent>
            <xs:restriction base="myBaseType">
                <xs:sequence>
                    <xs:element name="issuer">
                        <xs:simpleType>
                            <xs:restriction base="xs:string">
                                <xs:enumeration value="Owner"/>
                                <xs:enumeration value="Owner"/>
                            </xs:restriction>
                        </xs:simpleType>
                    </xs:element>
                    <xs:element name="assignor">
                        <xs:simpleType>
                            <xs:restriction base="xs:string">
                                <xs:enumeration value="Owner"/>
                                <xs:enumeration value="Owner"/>
                                <xs:enumeration value="Owner"/>
                            </xs:restriction>
                        </xs:simpleType>
                    </xs:element>
                </xs:sequence>
            </xs:restriction>
        </xs:complexContent>
    </xs:complexType>
</xs:schema>


Now when validation the xsd with schematron.sch the rule from within the xsd (DerivedAssert/@test) is being evaluated and you get the message "Number of enumerations needs to be the same for elements issuer assignor.".

It's quite primitive but should point to a possible direction...
twcook
Posts: 23

Re: Xpath result vs. xs:assert result

Wed Mar 25, 2015 3:58 pm

Thanks for this Patrik.

It certainly looks like it is a start.

However, just copying the files into oXygen (saving them in the same directory) and setting a Validation scenario to use Saxon and embedded Schematron still shows a valid XSD.

I am not an oXygen guru so maybe I am missing something in the settings?

Image
Patrik
Posts: 216
Location: Hamburg/Germany

Re: Xpath result vs. xs:assert result

Wed Mar 25, 2015 7:17 pm

You need to validate the Test-xsd file against the schematron file DerivedAssert.sch
twcook
Posts: 23

Re: Xpath result vs. xs:assert result

Wed Mar 25, 2015 8:57 pm

Patrik wrote:You need to validate the Test-xsd file against the schematron file DerivedAssert.sch


Ahhh, duh. :roll:

I thought the validation scenario would 'magically' load the schematron file.

But yes it works as you described and I think this will work just fine.

Cheers,
Tim

Return to “XML Schemas”

Who is online

Users browsing this forum: No registered users and 1 guest