检测 XSL 中的模板优先级冲突

Detecting template priority conflicts in XSL

我有一个 XSL 样式表,它导入许多其他 XSL 样式表,用于处理各种 XML 文件。我想检查 none 个导入的模板是否冲突。

例如,我有一个导入 import_one.xslimport_two.xsl.

的样式表

import_one.xsl 包含模板:

<xsl:template match="Foo">
   One
</xsl:template>

import_two.xsl包含一个模板:

<xsl:template match="Foo">
    Two
</xsl:template>

这两个模板都将以相同的优先级匹配 Foo 个元素,这是 XSL 处理器可以使用最后导入的模板恢复的错误。

对于一组给定的 XML 文件,我想检查是否会发生此类错误。

XSL 样式表包含 JavaScript 函数并使用 MSXSL 节点集,这使我无法使用例如撒克逊人,它会在发生此类冲突时发出警告。 MSXSL 处理器可以处理样式表,但不会发出警告。

我有哪些选择?

我觉得你可能需要考虑写一些简单的分析工具。这就是 XSLT 使用 XML 语法这一事实真正开始带来好处的地方:操纵 XSLT 代码比操纵大多数其他语言的代码要容易得多。如果您只需要了解相同的匹配模式,那么您可以使用 2.0 样式表来分析您的代码,该样式表执行类似

<xsl:function name="f:all-modules" as="document-node()*">
  <xsl:param name="root" as="document-node()"/>
  <xsl:sequence select="$root, document($root/*/(xsl:include|xsl:import)/@href)/f:all-modules(.)"/>
</xsl:function>

<xsl:template name="duplicate-patterns">
  <xsl:for-each-group select="f:all-modules(.)//xsl:template" 
        group-by="@match">
    <xsl:if test="current-group()[2]">
      <xsl:copy-of select="current-group()"/>
    </xsl:if>
  </xsl:for-each-group>
</xsl:template>

如果你想检测 "overlapping" 有多个匹配项的模式(例如 para[1]para[@class='header']),那么这不能通过静态分析来完成,你将需要做一些动态处理。一种方法可能是将现有样式表转换为 XSLT 2.0 样式表,该样式表针对每种模式测试每个元素。您可以通过为每个模式生成一个独特的模式来做到这一点。它可能看起来像这样:

<xsl:template match="para[1]" mode="mode-7826">1</xsl:template>
<xsl:template match="*" mode="mode-7826"/>

<xsl:template match="para[@class='header']" mode="mode-7827" as="xs:integer">1</xsl:template>
<xsl:template match="*" mode="mode-7827"/>

<xsl:template match="/">
    <xsl:for-each select="//*">
      <xsl:variable name="matches">
        <xsl:apply-templates select="." mode="mode-7826"/>
        <xsl:apply-templates select="." mode="mode-7827"/>
        <xsl:apply-templates select="." mode="mode-7828"/>
        ....
      </xsl:variable>
      <xsl:if test="string-length($matches) gt 1">
        Conflict!!
      </xsl:if>
    </xsl:for-each>
</xsl:template>