基于它的计数和过滤,在xsl:for-each中

时间:2014-09-12 17:43:20

标签: xml xslt

我有一个由笨拙的程序自动生成的源XML,其中包含重复和空的条目。

我希望能够选择并仅显示最具代表性的条目,过滤空条目。例如,假设我的源XML是

<catalog>
    <letter>
      <char>A</char>
    </letter>
    <letter>
        <char>B</char>
    </letter>
    <letter>
        <char></char>
    </letter>
    <letter>
        <char>A</char>
    </letter>
    <letter>
        <char></char>
    </letter>
    <letter>
        <char></char>
    </letter>
</catalog>

然后,我想只得到A。

我能做到:

<table><tr>
  <xsl:for-each select="catalog/letter[char!='']">
    <td><xsl:value-of select="char" /></td>
  </xsl:for-each>
</tr></table>

将显示一个仅包含A,B,A(不是空列)的表。

现在我想只获得A,因为它是最经常出现的。我该怎么做?

更新

这是一次尝试,但不起作用。

<xsl:variable name="counter" select="0" />
<xsl:variable name="this" select="" />
<xsl:for-each select="catalog/letter[char!='']">
  <xsl:variable name="var" select="char" />
  <xsl:variable name="cou" select="count(/catalog/letter[char=$var])" />
  <xsl:if test="$cou &gt; counter">
    <xsl:variable name="this" select="$var" />
  </xsl:if>
<td><xsl:value-of select="$this" /></td>
</xsl:for-each>

1 个答案:

答案 0 :(得分:2)

首先要提到的是,在XSLT中,变量是不可变的。它们一旦设置就无法更改,所以如果试图拥有一个&#34;计数器&#34;变量,它不起作用。

要修复当前的XSLT,您可以使用xsl:sort xsl:for-each命令对具有相同letter的{​​{1}}元素的数量进行排序,然后选择第一个。像

char

然而,这是非常低效的,因为你会反复计算相同的节点。

更好的技巧是使用Muenchian Grouping,其中包括定义查找元素的键

  <xsl:for-each select="catalog/letter[char!='']">
     <xsl:sort select="count(/catalog/letter[char=current()/char])" order="descending" />
     <xsl:if test="position() = 1">
        <xsl:value-of select="."/>
     </xsl:if>
  </xsl:for-each>

然后使用此键查找每个不同的字母,并使用相同的字符计算字母数。

试试这个XSLT

<xsl:key name="letter" match="letter[char!='']" use="char" />

这应该只输出<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:key name="letter" match="letter[char!='']" use="char" /> <xsl:template match="/"> <xsl:for-each select="catalog/letter[generate-id() = generate-id(key('letter', char)[1])]"> <xsl:sort select="count(key('letter', char))" order="descending" /> <xsl:if test="position() = 1"> <xsl:value-of select="."/> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet>