使用包含的 Schematron 因规则匹配不明确而失败

Schematron Using Include Fails With Ambiguous rule match

我正在 运行 根据我的包含语句的 schematron 规则设置核心 schematron XSLT(从 http://schematron.com/front-page/the-schematron-skeleton-implementation/ 下载)。当尝试 运行 要通过中间 XSL 测试的 XML 实例时,对于包含的 schematron 中存在的每个规则,它会失败并显示 'Ambiguous rule match for'。

"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".

检查生成的中间 XSL 后,似乎包含在所包含的 schematron 文件中的规则两次呈现到中间 XSL 中。检查 XSL 文件 iso_schematron_skeleton_for_saxon.xsl,看起来 iso:include 使用模式节点和规则节点调用规则模板,导致数据重复。

我本以为 github 上的 schematron XSLT 是 schematron 规范的最终实现。是不是这样,或者任何人都可以对此发表评论,因为我认为必须调整 schematron XSLT 才能使其工作对我来说是不正确的吗?

基础架构

<?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('&#127;application/json&#127;application/msword&#127;application/pdf&#127;application/vnd.oasis.opendocument.text&#127;application/vnd.openxmlformats-officedocument.wordprocessingml.document&#127;application/xml&#127;',concat('&#127;',.,'&#127;')) ) ) ">Invalid binary format code value.</assert>
   </rule>
</pattern>

我忘记提及的另一件事是,如果我只是使用像 Oxygen 或 XML buddy 这样的 XML 编辑器来使用我的 schematron 来验证 XML 实例,它就可以工作很好。

当我使用 Oxygen 加载我的 Test.sch 和 iso_schematron_message_xslt2.xslt 时,生成的 XSLT 如下所示。在中途你会看到在 ExternalTestPattern.sch (match="nc:BinaryFormatText") 中定义的规则模板是重复的:

<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('&#127;application/json&#127;application/msword&#127;application/pdf&#127;application/vnd.oasis.opendocument.text&#127;application/vnd.openxmlformats-officedocument.wordprocessingml.document&#127;application/xml&#127;',concat('&#127;',.,'&#127;')) ) ) "/>
         <xsl:otherwise>
            <xsl:message>Invalid binary format code value. (( false() or ( contains('&#127;application/json&#127;application/msword&#127;application/pdf&#127;application/vnd.oasis.opendocument.text&#127;application/vnd.openxmlformats-officedocument.wordprocessingml.document&#127;application/xml&#127;',concat('&#127;',.,'&#127;')) ) ))</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('&#127;application/json&#127;application/msword&#127;application/pdf&#127;application/vnd.oasis.opendocument.text&#127;application/vnd.openxmlformats-officedocument.wordprocessingml.document&#127;application/xml&#127;',concat('&#127;',.,'&#127;')) ) ) "/>
         <xsl:otherwise>
            <xsl:message>Invalid binary format code value. (( false() or ( contains('&#127;application/json&#127;application/msword&#127;application/pdf&#127;application/vnd.oasis.opendocument.text&#127;application/vnd.openxmlformats-officedocument.wordprocessingml.document&#127;application/xml&#127;',concat('&#127;',.,'&#127;')) ) ))</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>

任何启发都会非常有帮助。 谢谢

确保通过应用 readme 中列出的转换序列将 Schematron 编译成 XSLT,使用先前 XSLT 转换的输出作为下一步的输入:

1) First, preprocess your Schematron schema with iso_dsdl_include.xsl. This is a macro processor to assemble the schema from various parts. If your schema is not in separate parts, you can skip this stage. This stage also generates error messages for some common XPath syntax problems.

2) Second, preprocess the output from stage 1 with iso_abstract_expand.xsl. This is a macro processor to convert abstract patterns to real patterns. If your schema does not use abstract patterns, you can skip this stage.

3) Third, compile the Schematron schema into an XSLT script. This will typically use iso_svrl_for_xslt1.xsl or iso_svrl_for_xslt2.xsl (which in turn invoke iso_schematron_skeleton_for_xslt1.xsl or iso_schematron_skeleton_for_saxon.xsl) However, other "meta-stylesheets" are also in common use; the principle of operation is the same. If your schema uses Schematron phases, supply these as command line/invocation parameters to this process.

4) Fourth, run the script generated by stage 3 against the document being validated. If you are using the SVRL script, then the output of validation will be an XML document. If your schema uses Schematron parameters, supply these as command line/invocation parameters to this process.

此外,请确保您正在应用 iso_svrl_for_xslt2.xsl(导入 iso_schematron_skeleton_for_saxon.xsl)而不是直接使用 iso_schematron_skeleton_for_saxon.xsl