Nerz
Nerz

Reputation: 35

XSLT list top 50

Following my previous question: Sort complex XML structure by nested attribute using XSLT (Was poorly setup) apologies.

I was curious how you would go about only listing the top 10 Locations of Standard sales.

Can this be used inside apply-templates as i am having difficulty using it

<xsl:if test="position() &lt;= 10">

Upvotes: 2

Views: 180

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243449

Here is a simple, complete, solution, which is a single-pass:

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

    <xsl:param name="pTopN" select="2"/>

    <xsl:template match="CompanyStats">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="CompanyLocation">
                <xsl:sort data-type="number" select="UserContent/StandardSales/Sales" order="descending"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="CompanyLocation">
      <xsl:if test="not(position() > $pTopN)">
       <xsl:copy-of select="."/>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the following XML document (containing three CompanyLocation elements):

<Company>
    <CompanyStats>
        <CompanyLocation id="London">
            <OfficeID>1</OfficeID>
            <Totalworkers>20</Totalworkers>
            <NoCleaners>2</NoCleaners>
            <TopSales>
                <UserID>4</UserID>
                <Sales>43</Sales>
                <Description> Highest sales this quater</Description>
            </TopSales>
            <LowestSales>
                <UserID>12</UserID>
                <Sales>26</Sales>
                <Description> Lowest sales this quater</Description>
            </LowestSales>
            <UserContent>
                <ID>4</ID>
                <FirstName>Jack</FirstName>
                <Surname>Black</Surname>
                <StartDate>11/11/2011</StartDate>
                <StandardSales>
                    <SSID>0</SSID>
                    <Sales>64</Sales>
                    <SalesManager>Steve Hewitt</SalesManager>
                </StandardSales>
                <BusinessSales>
                    <BSID>0</BSID>
                    <Sales>64</Sales>
                    <SalesManager>Steve Hewitt</SalesManager>
                </BusinessSales>
            </UserContent>
        </CompanyLocation>
        <CompanyLocation id="Paris">
            <OfficeID>1</OfficeID>
            <Totalworkers>20</Totalworkers>
            <NoCleaners>2</NoCleaners>
            <TopSales>
                <UserID>4</UserID>
                <Sales>43</Sales>
                <Description> Highest sales this quater</Description>
            </TopSales>
            <LowestSales>
                <UserID>12</UserID>
                <Sales>26</Sales>
                <Description> Lowest sales this quater</Description>
            </LowestSales>
            <UserContent>
                <ID>4</ID>
                <FirstName>Jack</FirstName>
                <Surname>Black</Surname>
                <StartDate>11/11/2011</StartDate>
                <StandardSales>
                    <SSID>0</SSID>
                    <Sales>122</Sales>
                    <SalesManager>Steve Hewitt</SalesManager>
                </StandardSales>
                <BusinessSales>
                    <BSID>0</BSID>
                    <Sales>64</Sales>
                    <SalesManager>Steve Hewitt</SalesManager>
                </BusinessSales>
            </UserContent>
        </CompanyLocation>
        <CompanyLocation id="Berlin">
            <OfficeID>1</OfficeID>
            <Totalworkers>20</Totalworkers>
            <NoCleaners>2</NoCleaners>
            <TopSales>
                <UserID>4</UserID>
                <Sales>43</Sales>
                <Description> Highest sales this quater</Description>
            </TopSales>
            <LowestSales>
                <UserID>12</UserID>
                <Sales>26</Sales>
                <Description> Lowest sales this quater</Description>
            </LowestSales>
            <UserContent>
                <ID>4</ID>
                <FirstName>Jack</FirstName>
                <Surname>Black</Surname>
                <StartDate>11/11/2011</StartDate>
                <StandardSales>
                    <SSID>0</SSID>
                    <Sales>12</Sales>
                    <SalesManager>Steve Hewitt</SalesManager>
                </StandardSales>
                <BusinessSales>
                    <BSID>0</BSID>
                    <Sales>64</Sales>
                    <SalesManager>Steve Hewitt</SalesManager>
                </BusinessSales>
            </UserContent>
        </CompanyLocation>
    </CompanyStats>
</Company>

the top (after the sorting) two of these are produced to the output:

<CompanyStats>
   <CompanyLocation id="Paris">
      <OfficeID>1</OfficeID>
      <Totalworkers>20</Totalworkers>
      <NoCleaners>2</NoCleaners>
      <TopSales>
         <UserID>4</UserID>
         <Sales>43</Sales>
         <Description> Highest sales this quater</Description>
      </TopSales>
      <LowestSales>
         <UserID>12</UserID>
         <Sales>26</Sales>
         <Description> Lowest sales this quater</Description>
      </LowestSales>
      <UserContent>
         <ID>4</ID>
         <FirstName>Jack</FirstName>
         <Surname>Black</Surname>
         <StartDate>11/11/2011</StartDate>
         <StandardSales>
            <SSID>0</SSID>
            <Sales>122</Sales>
            <SalesManager>Steve Hewitt</SalesManager>
         </StandardSales>
         <BusinessSales>
            <BSID>0</BSID>
            <Sales>64</Sales>
            <SalesManager>Steve Hewitt</SalesManager>
         </BusinessSales>
      </UserContent>
   </CompanyLocation>
   <CompanyLocation id="London">
      <OfficeID>1</OfficeID>
      <Totalworkers>20</Totalworkers>
      <NoCleaners>2</NoCleaners>
      <TopSales>
         <UserID>4</UserID>
         <Sales>43</Sales>
         <Description> Highest sales this quater</Description>
      </TopSales>
      <LowestSales>
         <UserID>12</UserID>
         <Sales>26</Sales>
         <Description> Lowest sales this quater</Description>
      </LowestSales>
      <UserContent>
         <ID>4</ID>
         <FirstName>Jack</FirstName>
         <Surname>Black</Surname>
         <StartDate>11/11/2011</StartDate>
         <StandardSales>
            <SSID>0</SSID>
            <Sales>64</Sales>
            <SalesManager>Steve Hewitt</SalesManager>
         </StandardSales>
         <BusinessSales>
            <BSID>0</BSID>
            <Sales>64</Sales>
            <SalesManager>Steve Hewitt</SalesManager>
         </BusinessSales>
      </UserContent>
   </CompanyLocation>
</CompanyStats>

Explanation:

  1. The wanted number of top elements to process is specified in the global/external parameter $pTopN. In this way, when this parameter is set outside of the transformation, the transformation can be used for any wanted number, without any modification.

  2. The key moment is in the xsl:apply-templates, which has an xsl:sort child. This causes the template(s) to be applied to a sorted node-list.

  3. Inside the matching template there is a single condition that compares the position() to the $pTopN parameter and the processing is performed only if the current position hasn't exceeded that number.

Upvotes: 2

Nico Kutscherauer
Nico Kutscherauer

Reputation: 340

well, normaly i would do this in two steps. But in this simple case you can use a variable as temporary step. change the template you got by your first question in this way:

<xsl:template match="CompanyStats">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <!-- sorting of the CompanyLocation in a temporary variable -->
        <xsl:variable name="CompanyLocationSorted">
            <xsl:apply-templates select="CompanyLocation">
                <xsl:sort data-type="number" select="UserContent/StandardSales/Sales" order="descending"/>
            </xsl:apply-templates>
        </xsl:variable>
        <!-- copies just the first 10 of the sorted CompanyLocation-->
        <xsl:copy-of select="$CompanyLocationSorted/CompanyLocation[position() &lt;= 10]"/>
    </xsl:copy>
</xsl:template>

Upvotes: 2

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56162

Define this in predicate, e.g.:

<xsl:apply-templates select="item[position() &lt;= 10]" />

Upvotes: 2

Related Questions