XSLT:如何确保多模式身份模板不会覆盖所有导入的匹配模板?

时间:2017-06-21 09:25:04

标签: xslt xslt-2.0

我正在编写一个XSLT转换,它应该在很大程度上保持输入XML的结构不变,但添加一些属性并更改一些元素名称。

为实现这一目标,我有一个身份模板,可确保所有未与另一个模板匹配的节点(具有更高优先级)将按原样保留。

<!-- Identity template: leaves in place nodes not matched by a more specific template. -->
<xsl:template mode="#all" priority="2" match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates mode="#current" select="@*|node()"/>
  </xsl:copy>
</xsl:template>

我正在对输入文档执行多遍变换,每次传递都使用不同的模式。为了避免在所有这些模式中重复身份模板,我因此将其模式设置为#all

当我想要导入一些具有我希望在此样式表中应用的匹配属性的模板时,会出现问题。在调用<xsl:apply-templates>时,XSLT用于决定哪个模板具有匹配属性:

  1. 模式
  2. 匹配
  3. 导入优先级
  4. 优先
  5. (申报单)
  6. 由于身份模板具有mode="#all"match="@*|node()",因此它将匹配所有模式和所有节点类型。然后,确定将应用哪个模板的下一个属性是模板的导入优先级。 但是,由于导入的模板的导入优先级始终低于本地模板,因此此标识模板始终优先于任何导入的模板,因此导入具有匹配属性的模板是徒劳的。

    我的问题是:最合适的方法是什么?即如何确保多模式身份模板不会覆盖所有导入的匹配模板?

    我有两个建议的解决方案,但我都不满意:

    1. 更改身份模板mode属性的值,以明确列出所有使用的模式,例如: mode="#default mode1 mode2 mode3"。我发现这有问题,因为我现在需要记住每次更改使用的模式时更新此属性值(例如,添加或重命名模式)。它还涉及跟踪导入的样式表中使用的所有模式,或者导入这些模式的导入样式表中的另一个标识模板。
    2. 使用<xsl:include>代替<xsl:import>来获取相关的外部模板。这可能适用于我的具体情况,但我不喜欢它作为一般解决方案,因为这些XSLT元素具有不同的语义并以不同的方式工作,这可能不是我想要的XSLT样式表的Web增长复杂。

1 个答案:

答案 0 :(得分:0)

第三种可能的解决方案似乎是最好的解决方案:将身份模板放在自己的样式表中,然后将导入到需要它的样式表中。如果我们确保将此作为第一次导入,那么将为身份模板提供最低的导入优先级,这将再次确保仅在没有其他适用模板的情况下应用它,这是我们所寻求的行为。

感谢Martin Honnen提出的建议。