基于多个属性排序节点?

时间:2009-09-30 01:09:45

标签: xml xslt sorting

我想根据属性对节点进行排序。假设元素E1中有三个属性A,B和C.我知道节点的子组具有相同的属性A和B的值。如何让该子组检索具有最大值C的节点?这里棘手的部分是我不知道A的价值是多少。我只知道子组共享相同的A值。就像双键索引一样。

我正在考虑为每个组使用for-each。

例如

<masterNodes>
    <Node>
        <Element1 A="123" B="LEFT" C="1">
        <Element2>...</Element2>
    </Node>
    <Node>
        <Element1 A="123" B="DOWN" C="5">
        <Element2>...</Element2>
    </Node>
    <Node>
        <Element1 A="abc" B="RIGHT" C="2">
        <Element2>...</Element2>
    </Node>
    <Node>
        <Element1 A="123" B="LEFT" C="3">
        <Element2>...</Element2>
    </Node>
    <Node>
        <Element1 A="4XX" B="LEFT" C="4">
        <Element2>...</Element2>
    </Node>
    <Node>
        <Element1 A="abc" B="RIGHT" C="1">
        <Element2>...</Element2>
    </Node>
    <Node>
        <Element1 A="4XX" B="LEFT" C="5">
        <Element2>...</Element2>
    </Node>
    <Node>
        <Element1 A="4XX" B="UP" C="0">
        <Element2>...</Element2>
    </Node>
</masterNodes>

如何只为具有相同A和B值的节点写出C的最大值?

以下是我构建代码的方式。但我从来没有让它发挥作用。

<xsl:for-each-group select="/Node/Element1" group-by="@A">
    <xsl:for-each select=".[@B='LEFT']">
        <xsl:sort select="@C" data-type="number" order="descending"/>
        <xsl:if test="position()=1"><xsl:value-of select="@C"/></xsl:if>
    </xsl:for-each><xsl:text>&#xD;</xsl:text>
    <xsl:for-each select=".[@B='RIGHT']">
        <xsl:sort select="@C" data-type="number" order="descending"/>
        <xsl:if test="position()=1"><xsl:value-of select="@C"/></xsl:if>
    </xsl:for-each><xsl:text>&#xD;</xsl:text>
    <same for other direction>
</xsl:for-each-group>

有什么不对吗?

2 个答案:

答案 0 :(得分:1)

如果我正确理解规范,则for-each-group内的上下文项将设置为该组的第一个元素。要对组进行排序,您需要使用current-group()函数。以下模板似乎有效:

<xsl:template match="/masterNodes">
    <xsl:for-each-group select="Node/Element1" group-by="@A">
        <xsl:for-each select="current-group()[@B='LEFT']">
            <xsl:sort select="@C" data-type="number" order="descending"/>
            <xsl:if test="position()=1"><xsl:value-of select="concat(@A, ' ', @B, ' ', @C)"/></xsl:if>
        </xsl:for-each>
        <xsl:text>&#xD;</xsl:text>
        <xsl:for-each select="current-group()[@B='RIGHT']">
            <xsl:sort select="@C" data-type="number" order="descending"/>
            <xsl:if test="position()=1"><xsl:value-of select="concat(@A, ' ', @B, ' ', @C)"/></xsl:if>
        </xsl:for-each>
        <xsl:text>&#xD;</xsl:text>
    </xsl:for-each-group>

</xsl:template>

答案 1 :(得分:0)

我认为这可以通过'muenchian grouping'实现,它使用xsl:key元素对节点进行分组。

首先,使用A和B属性

定义Element1元素的键
<xsl:key name="Elements" match="Element1" use="concat(@A,@B)"/>

接下来,您需要使用此键

循环使用A和B的唯一组合
<xsl:for-each select="//Element1[generate-id(.) = generate-id(key(&apos;Elements&apos;, concat(@A,@B))[1])]">

在此循环中,您将再次循环,但仅在具有匹配键的元素上循环,这次按C属性的顺序

<xsl:for-each select="key('Elements', concat(@A,@B))">
   <xsl:sort select="@C" order="descending"/>

由于您只想要第一个具有C属性值最高的元素,因此您将测试位置()

<xsl:if test="position() = 1"> 

完全放弃

<xsl:key name="Elements" match="Element1" use="concat(@A,@B)"/>

<xsl:template match="/">
   <xsl:for-each select="//Element1[generate-id(.) = generate-id(key('Elements', concat(@A,@B))[1])]">
      <xsl:sort select="@C" order="descending"/>
      <xsl:for-each select="key('Elements', concat(@A,@B))">
          <xsl:sort select="@C" order="descending"/>
          <xsl:if test="position() = 1">
             (<xsl:value-of select="@A"/>,<xsl:value-of select="@B"/>,<xsl:value-of select="@C"/>) 
          </xsl:if>
       </xsl:for-each>
   </xsl:for-each>
</xsl:template>