gpt4 book ai didi

xml - 使用 XSLT 2 时,Schematron 会忽略在其上下文中具有属性的规则

转载 作者:行者123 更新时间:2023-12-03 16:09:28 24 4
gpt4 key购买 nike

我发现 Schematron 会忽略任何具有 context 的规则。包含对属性的引用的属性。在下面的代码中,我有 @att但是任何包含属性的复杂 xpath 都会遇到问题。 (例如 bar/@att 也将被忽略。)

我正在使用 Schematron 分发的版本 here .

我有这个test.sch :

<?xml version="1.0" encoding="utf-8"?>
<schema
xmlns="http://purl.oclc.org/dsdl/schematron"
queryBinding="xslt2"
schemaVersion="ISO19757-3">
<title>Test schema.</title>
<pattern>
<rule context="@att">
<assert test="false()">@att cannot appear anywhere.</assert>
</rule>
<rule context="foo">
<assert test="false()">foo cannot appear anywhere.</assert>
</rule>
</pattern>
</schema>

这个 test.xml文件:
<foo att="something"/>

为了可复制,这个 Makefile :
SAXON:=saxon
SCHEMATRON_TO_XSL:=/home/ldd/src/schematron/xslt/iso_svrl_for_xslt2.xsl

.PHONY: all
all: test.xsl test.xml
$(SAXON) -xsl:$< -s:$(word 2,$^)

test.xsl: test.sch
$(SAXON) -s:$< -o:$@ -xsl:$(SCHEMATRON_TO_XSL) allow-foreign=true generate-fired-rule=false

.PHONY: clean
clean:
rm test.xsl

如果我发出 make clean; make ,我得到了一个失败的断言:
<svrl:failed-assert test="false()" location="/foo[1]">
<svrl:text>foo cannot appear anywhere.</svrl:text>
</svrl:failed-assert>

Schematron 忽略了 <rule context="@att"> 中的测试。 ,这也应该失败。为什么忽略规则?

请注意,如果我更改 test.sch使用 queryBinding="xslt1"并编辑 Makefile改变 SCHEMATRON_TO_XSL要使用 XSLT 1 的 schematron 转换,我确实得到了我所期望的两个失败。所以这个问题只有在使用 XSLT 2 时才会出现。

最佳答案

这是 Schematron 中的一个错误,它似乎至少从 2010 年开始就存在于 Schematron 的代码中,而且肯定是从 2011 年开始的。(自从 AFAIK 以来,很难判断它究竟是什么时候出现的,没有用于 Schematron 的公共(public)版本控制存储库。看看这个答案的结尾知道为什么我说它自 2011 年以来肯定存在。)

解释

如果您检查您的 test.xsl从 Schematron 生成的文件,您将看到 xsl:apply-templates像这样的元素:

<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M1"/>

注意属性节点不是 select 的一部分。 .

运行时执行的代码 saxon转换您的 test.sch文件导入名为 iso_schematron_skeleton_for_saxon.xsl 的模式.如果你检查那个文件,你会发现 xsl:apply-template出现在 XSL 中的元素是使用如下代码生成的:
<axsl:apply-templates select="{$context-xpath}" mode="M{count(preceding-sibling::*)}"/>

( axsl: 不是拼写错误。它是输出节点使用的命名空间前缀。)

在同一个文件中向后看,你会发现:
<xsl:variable name="context-xpath">
<xsl:if test="$attributes='true' and parent::node() ">@*|</xsl:if>
<xsl:choose>
<xsl:when test="$only-child-elements='true'">*</xsl:when>
<xsl:when test="$visit-text='true'">node()</xsl:when>
<xsl:otherwise>*|comment()|processing-instruction()</xsl:otherwise>
</xsl:choose>
</xsl:variable>

和:
<xsl:param name="attributes">
<xsl:choose>
<xsl:when test="//iso:rule[contains(@context,'@') or contains(@context,'attribute')]">true</xsl:when>
<xsl:otherwise>false</xsl:otherwise>
</xsl:choose>
</xsl:param>

问题出在 context-xpath 的方式上。被初始化。它是一个顶级变量,初始化一次,并且只初始化一次。在初始化的时候,上下文节点是文档的根节点所以 parent::node()总是假的,因此 @*|从未包含在 context-xpath 的值中.

以我的经验 attributes已正确初始化。所以没有必要摆弄它。

请注意,当您为 XSLT 1 处理器运行 Schematron 样式表时,将使用不同的代码库,它没有此错误。 (XSLT 1 等价于 iso_schematron_skeleton_for_saxon.xsliso_schematron_skeleton_for_xslt1.xsl )。

解决方案 1:重写规则

可以重写有问题的规则,使它们没有 context指的是属性。我不能说我是这个解决方案的粉丝,因为它使规则复杂化并且可能对性能产生严重的负面影响。并且可能存在无法重写规则的情况。

解决方案2:编辑 iso_schematron_skeleton_for_saxon.xsl
当我编辑到文件时,我不再遇到此问题,以便 context-path以这种方式初始化:
<xsl:variable name="context-xpath">
<xsl:if test="$attributes='true'">@*|</xsl:if>
<xsl:choose>
<xsl:when test="$only-child-elements='true'">*</xsl:when>
<xsl:when test="$visit-text='true'">node()</xsl:when>
<xsl:otherwise>*|comment()|processing-instruction()</xsl:otherwise>
</xsl:choose>
</xsl:variable>

一般来说,我不喜欢对第三方代码进行临时编辑,但我没有看到更好的解决方案。

佐证

完成上述调查后,我很清楚哪些关键字可以帮助我找到有关该主题的任何问题报告,因此我开始搜索 context-xpath和类似的关键字。我发现 Ken Holman 在 2011 年 12 月遇到了同样的问题, this email 证明了这一点。 .他得出了与我相似的结论。他还建议强制 attributes参数为真。根据我的经验,它没有必要。他提到的情况是 Schematron 代码被拆分到多个文件中,但 readme.txt对于 Schematron 来说,处理的第一步应该是运行 iso_dsdl_include.xsl将架构的多个部分组合到一个文件中。

AFAIK Ken Holman 的电子邮件从未收到回复,并且该问题从未在任何“官方”来源中得到解决。

关于xml - 使用 XSLT 2 时,Schematron 会忽略在其上下文中具有属性的规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40045725/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com