分组在XSLT 1.0中不起作用

时间:2013-07-05 16:01:39

标签: xslt-1.0 xslt-grouping

我有如下的XML。

<minimums type="table">       
      <minLine>
        <minId>S-4LS16L</minId>
        <catA>5550</catA>
        <catA>1800</catA>      
        <catB>5550</catB>
        <catB>1800</catB>     
        <catC>5550</catC>
        <catC>1800</catC>      
      </minLine>    
      <minLine>
        <minId>S-LOC16L</minId>
        <catA>5660</catA>
        <catA>2400</catA>        
        <catB>5660</catB>
        <catB>2400</catB>           
        <catC>2400</catC>
        <catC>310</catC>      
      </minLine>   
 </minimums>

现在我想使用XSL对catA,catB,catC等重复元素进行分组。

以下是我的XSLT的一部分。

 <xsl:key name ="groupElement" match ="*" use="name(.)"/>

  <xsl:template match ="/">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="minLine">  

    <xsl:for-each select="*[generate-id()= generate-id(key('groupElement', name(.)))]">

      <xsl:comment> This is Not get Printed during second match of minLine element</xsl:comment>

    </xsl:for-each>

  </xsl:template>

在第一场比赛中工作正常。问题是在第二个元素的匹配期间,没有得到打印。我一定是在做一些愚蠢的错误。

我在哪里做错了?

1 个答案:

答案 0 :(得分:0)

这里有三个问题:

  1. 您的密钥包含所有元素
  2. generate-id()仅接受节点集的第一个节点(按文档顺序)
  3. 使用generate-id()或count()的简单'muenchian'分组,其中一个只占用查找节点的第一个节点,不适合嵌套结构
  4. 当我们使用'catA'元素验证时,您可以轻松理解问题;
    通过输出所有索引的'catA'元素,我们得到以下节点列表:
        <xsl:copy-of select="key('groupElement', 'catA')"/>
    - &GT;
    <catA>5550</catA>
    <catA>1800</catA>
    <catA>5660</catA>
    <catA>2400</catA>

    现在,因为generate-id()总是占用第一个节点,所以很明显在第二个'minLine'元素匹配期间没有任何事情发生。

    解决方案

    您可以通过以下方式实现目标:

    1. 仅索引第一个连续出现的'minLine / *'孩子
    2. 仅选择已编入索引的'minLine / *'儿童
    3. <!-- index first of sequentially occurring minLine children -->
      <xsl:key name ="minLine_key" match="minLine/*[name() != name(preceding-sibling::*[1])]" use="name()"/>
      
      <xsl:template match ="/">
          <xml>
              <xsl:apply-templates/>
          </xml>
      </xsl:template>
      
      <xsl:template match="minLine">
          <!-- select indexed children: look up nodes by name and test wether current is included in the node-set -->
          <xsl:for-each select="*[count(. | key('minLine_key', name())) = count(key('minLine_key', name()))]">
              <xsl:copy-of select="."/>
          </xsl:for-each>
      </xsl:template>