Reputation: 35
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() <= 10">
Upvotes: 2
Views: 180
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:
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.
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.
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
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() <= 10]"/>
</xsl:copy>
</xsl:template>
Upvotes: 2
Reputation: 56162
Define this in predicate, e.g.:
<xsl:apply-templates select="item[position() <= 10]" />
Upvotes: 2