为什么XSLT意外地改变了上下文?

时间:2013-08-15 11:06:11

标签: xslt xpath

我在包含树的一部分的select属性中应用带变量的模板。从那里我调用另一个应用模板与follow-sibling :: construction,但它适用于所有树。例如:

<a>
    <b id="1" ol="1" />
    <b id="2" ol="0" />
    <b id="3" ol="0" />
    <b id="4" ol="1" />
    <b id="5" ol="0" />
    <b id="6" ol="0" />
    <b id="7" ol="1" />
    <b id="8" ol="0" />
    <b id="9" ol="0" />
    <b id="10" ol="1" />
    <b id="11" ol="0" />
    <b id="12" ol="0" />
    <b id="13" ol="1" />
    <b id="14" ol="0" />
    <b id="15" ol="0" />
    <b id="16" ol="1" />
</a>

...
<xsl:variable name="part" select="b[@ol = 1] />
<xsl:apply-templates mode="top" select="$part[position() mod 3 = 1]" />
...
<xsl:template mode="top" match="*">
    <tr>
        <xsl:apply-template mode="inner" select=".|following-sibling::b[not(position() > 2)]" />
    </tr>
<xsl:template>

<xsl:template mode="inner" match="*">
    <p><xsl:value-of select="@id" /></p>
<xsl:template>

我期待的是

<tr><p>1</p><p>4</p><p>7</p></tr>
<tr><p>10</p><p>13</p><p>16</p></tr>

我得到了什么

<tr><p>1</p><p>2</p><p>3</p></tr>
<tr><p>10</p><p>11</p><p>12</p></tr>

那么为什么模板“top”在应用follow-sibling时更改上下文而不是$part?以及如何获得预期的变体?

2 个答案:

答案 0 :(得分:0)

XPath选择输入树中的节点,它永远不会更改该输入树。因此,选择一些节点不会以任何方式改变树中的结构和关系,兄弟姐妹或孩子或祖先保持不变。如果要操作树,请使用XSLT或XQuery。由于您已经使用XSLT,使用XSLT 1.0,您需要编写模板以使用新结构创建结果树片段,然后在应用类似exsl:node-set的扩展函数后,您可以处理中间树。使用XSLT 2.0,您不需要扩展功能,但需要构建中间树。

要实现您想要的输出,您可以使用

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

<xsl:output indent="yes" method="html"/>

<xsl:template match="a">
  <xsl:variable name="part" select="b[@ol = 1]" />
  <xsl:apply-templates mode="top" select="$part[position() mod 3 = 1]" />
</xsl:template>

<xsl:template mode="top" match="*">
    <tr>
        <xsl:apply-templates mode="inner" select=".|following-sibling::b[@ol = 1][not(position() > 2)]" />
    </tr>
</xsl:template>

<xsl:template mode="inner" match="*">
    <p><xsl:value-of select="@id" /></p>
</xsl:template>

</xsl:stylesheet>

使用XSLT样式表Saxon 6.5.5转换

<a>
    <b id="1" ol="1" />
    <b id="2" ol="0" />
    <b id="3" ol="0" />
    <b id="4" ol="1" />
    <b id="5" ol="0" />
    <b id="6" ol="0" />
    <b id="7" ol="1" />
    <b id="8" ol="0" />
    <b id="9" ol="0" />
    <b id="10" ol="1" />
    <b id="11" ol="0" />
    <b id="12" ol="0" />
    <b id="13" ol="1" />
    <b id="14" ol="0" />
    <b id="15" ol="0" />
    <b id="16" ol="1" />
</a>

<tr>
   <p>1</p>
   <p>4</p>
   <p>7</p>
</tr>
<tr>
   <p>10</p>
   <p>13</p>
   <p>16</p>
</tr>

答案 1 :(得分:0)

$ part选择@ ol = 1的元素,即元素1,4,7,10,13,16。

$ part [position()mod 3 = 1]选择$ part中$ part中的位置为1,4,7的项目......也就是说,它选择带有id和10的元素。

然后对这些模板应用模板,输出以这两个元素开头的三个元素的组,它们为您提供组(1,2,3)和(10,11,12)。

我认为你的错误可能在于想象position()返回树中元素的位置,而不是你要过滤的列表中元素的位置。