为什么在模板模式中不允许使用descendant-or-self ::?

时间:2011-11-10 15:16:06

标签: xslt

假设我有以下XML(将TEI注释方案嵌入到HTML中):

<p>(See, for example, <bibl type="journal" xmlns="http://www.tei-c.org/ns/1.0"><author>Greger IH, et al.</author> <date>2007</date>, <title>Trends Neurosci.</title> <biblScope type="vol">30</biblScope> (<biblScope type="issue">8</biblScope>): <biblScope type="pp">407-16</biblScope></bibl>).</p>

现在我想将所有注释节点按原样复制到生成的XHTML中,但只将<title>重命名为<bibTitle><title>仅允许<head> 1}}),所以我使用了以下转换:

<xsl:template match="tei:bibl/descendant-or-self::*">
    <xsl:variable name="nodeName">
        <xsl:choose>
            <xsl:when test="name() = 'title'">bibTitle</xsl:when>
            <xsl:otherwise><xsl:value-of select="name()" /></xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <!-- Changing of the namespace occurs here, but we don't care -->
    <xsl:element name="{$nodeName}">
        <xsl:copy-of select="@*" />
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<xsl:template match="p/text()|tei:bibl//text()">
    <xsl:copy-of select="." />
</xsl:template>

然而,它没有编译并因以下错误而中断:

Only child:: and attribute:: axes are allowed in match patterns! Offending axes = descendant-or-self

当我将匹配规则更改为<xsl:template match="tei:bibl|tei:bibl//*">时,它会按预期开始工作。但那应该与descendant-or-self::*相同,对吗?我在这里遇到了变压器实施限制吗?

首先,我使用Mozilla 3.5内部变压器测试,然后使用Xalan 2.7.1测试 - 同样的负面结果。

4 个答案:

答案 0 :(得分:2)

此限制对于模板匹配模式中的任何位置步骤仅对有效有效。它是按设计(由W3C XSLT 1.0 XSLT 2.0 规范强制执行) - 以确保有效的XSLT处理。

请注意:可以在任何位置步骤后面的谓词中自由使用任何轴(包括descending-or-self::)。

<强>更新

以下是在descendant-or-self::的{​​{1}}属性中使用match轴的简短完整示例:

xsl:template

将此转换应用于以下XML文档

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="num[descendant-or-self::num > 5]"/>
</xsl:stylesheet>

想要的结果:任何值为&gt; = 5的<nums> <num>1</num> <num>2</num> <num>3</num> <num>4</num> <num>5</num> <num>6</num> <num>7</num> <num>8</num> <num>9</num> <num>10</num> </nums> 元素都会被删除:

num

答案 1 :(得分:1)

the spec

是一项艰难的要求
  

虽然模式不能使用descendant-or-self轴,但模式可以使用//运算符和/运算符。

答案 2 :(得分:1)

这是一种可以将模式重写为不重复提及tei:bibl的等效模式的方法:

<xsl:template match="*[ancestor-or-self::tei:bibl]">

至于为什么存在这种限制,一般的答案是肯定的。也许这些限制过于保守,因为正如你所指出的那样,在这种情况下重写后代或自我是微不足道的。

我经常对这个限制感到恼火(你可以使用//而不是后代)。

答案 3 :(得分:1)

这是一个不够的案例:

<a>
  <b>
    <c>
      <c>
        <c/>
      </c>
    </c>
  </b>
  <c>
    <c>
      <c/>
    </c>
  </c>
</a>

现在我只想匹配:

*[self::a or self::b][p(.)]/c/descendent-or-self::c

即,如果a上的谓词p(。)为真,我想要a / c,a / c / c,a / c / c / c,如果b为真,我想要b / c, b / c / c和b / c / c / c。

但是我不想要/ b / c,a / b / c / c等等,因为谓词匹配a而不是b。

如果我制作匹配模式:

*[self::a or self::b][p(.)]//c 

然后我匹配所有我不想要的东西。

所以我必须在括号中向后执行:

c[ancestor-or-self::c/parent::*[self::a or self::b][p(.)]]

我认为我只是说服自己这个限制并不是一个合乎逻辑的限制,但是,我认为不能在匹配模式中允许正确的轴步骤的借口是非常蹩脚的,因为当我需要这个时,我需要这个,谁关心它是否不像我使用更简单的表达式那么快。