自己和后续兄弟姐妹的逗号分隔表达式列表在 XPath 中有效,但不适用于 XSLT 匹配模式

comma-separate list of expressions for self and following siblings works in XPath but not as XSLT match pattern

这是一个有效的 XPath 2.0:

//hi[@rend="bold"]/(self::hi, following-sibling::*, following-sibling::text())

它select 具有给定属性的所有 hi 节点以及所有同级元素和文本节点。

但是,如果我尝试像这样在 XSLT 2.0 中使用此 XPath:

<xsl:template match="hi[@rend='bold']/(self::hi, following-sibling::*, following-sibling::text())">
        <!--do something-->
    </xsl:template>

我遇到语法错误。这是为什么?我怎样才能重写这个匹配模式以便它在 XSLT 中工作?

目标是能够将以上所有内容包装在一个新元素中。

一切顺利, 丁奇

I am getting a syntax error. Why is that?

XSLT 匹配模式 有自己的 syntax rules。只有一部分有效的 XPath 表达式也是有效的匹配模式。

How can I rewrite this matching pattern so that it works in XSLT?

超出我的想象:

<xsl:template match="hi[@rend='bold'] | *[preceding-sibling::hi[@rend='bold']] | text()[preceding-sibling::hi[@rend='bold']]">

可能有更优雅的表达方式,但我相信它确实做到了您所说的。

我就是这样解决上述问题的:

  <xsl:template match="hi[@rend='bold']">
        <xsl:element name="wrap">
        <xsl:element name="hi">
            <xsl:attribute name="rend">bold</xsl:attribute>
            <xsl:value-of select="."/>
        </xsl:element>
        <xsl:copy-of select="following-sibling::node()"></xsl:copy-of>
        </xsl:element>
    </xsl:template>

    <xsl:template match="node()[preceding-sibling::hi[@rend='bold']]"></xsl:template>

基本上,我们先匹配hi元素,将它包裹起来,复制它后面的节点;在一个单独的模式中,我们匹配具有特定 hi 元素的节点作为它们的前一个兄弟节点,这样它们的内容就不会在输出中出现两次。

一个重要的教训:您不能只使用任何 xPath 并将其粘贴到您的 XSLT 中。

有时我想将模板规则应用于像这样的复杂模式选择的节点,最好的解决方案是将全局变量绑定到所有相关节点,然后使用模式中的全局变量:

<xsl:variable name="afterBold"
  select="//hi[@rend="bold"]/
   (self::hi, following-sibling::*, following-sibling::text())"/>

<xsl:template match="node()[. intersect $afterBold]"/>

以上要求 XSLT 2.0。在 XSLT 3.0 中可以简化:

<xsl:template match="$afterBold"/>