Список элементов, возвращаемых группой по xslt - PullRequest
0 голосов
/ 03 мая 2011

Привет, у меня есть следующий xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<name>john</name>
<year>2010</year>
</item>
<item>
<name>sam</name>
<year>2000</year>
</item>
<item>
<name>jack</name>
<year>2007</year>
</item>
<item>
<name>smith</name>
<year>2010</year>
</item>
</root>

Я использую следующий xslt для группировки по годам

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:template match="/">
<xsl:for-each-group select="r//*[(name=*)]" group-by="year">
<xsl:sort select="year" order="descending"/>
<xsl:variable name="total" select="count(/r//*[(name=*)]) + 1" />
    <xsl:value-of select="year"/><br />
    <xsl:for-each select="current-group()/name">
        <xsl:variable name="i" select="position()"/>    
        <xsl:call-template name="row">
            <xsl:with-param name="name" select="."/>
            <xsl:with-param name="number" select="$total - $i"/>
        </xsl:call-template>
    </xsl:for-each>
    <br />
</xsl:for-each-group>
</xsl:template>

<xsl:template name="row">
<xsl:param name="name"/>
<xsl:param name="number"/>
        <xsl:value-of select="concat($number, '. ')"/>
        <xsl:value-of select="concat($name, ' ')"/><br />
</xsl:template>
</xsl:stylesheet>

Это вывод, он довольно близок к выводу, который я хочу.

2010 
4. john 
3. smith 

2007 
4. jack 

2000
4. sam

То, что я хочу, это просто нумерация всех имен (в порядке убывания от общего количества имен до 1), например,

2010
4. john 
3. smith 

2007
2. jack 

2000
1. sam

Было бы просто, если бы мы могли переназначить переменную на новое значение, но я думаю, что это невозможно, поэтому мне нужно найти другое решение. Может кто-нибудь помочь мне узнать, как решить эту проблему.

спасибо

1 Ответ

0 голосов
/ 03 мая 2011

Вот решение XSLT-1.0:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output type="text" omit-xml-declaration="yes"/>
    <xsl:key name="byYear" match="item" use="year"/>
    <xsl:template match="/">
        <!-- process first item for each distinct year number (ordered) -->
        <xsl:apply-templates select="//item[count(.|key('byYear',year)[1])=1]">
            <xsl:sort select="year" order="descending"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="item">
        <!-- output year number, surrounded by newlines -->
        <xsl:text>
</xsl:text>
        <xsl:value-of select="year"/>
        <xsl:text>
</xsl:text>
        <!-- now process all items for the current year number -->
        <xsl:for-each select="key('byYear',year)">
            <!-- output reversed index of current item for current year number
                 plus total items for lower year numbers -->
            <xsl:number value="count(//item[year &lt; current()/year])+last()-position()+1"
                 format="1. "/>
            <!-- and finally also the name of the current item and again a newline -->
            <xsl:value-of select="name"/>
            <xsl:text>
</xsl:text>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>
...