检测 XSL 中的模板优先级冲突
Detecting template priority conflicts in XSL
我有一个 XSL 样式表,它导入许多其他 XSL 样式表,用于处理各种 XML 文件。我想检查 none 个导入的模板是否冲突。
例如,我有一个导入 import_one.xsl
和 import_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>
我有一个 XSL 样式表,它导入许多其他 XSL 样式表,用于处理各种 XML 文件。我想检查 none 个导入的模板是否冲突。
例如,我有一个导入 import_one.xsl
和 import_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>