Erik
Erik

Reputation: 23

Sort different elements by the same criteria

I'm trying to do a sort on the following data.

<contents>
   <content>
      <id>
      <text>
   </content>
   <relatedcontent>
      <id>
      <text>
   </relatedcontent>
</contents>

This is just sample data simplified, but you get the idea. Its two different named nodes that contains the same structure. Right now I have created two different templates to treat the content and relatedcontent separetly, but then sorting is also done separetly. Is there an easy way to sort both content and relatedcontent on ids? Lets say the <text> contains a text. How could I then list all the <text>-elements of content and relatedcontent sorted by id?

Thanks!

Upvotes: 2

Views: 572

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

This transformation shows how this can be done:

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

 <xsl:template match="/*">
  <contents>
   <xsl:apply-templates>
    <xsl:sort select="id" data-type="number"/>
   </xsl:apply-templates>
  </contents>
 </xsl:template>

 <xsl:template match="content">
   Content Here
 </xsl:template>

 <xsl:template match="relatedcontent">
   Relatedcontent Here
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document (corrected to be well-formed):

<contents>
    <content>
        <id>3</id>
        <text/>
    </content>
    <relatedcontent>
        <id>2</id>
        <text/>
    </relatedcontent>
</contents>

the wanted, correctly sorted result is produced:

<contents>
   Relatedcontent Here

   Content Here
 </contents>

Do note:

  1. No use of <xsl:for-each>. Only <xsl:apply-templates> is used.

  2. No use of the XPath union operator (yes, it is called the union operator, nothing to do with pipes).

  3. If in the future a third element to be sorted on id is added to the XML document, this transformation will still work without any changes.

Upvotes: 7

Lukas Eder
Lukas Eder

Reputation: 220752

Try something like this

<xsl:foreach select="//content | //relatedcontent">
  <xsl:sort select="id" />
  <xsl:value-of select="text" />
</xsl:foreach>

I guess the solution lies in the fact that you "join" //content and //relatedcontent into a single node-set using the union operator |

Upvotes: 8

Related Questions