简体   繁体   English

XSLT中除第一个元素外的元素分组

[英]Grouping of elements in XSLT except the first one

(the title of this question might not be the correct one, so I will change it if someone has a better suggestion.) (此问题的标题可能不是正确的,因此,如果有人有更好的建议,我将对其进行更改。)

I have a list of results from a sport event where I want to have the following output: 我有一个体育赛事的结果列表,希望获得以下输出:

<p>
1) John Doe, Norway 1.23,45, 2) Dave Doe, Norway 0.15 behind, 3) Nicholas Doe, Norway Same Time, 4) Barack Doe, USA S.T, 5) Vladimir Doe, Russia 1.00,00 behind, 6) Xi Min Doe, China S.T. .... 
</p>

In written words: First results has the total time. 用书面语言来说:第一结果就是总时间。 Second results uses gap and we add behind, if the third result has the same gap as the second result we give that one same time. 第二个结果使用间隔,并且如果第二个结果与第二个结果具有相同的间隔,则我们将其相加。 If the fourth result has the same gap as second result, we shorten it to st If there is a new gap, we write out the gap, but all results who has the same gap as the first one in this group, shall only have st 如果第四个结果与第二个结果具有相同的间隔,我们将其缩短为st。如果有新的间隔,我们将写出该间隔,但是与该组中第一个结果具有相同间隔的所有结果仅应具有st

Alternative output: 替代输出:

<results>
<result>
<rank>1</rank>
<name>John</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:23:45</time>
<gap>00:00</gap>
</result>

<result>
<rank>2</rank>
<name>Dave</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:00</time>
<gap>00:15</gap>
</result>

<result>
<rank>3</rank>
<name>Nicholas</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:00</time>
<gap>same time</gap>
</result>

<result>
<rank>4</rank>
<name>Barack</name>
<lastname>Doe</name>
<country>USA</country>
<time>1:24:00</time>
<gap>s.t.</gap>
</result>

<result>
<rank>5</rank>
<name>Vladimir</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:45</time>
<gap>01:15</gap>
</result>

<result>
<rank>6</rank>
<name>Xi Min</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:45</time>
<gap>s.t.</gap>
</result>
</results>

the XML is quite similar to this: XML非常类似于此:

<results>
<result>
<rank>1</rank>
<name>John</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:23:45</time>
<gap>00:00</gap>
</result>

<result>
<rank>2</rank>
<name>Dave</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:00</time>
<gap>00:15</gap>
</result>

<result>
<rank>3</rank>
<name>Nicholas</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:00</time>
<gap>00:15</gap>
</result>

<result>
<rank>4</rank>
<name>Barack</name>
<lastname>Doe</name>
<country>USA</country>
<time>1:24:00</time>
<gap>00:15</gap>
</result>

<result>
<rank>5</rank>
<name>Vladimir</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:45</time>
<gap>01:15</gap>
</result>

<result>
<rank>6</rank>
<name>Xi Min</name>
<lastname>Doe</name>
<country>Norway</country>
<time>1:24:45</time>
<gap>01:15</gap>
</result>
</results>

The output, as code: I am using XSLT 2.0, but there might be someone out there who are using 1.0, so any suggestions supporting either (or make that all) versions of XSLT, I and many with me in the same situation would be very happy. 输出为代码:我正在使用XSLT 2.0,但是可能有人正在使用1.0,因此任何支持(或使所有)XSLT版本的建议(在同一情况下,我和很多人都可以)很高兴。

The following stylesheet: 以下样式表:

XSLT 2.0 XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/results">
    <xsl:copy>
        <xsl:for-each-group select="result" group-by="gap">
            <xsl:apply-templates select="current-group()"/>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

<xsl:template match="result">
    <xsl:copy>
        <xsl:apply-templates select="* except gap"/>
        <gap>
            <xsl:value-of select="if (position()=1) then gap else 'SAME TIME'" />
        </gap>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

when applied to your example input (after correcting the mismatching name and lastname tags!), will return: 当应用于示例输入(更正了不匹配的namelastname标记!)后,将返回:

<?xml version="1.0" encoding="UTF-8"?>
<results>
   <result>
      <rank>1</rank>
      <name>John</name>
      <lastname>Doe</lastname>
      <country>Norway</country>
      <time>1:23:45</time>
      <gap>00:00</gap>
   </result>
   <result>
      <rank>2</rank>
      <name>Dave</name>
      <lastname>Doe</lastname>
      <country>Norway</country>
      <time>1:24:00</time>
      <gap>00:15</gap>
   </result>
   <result>
      <rank>3</rank>
      <name>Nicholas</name>
      <lastname>Doe</lastname>
      <country>Norway</country>
      <time>1:24:00</time>
      <gap>SAME TIME</gap>
   </result>
   <result>
      <rank>4</rank>
      <name>Barack</name>
      <lastname>Doe</lastname>
      <country>USA</country>
      <time>1:24:00</time>
      <gap>SAME TIME</gap>
   </result>
   <result>
      <rank>5</rank>
      <name>Vladimir</name>
      <lastname>Doe</lastname>
      <country>Norway</country>
      <time>1:24:45</time>
      <gap>01:15</gap>
   </result>
   <result>
      <rank>6</rank>
      <name>Xi Min</name>
      <lastname>Doe</lastname>
      <country>Norway</country>
      <time>1:24:45</time>
      <gap>SAME TIME</gap>
   </result>
</results>

This was my solution to the problem. 这是我解决问题的方法。 I was told after the post that only top 10 shall be rendered and so I have added a if rank <= 10 around the code. 帖子发布后,我被告知只能渲染前10名,因此在代码周围添加了if rank <= 10。

Some part of the original data source structure here (just one to show data, names and Ids has been removed). 此处原始数据源结构的一部分(仅用于显示数据,名称和ID的部分已删除)。

If you find something odd, please do not hesitate to comment or ask question. 如果您发现一些奇怪的东西,请不要犹豫发表评论或提出问题。

<RESULT>
        <rank>42</rank>
        <bib>43</bib>
        <name>John</name>
        <surname>Doe</surname>
        <short_team>ABA</short_team>
        <long_team>ABBA</long_team>
        <time>04:42:18</time>
        <gap>13</gap>
        <code>ABA1234</code>
        <nationality>BEL</nationality>
    </RESULT>

The part of the XSLT to group and get the right output. XSLT的组成部分并获得正确的输出。 Mind, this is production code, and so some text may differ from the example. 请注意,这是生产代码,因此某些文本可能与示例不同。 I have added comments where there are differences: 我在有差异的地方添加了评论:

<xsl:for-each-group select="RESULT" group-by="time">
            <xsl:for-each select="current-group()">
                <xsl:if test="rank &lt;= 10">
                    <xsl:value-of select="rank"/>
                    <xsl:text>) </xsl:text>
                    <xsl:value-of select="name"/>
                    <xsl:text> </xsl:text>
                    <xsl:variable name="surname">
                        <xsl:for-each select="tokenize(surname, ' ')">
                            <xsl:value-of
                                select="concat(upper-case(substring(., 1, 1)), lower-case(substring(., 2)))"/>
                            <xsl:text> </xsl:text>
                        </xsl:for-each>
                    </xsl:variable>
                    <xsl:value-of select="normalize-space($surname)"/>

                    <xsl:text>, </xsl:text>
                    <xsl:value-of select="nationality"/>
                    <xsl:text> (</xsl:text>
                    <xsl:value-of select="long_team"/>
                    <xsl:text>)</xsl:text>
                    <xsl:text> </xsl:text>
                    <xsl:choose>
                        <xsl:when test="rank = '1'">
                            <!-- the replace is just there to get the time in the correct format -->
                            <xsl:value-of select="replace(time, ':', '.')"/>
                        </xsl:when>
                        <xsl:when test="rank = '2'">
                            <xsl:choose>
                                <xsl:when test="gap != ''">
                                    <xsl:if test="string-length(gap) = 2">
                                       <!-- this text is here because the gap might just have two characters, and we want it like this 0.12 -->
                                        <xsl:text>0.</xsl:text>
                                    </xsl:if>
                                    <xsl:value-of select="replace(gap, ':', '.')"/>
                                    <!-- This is norwegian text for minutes behind (shortened) -->
                                    <xsl:text> min. bak</xsl:text>
                                </xsl:when>
                                <xsl:otherwise>
                                    <!-- This is norwegian for same time -->
                                    <xsl:text> samme tid</xsl:text>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:choose>
                                <xsl:when test="position() = 1">
                                    <xsl:if test="string-length(gap) = 2">
                                        <xsl:text>0.</xsl:text>
                                    </xsl:if>
                                    <xsl:value-of select="replace(gap, ':', '.')"/>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:text> s.t.</xsl:text>
                                </xsl:otherwise>
                            </xsl:choose>

                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:choose>
                        <xsl:when test="position() != last()">
                            <xsl:text>, </xsl:text>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:text>, </xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each-group>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM