I am running the core schematron XSLT (as downloaded from http://schematron.com/front-page/the-schematron-skeleton-implementation/) against my schematron rules which have an include statement. When trying to run the XML instance to be tested through the intermediate XSL, it fails with 'Ambiguous rule match for' for each rule present in the included schematron.
"Description: Ambiguous rule match for /filing:FilingMessage/filing:FilingConnectedDocument[1]/ecf:DocumentAugmentation[1]/ecf:DocumentRendition[1]/nc:Attachment[1]/nc:BinaryFormatText[1] Matches both "{http://release.niem.gov/niem/niem-core/3.0/}BinaryFormatText" on line 192 of file:/C:/_working/misc/schematron/schematron/trunk/schematron/code/temp.xsl and "{http://release.niem.gov/niem/niem-core/3.0/}BinaryFormatText" on line 175 of file:/C:/_working/misc/schematron/schematron/trunk/schematron/code/temp.xsl URL: http://www.w3.org/TR/xslt20/#err-XTRE0540".
Upon inspecting the resulting intermediate XSL, it appears that the rules contained in the included schematron file are rendered into the intermediate XSL twice. Inspecting the XSL file iso_schematron_skeleton_for_saxon.xsl, it looks like the iso:include calls the rules template with both the pattern node and the rules node which results in the duplication of the data.
I would have assumed that the schematron XSLT on github is the definitive implementation of the schematron specification. Is that not the case or can anyone comment to this as I don't feel it is correct for me to have to tweak the schematron XSLT to make it work?
Base Schematron
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<title>Test Schematron Illustrating Transform Bug</title>
<ns prefix="x" uri="http://www.w3.org/TR/REC-html40"/>
<ns prefix="filing" uri="https://docs.oasis-open.org/legalxml-courtfiling/ns/v5.0/filing"/>
<ns prefix="nc" uri="http://release.niem.gov/niem/niem-core/3.0/"/>
<include href="ExternalTestPattern.sch"/>
<pattern id="ecf">
<rule context="/filing:FilingMessage">
<assert test="./nc:DocumentIdentification/nc:IdentificationID">DocumentID must be present.</assert>
</rule>
</pattern>
</schema>
ExternalTestPattern.sch Schematron
<?xml version="1.0" encoding="UTF-8"?>
<pattern xmlns="http://purl.oclc.org/dsdl/schematron" id="code-list-rules">
<!-- Required namespace declarations as indicated in this set of rules:
<ns prefix="nc" uri="http://release.niem.gov/niem/niem-core/3.0/"/> -->
<rule context="nc:BinaryFormatText">
<assert test="( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ) ">Invalid binary format code value.</assert>
</rule>
</pattern>
One other thing I forgot to mention is that if I simply use an XML editor like Oxygen or XML buddy to use my schematron to validate the XML instance, it works fine.
When I use Oxygen to load my Test.sch and also iso_schematron_message_xslt2.xslt, the resulting XSLT is below. Partway down you will see that the template for the rule defined in ExternalTestPattern.sch (match="nc:BinaryFormatText") is duplicated:
<xsl:stylesheet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:x="http://www.w3.org/TR/REC-html40" xmlns:filing="https://docs.oasis-open.org/legalxml-courtfiling/ns/v5.0/filing" xmlns:nc="http://release.niem.gov/niem/niem-core/3.0/" version="2.0">
<!--Implementers: please note that overriding process-prolog or process-root is the preferred method for meta-stylesheets to use where possible. -->
<xsl:param name="archiveDirParameter"/>
<xsl:param name="archiveNameParameter"/>
<xsl:param name="fileNameParameter"/>
<xsl:param name="fileDirParameter"/>
<xsl:variable name="document-uri">
<xsl:value-of select="document-uri(/)"/>
</xsl:variable>
<!--PHASES-->
<!--PROLOG-->
<xsl:output method="text"/>
<!--XSD TYPES FOR XSLT2-->
<!--KEYS AND FUNCTIONS-->
<!--DEFAULT RULES-->
<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-select-full-path">
<xsl:apply-templates select="." mode="schematron-get-full-path"/>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-get-full-path">
<xsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">
<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>*:</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>[namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()"/>
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:variable name="preceding" select="count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri() = namespace-uri(current())])"/>
<xsl:text>[</xsl:text>
<xsl:value-of select="1+ $preceding"/>
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="@*" mode="schematron-get-full-path">
<xsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">@<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>@*[local-name()='</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>' and namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()"/>
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-2-->
<!--This mode can be used to generate prefixed XPath for humans-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-2">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)"/>
<xsl:if test="preceding-sibling::*[name(.)=name(current())]">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text/>/@<xsl:value-of select="name(.)"/>
</xsl:if>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-3-->
<!--This mode can be used to generate prefixed XPath for humans
(Top-level element has index)-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-3">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)"/>
<xsl:if test="parent::*">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text/>/@<xsl:value-of select="name(.)"/>
</xsl:if>
</xsl:template>
<!--MODE: GENERATE-ID-FROM-PATH -->
<xsl:template match="/" mode="generate-id-from-path"/>
<xsl:template match="text()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')"/>
</xsl:template>
<xsl:template match="comment()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')"/>
</xsl:template>
<xsl:template match="processing-instruction()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')"/>
</xsl:template>
<xsl:template match="@*" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.@', name())"/>
</xsl:template>
<xsl:template match="*" mode="generate-id-from-path" priority="-0.5">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:text>.</xsl:text>
<xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')"/>
</xsl:template>
<!--MODE: GENERATE-ID-2 -->
<xsl:template match="/" mode="generate-id-2">U</xsl:template>
<xsl:template match="*" mode="generate-id-2" priority="2">
<xsl:text>U</xsl:text>
<xsl:number level="multiple" count="*"/>
</xsl:template>
<xsl:template match="node()" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number level="multiple" count="*"/>
<xsl:text>n</xsl:text>
<xsl:number count="node()"/>
</xsl:template>
<xsl:template match="@*" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number level="multiple" count="*"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="string-length(local-name(.))"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="translate(name(),':','.')"/>
</xsl:template>
<!--Strip characters--><xsl:template match="text()" priority="-1"/>
<!--SCHEMA SETUP-->
<xsl:template match="/">
<xsl:apply-templates select="/" mode="M0"/>
<xsl:apply-templates select="/" mode="M5"/>
</xsl:template>
<!--SCHEMATRON PATTERNS-->
<!--PATTERN code-list-rules-->
<!--RULE -->
<xsl:template match="nc:BinaryFormatText" priority="1000" mode="M0">
<!--ASSERT -->
<xsl:choose>
<xsl:when test="( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ) "/>
<xsl:otherwise>
<xsl:message>Invalid binary format code value. (( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ))</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M0"/>
</xsl:template>
<xsl:template match="text()" priority="-1" mode="M0"/>
<xsl:template match="@*|node()" priority="-2" mode="M0">
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M0"/>
</xsl:template>
<!--RULE -->
<xsl:template match="nc:BinaryFormatText" priority="1000" mode="M0">
<!--ASSERT -->
<xsl:choose>
<xsl:when test="( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ) "/>
<xsl:otherwise>
<xsl:message>Invalid binary format code value. (( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ))</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M0"/>
</xsl:template>
<!--PATTERN ecf-->
<!--RULE -->
<xsl:template match="/filing:FilingMessage" priority="1000" mode="M5">
<!--ASSERT -->
<xsl:choose>
<xsl:when test="./nc:DocumentIdentification/nc:IdentificationID"/>
<xsl:otherwise>
<xsl:message>DocumentID must be present. (./nc:DocumentIdentification/nc:IdentificationID)</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M5"/>
</xsl:template>
<xsl:template match="text()" priority="-1" mode="M5"/>
<xsl:template match="@*|node()" priority="-2" mode="M5">
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M5"/>
</xsl:template>
</xsl:stylesheet>
Any enlightenment would be really helpful. Thanks
iso_schematron_message_xslt2.xslt? There is a sequence of transforms that should be applied, with the output being used as the input for the next XSLT when compiling your Schematron into XSLT. - Mads Hansen