tags:

views:

118

answers:

3

Similar to the previous subelement sort, but I have a few extra layers of nodes. I can't figure out a simple extension to the previous answer that works. http://stackoverflow.com/questions/572854/how-to-sort-a-subelement-of-xml-with-xslt

The simplified input example:


<Iteration>
  <Iteration_query-ID>NODE_10008</Iteration_query-ID>
  <Iteration_query-def>NODE_10008</Iteration_query-def>
  <Iteration_query-len>339</Iteration_query-len>
  <Iteration_hits>
    <Hit>
      <Hit_id>110679166</Hit_id>
      <Hit_def>[Roseobacter litoralis Och 149]</Hit_def>
      <Hit_len>68</Hit_len>
      <Hit_hsps>
        <Hsp>
          <Hsp_score>300.0</Hsp_score>
          <Hsp_evalue>4.94413E-26</Hsp_evalue>
          <Hsp_query-from>69</Hsp_query-from>
          <Hsp_query-to>272</Hsp_query-to>
        </Hsp>
      </Hit_hsps>
    </Hit>
    <Hit>
      <Hit_id>114767284</Hit_id>
      <Hit_def>[Roseovarius sp. HTCC2601]</Hit_def>
      <Hit_len>68</Hit_len>
      <Hit_hsps>
        <Hsp>
          <Hsp_bit-score>127.487</Hsp_bit-score>
          <Hsp_score>319.0</Hsp_score>
          <Hsp_evalue>3.0968E-28</Hsp_evalue>
          <Hsp_query-from>69</Hsp_query-from>
          <Hsp_query-to>272</Hsp_query-to>
        </Hsp>
      </Hit_hsps>
    </Hit>
  </Iteration_hits>
</Iteration>

I want to sort by one of the Hsp attributes, such as Hsp_score. I've been able to get it to sort, but I can't figure out how to keep it from dropping out some of the Hit nodes:


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

    <xsl:import href="identity.xsl"/>

    <!--
    Iteration/Iteration_hits/Hit/Hit_hsps/Hsp
    -->
    <xsl:template match="Iteration_hits">
        <xsl:copy>
           <xsl:apply-templates select="Hit/Hit_hsps/Hsp">
                <xsl:sort select="Hsp_score" order="descending"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
+2  A: 

Would this work?

<xsl:apply-templates select="Hit">
    <xsl:sort select="Hit_hsps/Hsp/Hsp_score" order="descending"/>
</xsl:apply-templates>
David
+1  A: 

Tested David's code.

This will work.

<xsl:apply-templates select="Hit">
    <xsl:sort select="Hit_hsps/Hsp/Hsp_score" data-type="number" order="descending"/>
</xsl:apply-templates>

W3 documentation agrees.

EDIT: Added Dimitre's data-type attribute. Thanks Dimitre!

Jweede
make sure to add the data-type="number" attribute to ensure proper ordering.
Jweede
@Jweede this is something important -- not just for show-off. Imagine you find unexpectedly one day the nodes sorted in an unwanted way! BTW your own solution has the same problem. And you even didn't up-vote my answer...
Dimitre Novatchev
Thanks Dimitre! I forgot to correct this code.
Jweede
A: 

There is a slight problem with David's code:

As written, 120 will come after 90, although the sort order is specified as descending.

The proper way to sort with numeric sort keys is illustrated below:

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
<!--                                                    --> 
    <xsl:param name="pNewType" select="'myNewType'"/>
    <xsl:template match="node()|@*">
     <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
    </xsl:template>
<!--                                                    -->
    <xsl:template match="Iteration_hits">
     <xsl:copy>
      <xsl:apply-templates select="Hit">
       <xsl:sort select="Hit_hsps/Hsp/Hsp_score"  
        data-type="number"
        order="descending"/>
      </xsl:apply-templates>
     </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

When applied on this XML document:

<Iteration>
    <Iteration_query-ID>NODE_10008</Iteration_query-ID>
    <Iteration_query-def>NODE_10008</Iteration_query-def>
    <Iteration_query-len>339</Iteration_query-len>
    <Iteration_hits>
     <Hit>
      <Hit_id>110679166</Hit_id>
      <Hit_def>[Roseobacter litoralis Och 149]</Hit_def>
      <Hit_len>68</Hit_len>
      <Hit_hsps>
       <Hsp>
        <Hsp_score>120.0</Hsp_score>
        <Hsp_evalue>4.94413E-26</Hsp_evalue>
        <Hsp_query-from>69</Hsp_query-from>
        <Hsp_query-to>272</Hsp_query-to>
       </Hsp>
      </Hit_hsps>
     </Hit>
     <Hit>
      <Hit_id>114767284</Hit_id>
      <Hit_def>[Roseovarius sp. HTCC2601]</Hit_def>
      <Hit_len>68</Hit_len>
      <Hit_hsps>
       <Hsp>
        <Hsp_bit-score>127.487</Hsp_bit-score>
        <Hsp_score>90.0</Hsp_score>
        <Hsp_evalue>3.0968E-28</Hsp_evalue>
        <Hsp_query-from>69</Hsp_query-from>
        <Hsp_query-to>272</Hsp_query-to>
       </Hsp>
      </Hit_hsps>
     </Hit>
    </Iteration_hits>
</Iteration>

the correct result is produced:

<Iteration>
    <Iteration_query-ID>NODE_10008</Iteration_query-ID>
    <Iteration_query-def>NODE_10008</Iteration_query-def>
    <Iteration_query-len>339</Iteration_query-len>
    <Iteration_hits><Hit>
      <Hit_id>110679166</Hit_id>
      <Hit_def>[Roseobacter litoralis Och 149]</Hit_def>
      <Hit_len>68</Hit_len>
      <Hit_hsps>
       <Hsp>
        <Hsp_score>120.0</Hsp_score>
        <Hsp_evalue>4.94413E-26</Hsp_evalue>
        <Hsp_query-from>69</Hsp_query-from>
        <Hsp_query-to>272</Hsp_query-to>
       </Hsp>
      </Hit_hsps>
     </Hit><Hit>
      <Hit_id>114767284</Hit_id>
      <Hit_def>[Roseovarius sp. HTCC2601]</Hit_def>
      <Hit_len>68</Hit_len>
      <Hit_hsps>
       <Hsp>
        <Hsp_bit-score>127.487</Hsp_bit-score>
        <Hsp_score>90.0</Hsp_score>
        <Hsp_evalue>3.0968E-28</Hsp_evalue>
        <Hsp_query-from>69</Hsp_query-from>
        <Hsp_query-to>272</Hsp_query-to>
       </Hsp>
      </Hit_hsps>
     </Hit></Iteration_hits>
</Iteration>

Do note the use of the data-type attribute of xsl:sort.

Dimitre Novatchev
I see what you mean. Such a show-off Dimitre. :-)
Jweede
@Jweede this is something important -- not just for show-off. Imagine you find unexpectedly one day the nodes sorted in an unwanted way! BTW your own solution has the same problem.
Dimitre Novatchev
I like your answer Dimitre, but that's a lot of reading. is it possible you can post a concise introduction or summary for it (about the size of the other posts)?
Nerdling
@Nerdling When one does not know some fundamental stuff, a lot of reading is really needed! 90% of all answers on SO suffer from being untested and incomplete. An answer must provide self-contained working code and demonstrate the results when executed on a specific input. The OPs input is long agr.
Dimitre Novatchev