【问题标题】:Schematron Using Include Fails With Ambiguous rule matchSchematron 使用 Include 失败,规则匹配不明确
【发布时间】:2018-03-08 20:30:34
【问题描述】:

我正在运行核心 schematron XSLT(从 http://schematron.com/front-page/the-schematron-skeleton-implementation/ 下载)针对我的带有 include 语句的 schematron 规则。尝试通过中间 XSL 运行要测试的 XML 实例时,对于包含的 schematron 中存在的每个规则,它都会失败,并显示“不明确的规则匹配”。

"描述:不明确的规则匹配 /filing:FilingMessage/filing:FilingConnectedDocument[1]/ecf:DocumentAugmentation[1]/ecf:DocumentRendition[1]/nc:Attachment[1]/nc:BinaryFormatText[1] 两者都匹配 “{http://release.niem.gov/niem/niem-core/3.0/}BinaryFormatText”在文件的第 192 行:/C:/_working/misc/schematron/schematron/trunk/schematron/code/temp.xsl 和 “{http://release.niem.gov/niem/niem-core/3.0/}BinaryFormatText”在文件的第 175 行:/C:/_working/misc/schematron/schematron/trunk/schematron/code/temp.xsl 网址: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 以使其工作是正确的?

基本 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('&#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>

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

【问题讨论】:

  • 我无法重现。它在 oXygen 中验证,没有警告,我手动编译了 XSLT,没有看到在相同模式下匹配的重复模板。您可以发布生成的 XSLT 吗?链接到您认为可疑的 iso_schematron_skeleton_for_saxon.xsl 中的行? github.com/Schematron/schematron/blob/master/trunk/schematron/…
  • 谢谢麦兹。似乎导致问题的行是第 1260 行“ " 在模板
  • 您是否正在使用iso_schematron_message_xslt2.xslt 转换您的Schematron 文件?应该应用一系列转换,在将 Schematron 编译成 XSLT 时,输出将用作下一个 XSLT 的输入。

标签: xslt schematron


【解决方案1】:

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

1) 首先,使用 iso_dsdl_include.xsl 预处理您的 Schematron 模式。 这是一个宏处理器,用于从各个部分组装模式。 如果您的架构不在单独的部分中,则可以跳过此阶段。这 stage 还会为一些常见的 XPath 语法生成错误消息 问题。

2) 其次,预处理阶段 1的输出 iso_abstract_expand.xsl。这是一个宏处理器来转换 抽象模式到真实模式。如果您的架构不使用 抽象模式,你可以跳过这个阶段。

3) 第三,将 Schematron 模式编译成 XSLT 脚本。这 通常会使用iso_svrl_for_xslt1.xsliso_svrl_for_xslt2.xsl (依次调用 iso_schematron_skeleton_for_xslt1.xsliso_schematron_skeleton_for_saxon.xsl) 但是,其他 “元样式表”也很常用;工作原理 是一样的。如果您的架构使用 Schematron 阶段,请将这些提供为 此进程的命令行/调用参数。

4) 第四,针对文档运行阶段 3 生成的脚本 被验证。如果您使用的是 SVRL 脚本,则输出 验证将是一个 XML 文档。如果您的架构使用 Schematron 参数,将这些作为命令行/调用参数提供给此 过程。

另外,请确保您正在应用iso_svrl_for_xslt2.xsl(它导入iso_schematron_skeleton_for_saxon.xsl)并且没有直接使用iso_schematron_skeleton_for_saxon.xsl

【讨论】:

  • 再次感谢 Mads。显然我无法阅读。这两个预处理器通过将 schematron 和包含文件中的模式合并到一个文件中来达到目的,因此不会执行与 XSL 包含一起工作的 XSLT 段。这确实提出了另一个有助于我理解的问题。具体来说,如果两个预处理器将my base schematron 合并并包含在一起,那么在什么情况下会使用iso_schematron_skeleton_for_saxon.xsl 中的include 模板?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 2018-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多