tags:

views:

1041

answers:

4

So you have a third-party web service that likes to abuse XML and return things in an order that makes your programming a complete pain in the neck. For example...

<file>
  <node1>Foo</node1>
  <price>4.99</price>
  <node2>
    <key>XX999</key>
  </node2>
</file>

There are about a thousand of these sorted in order by price.

How can you re-sort this XML document by the key value?

I need the result to be a sorted XML file. Thanks!

EDIT: .NET version 2.0 (no LINQ)

+6  A: 

Here's how to do it with XSLT:

assuming your data takes this form (file.xml):

<?xml version="1.0"?>
<listing>
<file>
  <node1>Foo</node1>
  <price>4.99</price>
  <node2>
    <key>XX999</key>
  </node2>
</file>
<file>
  <node1>Bar</node1>
  <price>5.67</price>
  <node2>
    <key>aa743</key>
  </node2>
</file>
<file>
  <node1>Was</node1>
  <price>5.67</price>
  <node2>
    <key>rr321</key>
  </node2>
</file>
</listing>

This transform (stylesheet.xsl):

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

  <xsl:template match="listing">
    <xsl:copy>
      <xsl:apply-templates select="file">
        <xsl:sort select="node2/key" data-type="text"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

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

</xsl:stylesheet>

When used with this .Net code (need to add a using System.Xml;):

XslCompiledTransform xslt= new XslCompiledTransform();
xslt.Load(@"c:\stylesheet.xsl");

xslt.Transform(@"C:\file.xml", @"c:\sorted.xml");

Results in this output in sorted.xml:

<?xml version="1.0" encoding="utf-8"?>
<listing>
  <file>
    <node1>Bar</node1>
    <price>5.67</price>
    <node2>
      <key>aa743</key>
    </node2>
  </file>
  <file>
    <node1>Was</node1>
    <price>5.67</price>
    <node2>
      <key>rr321</key>
    </node2>
  </file>
  <file>
    <node1>Foo</node1>
    <price>4.99</price>
    <node2>
      <key>XX999</key>
    </node2>
  </file>
</listing>
Mitch Wheat
No, I need to sort this prior to parsing the XML. I'd prefer to have a way to sort it without casting it to an object.
Josh Stodola
"How are you consuming this data?" It's nothing but a classic HTTP request, and I have a huge string to be parsed.
Josh Stodola
XSLT? Please hook me up with an example or something - I am clueless!
Josh Stodola
OK I am reading W3 specs on XSLT, but what would the select string be?
Josh Stodola
code included in updated answer...
Mitch Wheat
Excellent answer! Reformatted your stylesheet to enhance readability.
Cerebrus
@Cerebrus: Thanks.
Mitch Wheat
I had to come back to this answer again today, and I just wanted to say THANK YOU very much!
Josh Stodola
+3  A: 

Apply an Xml Style Sheet to transform to source XML into an XML format suitable for your use. You can easily sort elements by values during the xsl transformation.

qux
A: 

Will Linq to XML handle this for you?

Ian Suttle
+1  A: 

XSLT rules, of course, but I'd go with LINQ To XML (i.e., what's in the System.Xml.Linq namespace). Specifically, what you need to do is something like this:

newElement = new XElement(oldElement.Elements().OrderBy(x => x.Whatever);
Dmitri Nesteruk