我正在使用 Schematron 在自定义模式感知 XML 编辑器中验证实例 XML 文档(请注意,Schematron 验证只是一个 XSLT 转换)。该实例可能包含在其值中带有路径的元素(简化的 XPath 表达式)。这种路径的一个例子是:
/p:root/p:level-one/r:level-two/r:level-two-leaf
其中两个前缀(p 和 r)都绑定到实例文档中定义的命名空间。我的 Schematron 通过确保路径指向的元素实际存在于实例文档中来验证此类路径。它依赖EXSLT来执行此操作(我被迫使用 XSLT1.0),更准确地说dyn:evaluate()
是为了评估元素的文本值,如您所见,它基本上是一个 XPath 表达式。它就像一个魅力。
但有一个问题,实际上是一个巨大的问题。调用从 Schematron XSLT 执行,该 XSLT在它自己的命名空间上下文中dyn:evaluate()
评估 XPath 表达式。这意味着为了使其正常工作,实例文档和 Schematron XSLT 必须使用完全相同的前缀 → 命名空间捆绑。我不能强制用户对我的架构中指定的相同命名空间使用相同的前缀......这将是一个愚蠢的要求(但确保至少在两者中使用相同的命名空间)。Schematron 总是在实例验证发生之前生成,但出于性能原因,这只执行一次。我唯一的选择是以某种方式预处理来自实例的路径,并进行某种从“实例路径”到“XSLT 路径”的转换。我是 XSLT 的新手,不知道如何实现这一点。
我如何将这些文本值转换为 XSLT 的名称空间上下文所需的内容?这甚至可能吗?我目前正在考虑在每次验证调用之前在内存中修复 XSLT(所有这些都在 Java 中完成)——重命名前缀以使其匹配实例绑定或注入新的命名空间属性——但这可能导致前缀名称冲突,我'不确定它将如何影响验证性能。我愿意接受任何建议,因为我假设这也是其他人必须遇到的事情(在使用 Schematron 或 时dyn:evaluate()
)。
编辑:从这里开始澄清我正在尝试做的事情。
我有一个用户正在编辑器中编辑的 XML 实例文件。这种文件的一个例子是:
<?xml version="1.0" encoding="utf-8"?>
<config xmlns="http://example.com/ns/config"
xmlns:cfg="http://example.com/ns/config"
xmlns:ns1="http://example.com/ns/custom-01"
xmlns:ns2="http://example.com/ns/custom-02">
<ns1:some-element>/cfg:config/ns1:other-element/ns2:nested-element</ns1:some-element>
<ns1:other-element>
<ns2:nested-element>some value</ns2:nested-element>
</ns1:other-element>
</config>
然后,这样的文档会通过 schematron 验证,这基本上是一个 XSLT 转换。ns1:some-element
只有当路径 in引用同一文档中的现有元素时,它才会被声明为有效(因此上面的示例是有效的)。
schematron XSLT 看起来像这样(注意它已经被大大简化了):
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--This XSLT was automatically generated from a Schematron schema.-->
<xsl:stylesheet xmlns:iso="http://purl.oclc.org/dsdl/schematron"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
xmlns:exsl="http://exslt.org/common"
xmlns:sch="http://www.ascc.net/xml/schematron"
xmlns:cfg="http://example.com/ns/config"
xmlns:cust1="http://example.com/ns/custom-01"
xmlns:cust2="http://example.com/ns/custom-02"
extension-element-prefixes="dyn exsl"
version="1.0">
<!-- other templates -->
<xsl:template match="/cfg:config/cust1:some-element">
<xsl:choose>
<xsl:when test="dyn:evaluate(.)">
<!-- do stuff -->
<xsl:when>
</xsl:choose>
</xsl:template>
<!-- other templates -->
</xsl:stylesheet>
我确信这可以解释问题。调用dyn:evaluate(.)
将尝试评估/cfg:config/ns1:other-element/ns2:nested-element
XPath 表达式,该表达式使用来自转换的预定义的未绑定前缀(因此始终评估为 false)。
问题过去和现在仍然是:如何翻译这些 XPath 表达式,以便它们在转换中真正有意义?