带索引计数器的XSLT过滤器

时间:2009-03-23 11:30:48

标签: xslt xpath

我编写了一些使用一个XML文档来过滤另一个XML文档的XSLT。现在我想使用position()对输出元素进行编号,但我的过滤条件并未内置到我的<xsl:for-each>中,因此position()为我提供了编号间隔的结果。我如何摆脱差距?

<xsl:variable name="Astring">
  <a><b>10</b><b>20</b><b>30</b></a>
</xsl:variable>
<xsl:variable name="A" select="msxml:node-set($Astring)" />

<xsl:variable name="Bstring">
  <c><d>20</d><d>30</d></c>
</xsl:variable>
<xsl:variable name="B" select="msxml:node-set($Bstring)" />

<e>
  <xsl:for-each select="$A/a/b">
    <xsl:variable name="matchvalue" select="text()" />
    <xsl:if test="count($B/c/d[text() = $matchvalue]) &gt; 0">
      <xsl:element name="f">
        <xsl:attribute name="i">
          <xsl:value-of select="position()" />
        </xsl:attribute>
        <xsl:copy-of select="text()" />
      </xsl:element>
    </xsl:if>
  </xsl:for-each>
</e>

结果如下:

<e>
  <f i="2">20</f>
  <f i="3">30</f>
</e>

...但我想要这个:

<e>
  <f i="1">20</f>
  <f i="2">30</f>
</e>

有没有办法在<xsl:if> <xsl:for-each>属性中加入上述select过滤测试?

注意:我看过this question re:过滤和this one re:计数器,但前者不对其结果进行编号,后者使用position()。

2 个答案:

答案 0 :(得分:3)

为什么你不能在for-each循环中包含你的条件有什么特别的原因吗?

<xsl:for-each select="$A/a/b[$B/c/d = .]">

我在Visual Studio中对此进行了测试,它适用于此示例。

这是输出:

<e>
  <f i="1">20</f>
  <f i="2">30</f>
</e>

答案 1 :(得分:2)

我不确定为什么当<xsl:for-each>显然是更好的选择时,人们总是希望使用<xsl:apply-templates>

好的,这是修辞。我知道为什么会这样:<xsl:for-each>似乎更容易。但事实并非如此 - 以下两个模板取代了整个for-each构造:

<xsl:template match="/">
  <e><xsl:apply-templates select="$B/c/d[$A/a/b = .]" /></e>
</xsl:template>

<xsl:template match="d">
  <f i="{position()}"><xsl:value-of select="." /></f>
</xsl:template>

输出:

<e>
  <f i="1">20</f>
  <f i="2">30</f>
</e>

好吧,我有点作弊。您可以将<xsl:for-each>版本压缩为:

<xsl:template match="/">
  <e>
    <xsl:for-each select="$B/c/d[$A/a/b = .]">
      <f i="{position()}"><xsl:value-of select="." /></f>
    </xsl:for-each>
  </e>
</xsl:template>

然而,它缺乏<xsl:apply-templates>变种的轻盈,恕我直言。

相关问题