[jdom-interest] Sorting elements in a document by a Node
Alex Rosen
arosen at silverstream.com
Mon Apr 15 16:24:36 PDT 2002
I worked on this a while ago, and I've cleaned it up and added it to the
jdom-contrib tree in CVS in org.jdom.contrib.helpers.JDOMHelper, for now.
Here's a copy of the sorting code.
(Jason, I also tried to check in this test module to the jdom-test tree, but
for some reason it ended up in jdom-contrib instead, so I had to delete it.
That's why there's now an empty org.jdom.contrib.helpers.test package there.
Can you add this to jdom-test?)
--Alex
/**
* <p>
* Sorts the child elements, using the specified comparator.
* Any other intervening content (Text, Comments, etc.) are not moved.
* (Note that this means that the elements will now be in a different
* order with respect to any comments, which may cause a problem
* if the comments describe the elements.)
* </p>
* <p>
* This method overcomes two problems with the standard
Collections.sort():
* <ul>
* <li>Collections.sort() doesn't bother to remove an item from its old
* location before placing it in its new location, which causes JDOM to
* complain that the item has been added twice.
* <li>This method will sort the child Elements without moving other
* content, such as formatting text nodes (newlines, indents, etc.)
* Otherwise, all the formatting whitespace would move to the beginning
* or end of the content list.
* </ul>
* </p>
*/
public static void sortElements(Element parent, Comparator c) {
// Create a new, static list of child elements, and sort it.
List children = new ArrayList(parent.getChildren());
Collections.sort(children, c);
ListIterator childrenIter = children.listIterator();
// Create a new, static list of all content items.
List content = new ArrayList(parent.getContent());
ListIterator contentIter = content.listIterator();
// Loop through the content items, and whenever we find an Element,
// we'll insert the next ordered Element in its place. Because the
// content list is not live, it won't complain about an Element
being
// added twice.
while(contentIter.hasNext())
{
Object obj = contentIter.next();
if (obj instanceof Element)
contentIter.set(childrenIter.next());
}
// Finally, we set the content list back into the parent Element.
parent.setContent(null);
parent.setContent(content);
}
> -----Original Message-----
> From: jdom-interest-admin at jdom.org
> [mailto:jdom-interest-admin at jdom.org]On Behalf Of George Pieri
> Sent: Monday, April 15, 2002 4:50 PM
> To: jdom-interest at jdom.org
> Subject: [jdom-interest] Sorting elements in a document by a Node
>
>
>
>
> Using JDOM is it possible to sort all the elements in an XML
> string by one of the nodes...
>
> e.g. Sort all the the XML "NAME" nodes/tags in ascending order ??
>
>
> StringReader sReader = new StringReader(xmlData) ;
> doc = builder.build(sReader) ;
> root = doc.getRootElement() ;
>
> doc.sort("NAME","asc") ????????????????????
>
>
> Thanks in advance!
> _______________________________________________
> To control your jdom-interest membership:
> http://lists.denveronline.net/mailman/options/jdom-interest/yo
> uraddr at yourhost.com
-------------- next part --------------
package org.jdom.contrib.helpers.test;
/*--
Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JDOM" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact license at jdom.org.
4. Products derived from this software may not be called "JDOM", nor
may "JDOM" appear in their name, without prior written permission
from the JDOM Project Management (pm at jdom.org).
In addition, we request (but do not require) that you include in the
end-user documentation provided with the redistribution and/or in the
software itself an acknowledgement equivalent to the following:
"This product includes software developed by the
JDOM Project (http://www.jdom.org/)."
Alternatively, the acknowledgment may be graphical using the logos
available at http://www.jdom.org/images/logos.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
This software consists of voluntary contributions made by many
individuals on behalf of the JDOM Project and was originally
created by Brett McLaughlin <brett at jdom.org> and
Jason Hunter <jhunter at jdom.org>. For more information on the
JDOM Project, please see <http://www.jdom.org/>.
*/
/**
* Please put a description of your test here.
*
* @author unascribed
* @version 0.1
*/
import junit.framework.*;
import java.io.*;
import java.util.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;
import org.jdom.contrib.helpers.*;
public final class TestJDOMHelper extends junit.framework.TestCase {
/**
* Construct a new instance.
*/
public TestJDOMHelper(String name) {
super(name);
}
/**
* The main method runs all the tests in the text ui
*/
public static void main (String args[])
{
junit.textui.TestRunner.run(suite());
}
/**
* This method is called before a test is executed.
*/
public void setUp() {
}
/**
* The suite method runs all the tests
*/
public static Test suite () {
TestSuite suite = new TestSuite(TestJDOMHelper.class);
return suite;
}
/**
* This method is called after a test is executed.
*/
public void tearDown() {
}
public void test_sortElements() throws Exception {
// Read the unsorted test document.
StringReader reader = new StringReader(UNSORTED);
SAXBuilder builder = new SAXBuilder();
Document testDoc = builder.build(reader);
// Sort all the groups.
List children = testDoc.getRootElement().getChildren();
Iterator iter = children.iterator();
while(iter.hasNext()) {
Element child = (Element)iter.next();
JDOMHelper.sortElements(child, new ElementNameComparator());
}
// Read the sorted reference document.
reader = new StringReader(SORTED);
builder = new SAXBuilder();
Document referenceDoc = builder.build(reader);
// new XMLOutputter().output(testDoc, System.out);
// System.out.println("\n\n=================================\n\n");
// new XMLOutputter().output(referenceDoc, System.out);
// Compare the two.
boolean success = matches(testDoc.getContent(), referenceDoc.getContent());
assertTrue("sortElements failed", success);
}
// Compares two Elements by comparing their tag names.
private static class ElementNameComparator implements Comparator {
public int compare(Object o1, Object o2) {
String s1 = ((Element)o1).getName();
String s2 = ((Element)o2).getName();
// (A real implementation might use java.text)
return s1.compareTo(s2);
}
}
// Returns true if the two contents lists are identical
// Elements, Attributes, and Text. Ignores all other items.
private static boolean matches(List contents1, List contents2) {
if (contents1.size() != contents2.size()) {
return false;
}
Iterator iter1 = contents1.iterator();
Iterator iter2 = contents2.iterator();
while(iter1.hasNext()) {
Object child1 = iter1.next();
Object child2 = iter2.next();
if (!child1.getClass().equals(child2.getClass())) {
return false;
}
if (child1 instanceof Element) {
Element element1 = (Element)child1;
Element element2 = (Element)child2;
if (!element1.getName().equals(element2.getName()))
return false;
if (!matches(element1.getAttributes(), element2.getAttributes()))
return false;
if (!matches(element1.getContent(), element2.getContent()))
return false;
}
if (child1 instanceof Attribute) {
Attribute attr1 = (Attribute)child1;
Attribute attr2 = (Attribute)child2;
if (!attr1.getName().equals(attr2.getName()))
return false;
if (!attr1.getValue().equals(attr2.getValue()))
return false;
}
if (child1 instanceof Text) {
Text text1 = (Text)child1;
Text text2 = (Text)child2;
if (!text1.getText().equals(text2.getText()))
return false;
}
}
return true;
}
private static final String UNSORTED =
"<root>\n" +
"\n" +
" <group1>\n" +
" <yankee><child/><child/></yankee>\n" +
" <xray/>\n" +
" <bravo>data</bravo>\n" +
" <delta/>\n" +
" <charlie data='value'/>\n" +
" <zulu/>\n" +
" <alpha/>\n" +
" </group1>\n" +
"\n" +
" <group2><yankee/>\n" +
" <alpha/>\n" +
" <delta/>\n" +
" <xray/>\n" +
" <bravo/></group2>\n" +
"\n" +
" <group3><alpha/><delta/><charlie/><xray/><bravo/><yankee/><zulu/></group3>\n" +
"\n" +
" <group4>\n" +
" </group4>\n" +
"\n" +
" <group5>\n" +
" <alpha/>\n" +
" </group5>\n" +
"\n" +
" <group6><alpha/></group6>\n" +
"\n" +
" <group7></group7>\n" +
"\n" +
"</root>";
private static final String SORTED =
"<root>\n" +
"\n" +
" <group1>\n" +
" <alpha/>\n" +
" <bravo>data</bravo>\n" +
" <charlie data='value'/>\n" +
" <delta/>\n" +
" <xray/>\n" +
" <yankee><child/><child/></yankee>\n" +
" <zulu/>\n" +
" </group1>\n" +
"\n" +
" <group2><alpha/>\n" +
" <bravo/>\n" +
" <delta/>\n" +
" <xray/>\n" +
" <yankee/></group2>\n" +
"\n" +
" <group3><alpha/><bravo/><charlie/><delta/><xray/><yankee/><zulu/></group3>\n" +
"\n" +
" <group4>\n" +
" </group4>\n" +
"\n" +
" <group5>\n" +
" <alpha/>\n" +
" </group5>\n" +
"\n" +
" <group6><alpha/></group6>\n" +
"\n" +
" <group7></group7>\n" +
"\n" +
"</root>";
}
More information about the jdom-interest
mailing list