XSLT:基于来自其他节点的值的总和进行排序

时间:2012-11-21 21:27:49

标签: xslt xpath xslt-2.0

我对编码xslt很新,并且在尝试执行以下操作时遇到了困难。

我有一个xml文件,其中包含分为两个主要部分的马匹的育种信息。 1.马节点具有个体马的表现细节以及父亲的身份。 2. Sires节点是Sires的列表,也包含育种特定的统计数据。

我需要根据他们的小马驹(即马匹节点)赢得的“赌注”金额的总和来对公猪名单进行排序。

因此,缩小的xml文件如下所示:

<Horses>
    <Horse>
        <ID>1</ID>
        <Name>hrsA</Name>
        <SireID>101</SireID>
        <Pace>
            <Stakes>4800</Stakes>
        </Pace>
    </Horse>
    <Horse>
        <ID>2</ID>
        <Name>hrsB</Name>
        <SireID>102</SireID>
        <Pace>
            <Stakes>3600</Stakes>
        </Pace>
    </Horse>
    <Horse>
        <ID>3</ID>
        <Name>hrsC</Name>
        <SireID>102</SireID>
        <Pace>
            <Stakes>2800</Stakes>
        </Pace>
    </Horse>
    <Horse>
        <ID>4</ID>
        <Name>hrsD</Name>
        <SireID>101</SireID>
        <Pace>
            <Stakes>56</Stakes>
        </Pace>
    </Horse>
    <Horse>
        <ID>5</ID>
        <Name>hrsE</Name>
        <SireID>100</SireID>
        <Pace>
            <Stakes>20000</Stakes>
        </Pace>
    </Horse>
    <Horse>
        <ID>6</ID>
        <Name>hrsF</Name>
        <SireID>101</SireID>
        <Trot>
            <Stakes>20000</Stakes>
        </Trot>
    </Horse>
    <Horse>
        <ID>7</ID>
        <Name>hrsG</Name>
        <SireID>101</SireID>
        <Trot>
            <Stakes>559</Stakes>
        </Trot>
    </Horse>
    <Horse>
        <ID>8</ID>
        <Name>hrsH</Name>
        <SireID>102</SireID>
        <Pace>
            <Stakes>386</Stakes>
        </Pace>
        <Trot>
            <Stakes>10000</Stakes>
        </Trot>
    </Horse>
</Horses>
<Sires>
    <Sire>
        <ID>100</ID>
        <Name>srA</Name>
        <LiveFoalsALL>117</LiveFoalsALL>
    </Sire>
    <Sire>
        <ID>101</ID>
        <Name>srB</Name>
        <LiveFoalsALL>774</LiveFoalsALL>
    </Sire>
    <Sire>
        <ID>102</ID>
        <Name>srC</Name>
        <LiveFoalsALL>43</LiveFoalsALL>
    </Sire>
</Sires>

因此,总结输出将具有此排序的各种赌注:

Sire 101 (srB) Stakes: $25415
Sire 100 (srA) Stakes: $20000
Sire 103 (srC) Stakes: $16768.

当我刚刚总结并订购其他网页的个别马匹时,我可以使用:

<xsl:apply-templates select="Horse">
    <xsl:sort select="sum(descendant::Stakes)" data-type="number"
        order="descending"/>
</xsl:apply-templates>

我只是无法弄清楚如何为参与马节点的公牛做同样的事情以获得正确的排序...可能这样的地方,我试图说Sire / ID等于马/ SireID:

<xsl:apply-templates select="Sire">
    <xsl:sort select="sum(//Horses/Horse[@SireID=ID]/descendant::Stakes)" 
        data-type="number" order="descending"/>
</xsl:apply-templates>

但是这不起作用,当调试器到达排序行时,调试器直接跳出当前模板,因此我的语法必须无效。 我一直在尝试对这个主题进行修改而没有成功。

任何人都可以给我一个如何调用我的Sire模板并获得正确排序的指针吗?

谢谢,

Bryce Stenberg

2 个答案:

答案 0 :(得分:2)

此转化

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kOffspring" match="Horse" use="SireID"/>

 <xsl:template match="/*">
  <xsl:apply-templates select="Sires/Sire">
   <xsl:sort select="sum(key('kOffspring', ID)/*/Stakes)"
             data-type="number" order="descending"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="Sire">
     Sire <xsl:value-of select="concat(ID,' (', Name, ') Stakes: ')"/>
   <xsl:value-of select="sum(key('kOffspring', ID)/*/Stakes)"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

应用于提供的XML文档时:

<t>
    <Horses>
        <Horse>
            <ID>1</ID>
            <Name>hrsA</Name>
            <SireID>101</SireID>
            <Pace>
                <Stakes>4800</Stakes>
            </Pace>
        </Horse>
        <Horse>
            <ID>2</ID>
            <Name>hrsB</Name>
            <SireID>102</SireID>
            <Pace>
                <Stakes>3600</Stakes>
            </Pace>
        </Horse>
        <Horse>
            <ID>3</ID>
            <Name>hrsC</Name>
            <SireID>102</SireID>
            <Pace>
                <Stakes>2800</Stakes>
            </Pace>
        </Horse>
        <Horse>
            <ID>4</ID>
            <Name>hrsD</Name>
            <SireID>101</SireID>
            <Pace>
                <Stakes>56</Stakes>
            </Pace>
        </Horse>
        <Horse>
            <ID>5</ID>
            <Name>hrsE</Name>
            <SireID>100</SireID>
            <Pace>
                <Stakes>20000</Stakes>
            </Pace>
        </Horse>
        <Horse>
            <ID>6</ID>
            <Name>hrsF</Name>
            <SireID>101</SireID>
            <Trot>
                <Stakes>20000</Stakes>
            </Trot>
        </Horse>
        <Horse>
            <ID>7</ID>
            <Name>hrsG</Name>
            <SireID>101</SireID>
            <Trot>
                <Stakes>559</Stakes>
            </Trot>
        </Horse>
        <Horse>
            <ID>8</ID>
            <Name>hrsH</Name>
            <SireID>102</SireID>
            <Pace>
                <Stakes>386</Stakes>
            </Pace>
            <Trot>
                <Stakes>10000</Stakes>
            </Trot>
        </Horse>
    </Horses>
    <Sires>
        <Sire>
            <ID>100</ID>
            <Name>srA</Name>
            <LiveFoalsALL>117</LiveFoalsALL>
        </Sire>
        <Sire>
            <ID>101</ID>
            <Name>srB</Name>
            <LiveFoalsALL>774</LiveFoalsALL>
        </Sire>
        <Sire>
            <ID>102</ID>
            <Name>srC</Name>
            <LiveFoalsALL>43</LiveFoalsALL>
        </Sire>
    </Sires>
</t>

生成想要的正确结果

 Sire 101 (srB) Stakes: 25415
 Sire 100 (srA) Stakes: 20000
 Sire 102 (srC) Stakes: 16786

<强>解释

  1. 我们定义一个键,指定Horse作为其SireID的函数。这仅仅是通过在调用标准XSLT key() 函数时提供Sire来选择给定ID的所有后代非常有用 - 如下所示:{ {1}}。

  2. 同样,给定key('kOffspring', ID)的所有后代Stakes的总和为:Sire

  3. 我们将模板应用于XML文档中的所有sum(key('kOffspring', ID)/*/Stakes)元素,并按其后代的Sire总和的递减值对其进行排序。

  4. 对于每个Stakes,我们会输出其SireID及其后代Name的总和。

答案 1 :(得分:1)

您需要使用current()

<xsl:apply-templates select="Sire">
    <xsl:sort select="sum(//Horses/Horse[SireID = current()/ID]//Stakes)" 
        data-type="number" order="descending"/>

current()为您提供上下文节点,因为它是当前XPath表达式的外部;在这种情况下,<Sire>选择的当前xsl:apply-templates元素。在谓词中,上下文节点是正在针对谓词表达式进行测试的<Horse>元素。

注意:

  • 你在那里有@你不想要的; @ID是指ID 属性
  • 我将descendant::/替换为//
  • 正如@Dimitre所指出的,如果您使用密钥而不是//foo[barID = current()/ID],您的样式表将更好地扩展到大输入。