7

I have an XML similar to below, which needs to be sorted using the date field.

<root> 
    <Node1>
        <date></date> 
    </Node1> 
    <Node1> 
        <date></date> 
    </Node1> 
    <Node1> 
        <date></date> 
    </Node1> 
    <Node1> 
        <date></date> 
    </Node1> 
    <Node2> 
        <date></date> 
    </Node2> 
    <Node2> 
        <date></date> 
    </Node2> 
    <Node2> 
        <date></date> 
    </Node2> 
    <Node2> 
        <date></date> 
    </Node2> 
</root>

I would like to sort the XML based on the date(say ascending order), irrespective of whether the date is under Node1 or Node2. Actually, in Java code I have two separate lists, one with Node1 objects and other with Node2 objects. I can sort the list in any order separately inside java. But I need to have the dates sorted irrespective of the nodes it is appearing on the XML. What is the best approach to sort this way in Java?

Actually I am using Castor for marshaling the java objects to XML. If you know this can be done with Castor, that will be great!

Abdollah
  • 4,579
  • 3
  • 29
  • 49
Java Guy
  • 3,391
  • 14
  • 49
  • 55
  • XML is "meant" to be a set, so sorting your data in ascending order isn't "meant" to be be useful... – blissapp May 26 '10 at 22:49
  • 4
    @blissapp - Order is fundamental to XML, the abstract model is a sequence. the basis of xpath 2.0/xquery. Maybe you're thinking of relational data? – mdma May 26 '10 at 23:28
  • @mdma The XML 1.0 specification does not guarantee element order. The well-formedness definition specifically states that attributes are unordered, but says nothing about elements. – blissapp May 27 '10 at 08:23
  • @blissapp So, the XPath position() function is essentially undefined as to which node it returns? This is just absurd. Even the old DTD takes element order into account - there are some expressions that can be parsed only when the order is known, or the resulting recogniser becomes non-deterministic. Attribute order is not part of the model, but element order is fundamental to it. – mdma May 27 '10 at 10:21
  • @mdma XPath, XSLT, etc. all inherit from the XML Information Set recommendation that states that children are An ordered list of child information items, in document order. In raw XML, this is not so. – blissapp May 27 '10 at 12:55
  • @blisapp - in theory what you say is true, but in practice is isn't. Re: "well-formedness ... but says nothing about elements" - here's an article from developerWorks that discusses this point, (and quotes your statement pretty much verbatim :-) http://www.ibm.com/developerworks/xml/library/x-eleord.html – mdma May 27 '10 at 14:03
  • precisely what I meant to imply by my use of quotes around "meant". XML is "meant" to be a set, but pretty much everyone treats it like ascending order. I'm sure I came across that website too when I was looking for the XML specs to back up my assertion, so perhaps slightly guilty of plagiarism here... forgive me ibm... ;-) – blissapp May 28 '10 at 23:14

4 Answers4

2

I'd use XSLT, it has probs with sorting dates that you'll need to work round, simplest way if you can control it is to have sortable date format like yyyymmdd

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

  <xsl:template match="root">
    <xsl:copy>
        <xsl:apply-templates>
           <xsl:sort data-type="number" select="date"/>
        </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
      <xsl:copy>
          <xsl:apply-templates/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
blissapp
  • 1,330
  • 12
  • 19
1

I also think that XSL sorting would be better and fast.

Check the following links,

http://www.codeproject.com/KB/XML/sorting_dates_in_xsl.aspx

http://www.xml.com/pub/a/2002/07/03/transform.html?page=2

http://forums.devx.com/showthread.php?t=4063

thanks.

Parth
  • 1,281
  • 8
  • 17
0

If you would like the result of the sort to be a single list, sorted by date then you have to put all of the nodes into a single List of array. If the two types (node1 & node2) extend a common base class, you can use Java's Generics for you list.

List<Node> nodes = new ArrayList<Node>();
nodes.add(node1);
nodes.add(node2);
Node[] nodeArrayToSort = nodes.toArray();

If the two node types do not inherit from a common class, you can simply use a List of Objects.

Now you will have to write your own Comparator. here is an example of one you could use if the node types do have a common super class which holds the Date field.

public class NodeComparator implements Comparator<Node> {
    @Override
    public int compare(Node node1, Node node2) {
        return node1.getDate().compare(node2.getDate());
    }
}

Now that you have your custom comparator and your array with all of your nodes, it is a single line of Java code to sort the list.

Arrays.sort(nodeArrayToSort, new NodeComparator());

The javadoc for the above method can be found here if you would like any additional info on it's behaviour.

Using the above method, it is easy to see how you could write any type of compare function to change the behavior of your sort. You could also write as many custom Comparator classes as you'd please so that you could switch them at runtime. Hope this helps! :)

Jesse Webb
  • 43,135
  • 27
  • 106
  • 143
0

I used XSLT and XALAN.

The XSL is as below.. Date is of the format mm/dd/yyyy

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:template match="root"> 
<xsl:copy> 
<xsl:apply-templates> 
<xsl:sort data-type="number"  select="substring(date,7,4)"/> <!-- year sort -->
<xsl:sort data-type="number" select="substring(date,1,2)"/> <!-- day sort -->
<xsl:sort data-type="number" select="substring(date,4,2)"/> <!-- month sort -->
</xsl:apply-templates> 
</xsl:copy> 
</xsl:template> 
<xsl:template match="*"> 
<xsl:copy> 
<xsl:apply-templates/> 
</xsl:copy> 
</xsl:template> 
</xsl:stylesheet>

and the java code is

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

/**
 *  Use the TraX interface to perform a transformation in the simplest manner possible
 *  (3 statements).
 */
public class SimpleTransform
{
    public static void main(String[] args)
    throws TransformerException, TransformerConfigurationException, 
           FileNotFoundException, IOException
  {  
  // Use the static TransformerFactory.newInstance() method to instantiate 
  // a TransformerFactory. The javax.xml.transform.TransformerFactory 
  // system property setting determines the actual class to instantiate --
  // org.apache.xalan.transformer.TransformerImpl.
    TransformerFactory tFactory = TransformerFactory.newInstance();

    // Use the TransformerFactory to instantiate a Transformer that will work with  
    // the stylesheet you specify. This method call also processes the stylesheet
  // into a compiled Templates object.
    Transformer transformer = tFactory.newTransformer(new StreamSource("sort.xsl"));

    // Use the Transformer to apply the associated Templates object to an XML document
    // (foo.xml) and write the output to a file (foo.out).
    transformer.transform(new StreamSource("root.xml"), new StreamResult(new FileOutputStream("out.xml")));

    System.out.println("************* The result is in birds.out *************");
  }
}
AppleGrew
  • 9,302
  • 24
  • 80
  • 124
Java Guy
  • 3,391
  • 14
  • 49
  • 55
  • Cool, it's good to see how to pull it off in Java. Your response looks pretty weird here - scrolling text areas within scrolling text areas - I'm sure that's an SO bug... – blissapp May 28 '10 at 23:17
  • I didn't do anything intentionally to have two scrolling test areas..Just came up like this.. I am also surprised with this.. :) – Java Guy May 31 '10 at 01:16