如何按Java中的属性值对XML元素进行排序?

时间:2015-08-31 09:02:13

标签: java xml

我有一个XML字符串,我需要按属性对其进行排序。这是输入XML字符串:

<graph>
  <root root_id="1"/>
  <type name="A">
    <extends name="Sphere"/>
  </type>
  <node id="3" name="" type="A">
    <property name="radius" value="0.1"/>
  </node>
  <edge id="2" src_id="5" dest_id="3" type="successor"/>
  <node id="4" name="" type="L">
    <property name="length" value="3.0"/>
  </node>
  <edge id="3" src_id="1" dest_id="4" type="successor"/>
  <node id="5" name="" type="P">
    <property name="color" value="14"/>
  </node>
  <edge id="4" src_id="4" dest_id="5" type="successor"/>
</graph>

这是期待的结果:

<graph>
  <root root_id="1"/>
  <type name="A">
    <extends name="Sphere"/>
  </type>
  <edge id="3" src_id="1" dest_id="4" type="successor"/>
  <node id="4" name="" type="L">
    <property name="length" value="3.0"/>
  </node>
  <edge id="4" src_id="4" dest_id="5" type="successor"/>
  <node id="5" name="" type="P">
    <property name="color" value="14"/>
  </node>
  <edge id="2" src_id="5" dest_id="3" type="successor"/>
  <node id="3" name="" type="A">
    <property name="radius" value="0.1"/>
  </node>
</graph>

基本上,在edge的属性src_id和dest_id的帮助下,节点必须一个接一个地与边连接。任何想法将非常感谢!非常感谢你!

1 个答案:

答案 0 :(得分:1)

对于数据类型(String,Integer,Double等),此Class按属性的值对NodeList进行排序。

以下是完整的解决方案:

package mynewpackage;

// for the method
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

// for the test example
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import org.w3c.dom.Document;
import java.math.BigDecimal;

public class NodeTools {
    /**
     * Method sorts any NodeList by provided attribute.
     * @param nl NodeList to sort
     * @param attributeName attribute name to use
     * @param asc true - ascending, false - descending
     * @param B class must implement Comparable and have Constructor(String) - e.g. Integer.class , BigDecimal.class etc
     * @return Array of Nodes in required order
     */
    public static Node[] sortNodes(NodeList nl, String attributeName, boolean asc, Class<? extends Comparable> B)
    {        
        class NodeComparator<T> implements Comparator<T>
        {
            @Override
            public int compare(T a, T b)
            {
                int ret;
                Comparable bda = null, bdb = null;
                try{
                    Constructor bc = B.getDeclaredConstructor(String.class);
                    bda = (Comparable)bc.newInstance(((Element)a).getAttribute(attributeName));
                    bdb = (Comparable)bc.newInstance(((Element)b).getAttribute(attributeName));
                }
                catch(Exception e)
                {
                    return 0; // yes, ugly, i know :)
                }
                ret = bda.compareTo(bdb);
                return asc ? ret : -ret; 
            }
        }

        List<Node> x = new ArrayList<>();
        for(int i = 0; i < nl.getLength(); i++)
        {
            x.add(nl.item(i));
        }
        Node[] ret = new Node[x.size()];
        ret = x.toArray(ret);
        Arrays.sort(ret, new NodeComparator<Node>());
        return ret;
    }   

// Test with simple example 
    public static void main(String... args)
    {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
        DocumentBuilder builder;
        String s = "<xml><item id=\"1\" price=\"100.00\" /><item id=\"3\" price=\"29.99\" /><item id=\"2\" price=\"5.10\" /></xml>";
        Document doc = null;
        try 
        {  
            builder = factory.newDocumentBuilder();  
            doc = builder.parse(new InputSource(new StringReader(s)));
        }
        catch(Exception e) { System.out.println("Alarm "+e); return; }

        System.out.println("*** Sort by id ***");
        Node[] ret = NodeTools.sortNodes(doc.getElementsByTagName("item"), "id", true, Integer.class);

        for(Node n: ret)
        {
            System.out.println(((Element)n).getAttribute("id")+" : "+((Element)n).getAttribute("price"));
        }

        System.out.println("*** Sort by price ***");
        ret = NodeTools.sortNodes(doc.getElementsByTagName("item"), "price", true, BigDecimal.class);
        for(Node n: ret)
        {
            System.out.println(((Element)n).getAttribute("id")+" : "+((Element)n).getAttribute("price"));
        }
    }
}

在我的简单测试中,它打印出来:

*** Sort by id ***
1 : 100.00
2 : 5.10
3 : 29.99
*** Sort by price ***
2 : 5.10
3 : 29.99
1 : 100.00