【问题标题】:Counting distinct items in XSLT and listing only once计算 XSLT 中的不同项目并仅列出一次
【发布时间】:2011-03-17 00:51:24
【问题描述】:

我有以下 XML:

<assessment>
    <section>
        <item>
            <attributes>
                <variables>
                    <variable>
                        <variable_name value="MORTIMER"/>
                    </variable>
                </variables>
            </attributes>
        </item>
        <item>
            <attributes>
                <variables>
                    <variable>
                        <variable_name value="FRED"/>
                    </variable>
                </variables>
            </attributes>
        </item>
        <item>
            <attributes>
                <variables>
                    <variable>
                        <variable_name value="MORTIMER"/>
                    </variable>
                </variables>
            </attributes>
        </item>
    </section>
</assessment>

我有以下 XSLT 来处理该 XML:

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

 <xsl:key name="kValueByVal" match="item//variables//variable_name" 
          use="@value"/>

 <xsl:template match="assessment">
     <xsl:for-each select="
      .//item//variables//variable_name/@value
      ">
        <xsl:value-of select=
        "concat(., ' ', count(key('kValueByVal', .)), '&#xA;')"/>
         <br/>
     </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

它输出以下内容,这几乎是我想要的:

MORTIMER 2
FRED 1
MORTIMER 2

它列出了每个变量名以及每个变量名出现的次数。唯一的问题是,每次出现 variable_name 时,它​​都会给出一次计数,而不是只给出一次。

这是我希望它输出的内容:

MORTIMER 2
FRED 1

如何修改 XSLT 代码以提供该代码?请注意,我们使用的是 XSLT 1.0。

以下解决方案似乎应该可以工作,但什么也没输出:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kValueByVal" match="item//variables//variable_name"
          use="@value"/>

 <xsl:template match="assessment">
     <xsl:for-each select=".//item//variables//variable_name/@value[generate-id()
                                                                    =
                                                                    generate-id(key('kValueByVal',.)[1])]">
        <xsl:value-of select=
        "concat(., ' ', count(key('kValueByVal', .)), '&#xA;')"/>
         <br/>
     </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

【问题讨论】:

  • 我的回答提供了一个简短的解决方案。

标签: xslt xslt-grouping xslkey


【解决方案1】:

鉴于您使用的是 XSLT 2.0,我会使用内置的 grouping features。 (对于早期版本,您可能需要研究 Muenchian 分组。)

<?xml version="1.0" ?>
<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kValueByVal" match="item//variables//variable_name" 
          use="@value"/>

 <xsl:template match="assessment">
     <xsl:for-each-group select=".//item//variables//variable_name" group-by="@value">
                <xsl:value-of select="concat(current-grouping-key(), ' ', count(current-group()), '&#xA;')"/>
        <br/>
     </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 谢谢,但是当我尝试这样做时出现以下错误:“XSLT 转换期间出错:XSLT 转换失败。”
  • 这些是我得到的错误:D:\software\source\applications\Athena\main\src\vue\exam\inspector\xslt>xalan repository.inspection-pi.xml variables.xslt XSLT警告:元素 xsl:for-each-group 是未知的 XSLT 元素。 (variables.xslt,第 11 行,第 87 列。) XPathParserException:找不到函数“current-grouping-key”。 expression = 'concat(current-grouping-key(), ' ', count(current-group()), ' ')' 剩余的标记是: ( 'current-grouping-key' '(' ')' ',' '' '' ',' 'count ' '(' 'current-group' '(' ')' ')' ',' '' '' ')') (variables.xslt,第 12 行,第 110 列)
  • 也许处理器真的不是 2.0。有1.0的解决方案吗?
【解决方案2】:

你得到你想要的:

<xsl:for-each select=".//item//variables//variable_name/@value"> 

Wich 表示:对于这些属性中的每一个

在分组时,您必须说:对于其中的每一个

而且,你怎么知道是哪一种?用孟契法:

<xsl:for-each select=".//item//variables//variable_name/@value[generate-id()
                                                               =
                                                               generate-id(key('kValueByVal',.)[1])]">

这意味着:那些是第一个拥有那把钥匙的人。

编辑:另外,当您知道输入架构时,请避免使用//

编辑:现在我可以看到您更改了密钥...那么,对于您的新密钥,谁是同类中的第一个?是的! variable_name元素:

<xsl:for-each select=".//item//variables//variable_name[generate-id()
                                                        =
                                                        generate-id(key('kValueByVal',@value)[1])]">

【讨论】:

  • @Paul Reiners:那是因为您更改了密钥。在您对同一个样式表的许多问题进行细微更改之后,这很困难。
【解决方案3】:
<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kValueByVal" match="item//variables//variable_name" 
          use="@value"/>

 <xsl:template match="assessment">
     <xsl:for-each 
              select="//item//variables//variable_name[
                          generate-id() = 
                              generate-id(key('kValueByVal', @value)[1])]">
        <xsl:value-of select=
        "concat(./@value, ' ', count(key('kValueByVal', ./@value)), '&#xA;')"/>
         <br/>
     </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

【讨论】:

    【解决方案4】:

    这将在 XSLT 1.0 中实现。

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
    
     <xsl:key name="kValueByVal" match="item//variables//variable_name" 
              use="@value"/>
    
     <xsl:template match="assessment">
         <xsl:for-each select="
          //item//variables//variable_name[not(@value=ancestor::item/preceding-sibling::item//variables//variable_name/@value)]
          ">
            <xsl:value-of select=
            "concat(@value, ' ', count(key('kValueByVal', @value)), '&#xA;')"/>
             <br/>
         </xsl:for-each>
     </xsl:template>
    </xsl:stylesheet>
    

    我得到的输出是

    MORTIMER 2
    <br />FRED 1
    <br />
    

    请注意,它假设了更多关于文档结构(祖先::item 位)的信息,但您应该能够从那里得到它。

    【讨论】:

      【解决方案5】:

      您确实需要了解 Muenchian 分组的工作原理,否则您将永远问相同问题的变体。

      请阅读Jeni Tennison's tutorial

      这是您最新问题的解决方案:

      <xsl:stylesheet version="1.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:output method="text"/>
      
       <xsl:key name="kVarNameByVal" match="variable_name"
                use="@value"/>
      
       <xsl:template match=
        "variable_name[generate-id()
                      =
                       generate-id(key('kVarNameByVal', @value)[1])
                      ]
        ">
              <xsl:value-of select=
              "concat(@value, ' ', count(key('kVarNameByVal', @value)), '&#xA;')"/>
               <br/>
       </xsl:template>
      </xsl:stylesheet>
      

      当对提供的 XML 文档执行此转换时,会产生想要的结果:

      MORTIMER 2
      FRED 1
      

      【讨论】:

      • 我终于开始阅读该教程了,谢谢!现在我终于开始理解这些东西了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      • 2019-03-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多