Wednesday, 15 June 2011

xml - double sort in xslt on two different fields -



xml - double sort in xslt on two different fields -

i sort xml file on 2 fieds: identifier , impact. order elements identifier, except elements have xx product must appear last.

my xml file

<evolutionlist> <date> <object> <identifier>id5</identifier> <impact> <product>aa</produit> </impact> </objet> <object> <identifier>id2</identifier> <impact> <product>xx</produit> </impact> </objet> <object> <identifier>id4</identifier> <impact> <product>bb</produit> </impact> </objet> <object> <identifier>id3</identifier> <impact> <product>xx</produit> </impact> </objet> <object> <identifier>id1</identifier> <impact> <product>cc</produit> </impact> </objet> </date> </evolutionlist>

the expceted result be:

<evolutionlist> <date> <object> <identifier>id1</identifier> <impact> <product>cc</produit> </impact> </objet> <object> <identifier>id4</identifier> <impact> <product>bb</produit> </impact> </objet> <object> <identifier>id5</identifier> <impact> <product>aa</produit> </impact> </objet> <object> <identifier>id2</identifier> <impact> <product>xx</produit> </impact> </objet> <object> <identifier>id3</identifier> <impact> <product>xx</produit> </impact> </objet> </date> </evolutionlist>

my xslt code (does not work though)

<xsl:for-each select="//date"> <tr> <td> <xsl:value-of select="./@id"/> </td> </tr> <xsl:for-each select="./object"> <xsl:choose> <xsl:when test="impact/produit = 'xx'"> <xsl:sort select="impact/produit" order="descending"/> </xsl:when> <xsl:otherwise> <xsl:sort select="identifiant"/> </xsl:otherwise> </xsl:choose> ... </xsl:for-each>

you can place <xsl:sort> in origin of <xsl:for-each> or <xsl:apply-templates/>, not in <choose> block.

you using sort order xx, i assume that's ok in scenario (e.g.: don't have product named zz, placed after xx). if that's not case, shouldn't utilize sort rule, template matches xx contents , places them @ end.

this stylesheet produces results expect using sort rules have in original stylesheet (ordering id , product strings). moved selection rules xpath predicate, , used templates instead of nested for-each nodes.

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:template match="date"> <xsl:apply-templates select="object"> <xsl:sort select="impact/product[. = 'xx']" order="ascending"/> <xsl:sort select="identifier"/> </xsl:apply-templates> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>

you can seek out in xslt fiddle

update in case don't want order xx products, place them @ end, always, can filter elements , apply templates after processing other elements. other stylesheet that:

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:template match="date"> <xsl:apply-templates select="object[not(impact[product = 'xx'])]"> <xsl:sort select="identifier"/> </xsl:apply-templates> <xsl:apply-templates select="object[impact[product = 'xx']]"/> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>

here's xslt fiddle example.

xml xslt

No comments:

Post a Comment