16443

Sort complex XML structure by nested attribute using XSLT

Question:

I am looking to sort an XML structure using XSLT using xsltproc:

The xml needs to be sorted from CompanyLocation according to the salesman's standard sales inside Usercontent. My XSLT however never seems to sort the data, only copy it.

Below is one CompanyLocation XML tree structure I have about 400 others.

XML data:

<Company> <CompanyStats> <CompanyLocation="London"> <OfficeID>1</OfficeID> <Totalworkers>20 <NoCleaners>2 <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 <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>

Here is my attached XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="CompanyStats"> <xsl:copy> <xsl:apply-templates select="@*|node()"> <xsl:sort select="CompanyLocation/UserContent/StandardSales/Sales" order="descending"/> </xsl:apply-templates> </xsl:copy> </xsl:template>

As i have about 400 CompanyLocation Trees I wish to have the whole tree for each CompanyLocaiton ordered by sales:

<CompanyLocation="London"> <.....> <StandardSales> <Sales>4</Sales> <StandardSales> <.....> </CompanyLocation> <CompanyLocation="Birmingham"> <.....> <StandardSales> <Sales>25</Sales> <StandardSales> <.....> </CompanyLocation> <CompanyLocation="Norwich"> <.....> <StandardSales> <Sales>35</Sales> <StandardSales> <.....> </CompanyLocation>

Answer1:

That is sorting the attributes and children of CompanyStats, but there are no attributes and only one element child (and two white space node) children of that element so all it is doing is bringing the white space before or after the element. I suspect you want to apply the sorting a level down:

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

But actually I'm not clear what you do want, perhaps you could edit your question to add the result that you want in this case.

<strong>UPDATE</strong> even after clarification in comments, you don't make it easy to help:

<CompanyLocation="London">

not well formed, presumably an attribute name missing?

<Totalworkers>20

not well formed, missing end tag,

And assorted other errors in the file. I <em>think</em> a corrected input and working stylesheet are below.

<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> </CompanyStats> </Company>

and stylesheet, the main change being the xsl:sort select attribute and datatype="number" to get numeric sorting.

<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:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <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:stylesheet>

Answer2:

Your sort wants to be relative to the node you are selecting. not the context of the template you are in.

try <xsl:sort select="UserContent/StandardSales/Sales" order="descending"/> as you are selecting CompanyLocation.

Recommend

  • Keep a reference to objects passed to a UserControl
  • Regular expression pipe confusion
  • but these conflict with your requirements or minimum-stability
  • SQL Consolidating groups of data
  • Sum of Overlapping DateTimes in Excel
  • SQL Consolidating groups of data
  • RecyclerView Mixing Up Items
  • What is MongoDB's $min? How is that different from find().sort({the_field: 1}).limit(1)?
  • How do I generate totally a random number at a time?
  • EXCEL lookup minimum value with multiple criteria
  • php, sort an array from mysql
  • Insert the lowest possible unique positve integer in an atomic fashion in MySql
  • Select top 10 percent, also bottom percent in SQL Server
  • Passing variable through switch statement with functions
  • Windows Azure - Virtual Application
  • Get Mac address of client connected with esp8266
  • Trying to move an object from a fixed starting point to the coordinates of a mouse click
  • Generate “special” dictionary structure from just columns index in tsv
  • How exactly BIC in Augmented Dickey–Fuller test work in Python?
  • Get SSID's in range iOS 7
  • Multiclass element selection clarification [duplicate]
  • beginner-opening explorer to show folder contents
  • How to order or choose rows in MySQL GROUP BY clause?
  • better way to communicate between ad hoc wifi windows mobile devices
  • Calculate sum of a column based on ranking of another column
  • SQL SELECT ORDER BY multiple columns depending on value of other column
  • Hibernate 5 ImplicitNamingStrategy
  • Dereferenceing on casting the void pointer to float*/int*
  • Java: List the dates between a start and end date [duplicate]
  • How does socketcan handle arbitration?
  • LINQ to NHibernate WHERE EXISTS IN
  • Ordering a Union Query in MS Access SQL
  • SharePoint Designer 2010 - Determine if today's date is within x days of a start date column us
  • Can you build a truly RESTful service that takes many parameters?
  • AlertDialog style when using setView()
  • HTML5 video only works in IE. The other browsers shows the black screen
  • AndEngine Applying Transparancy to AndEngine View
  • JFileChooser in front of fullscreen Swing application
  • failed to connect to specific WiFi in android programmatically