Сортировка XML в Java

У меня есть XML, аналогичный приведенному ниже, который необходимо отсортировать с использованием поля даты.

<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>

Я хотел бы отсортировать XML на основе даты (скажем, в порядке возрастания), независимо от того, находится ли дата под Node1 или Node2. На самом деле в коде Java у меня есть два отдельных списка: один с объектами Node1, а другой с объектами Node2. Я могу отсортировать список в любом порядке отдельно внутри java. Но мне нужно отсортировать даты независимо от узлов, которые они появляются в XML. Каков наилучший подход к такой сортировке в Java?

На самом деле я использую Castor для маршалинга java-объектов в XML. Если вы знаете, что это можно сделать с Castor, это будет здорово!


person Java Guy    schedule 26.05.2010    source источник
comment
XML предназначен для набора, поэтому сортировка ваших данных в порядке возрастания не должна быть полезной...   -  person blissapp    schedule 27.05.2010
comment
@blissapp - Порядок является фундаментальным для XML, абстрактная модель - это последовательность. на основе xpath 2.0/xquery. Может быть, вы думаете о реляционных данных?   -  person mdma    schedule 27.05.2010
comment
@mdma Спецификация XML 1.0 не гарантирует порядок элементов. Определение правильности прямо указывает, что атрибуты неупорядочены, но ничего не говорит об элементах.   -  person blissapp    schedule 27.05.2010
comment
@blissapp Итак, функция XPath position () по существу не определена в отношении того, какой узел она возвращает? Это просто абсурд. Даже старое DTD учитывает порядок элементов — есть некоторые выражения, которые можно анализировать, только если порядок известен, иначе результирующий распознаватель становится недетерминированным. Порядок атрибутов не является частью модели, но порядок элементов имеет для нее основополагающее значение.   -  person mdma    schedule 27.05.2010
comment
@mdma XPath, XSLT и т. д. — все они наследуют рекомендацию набора данных XML, в которой говорится, что дочерние элементы — это упорядоченный список дочерних информационных элементов в порядке документа. В необработанном XML это не так.   -  person blissapp    schedule 27.05.2010
comment
@blisapp - теоретически то, что вы говорите, верно, но на практике это не так. Re: корректность... но ничего не говорится об элементах - вот статья от developerWorks, в которой обсуждается этот момент (и почти дословно цитируется ваше утверждение :-) ibm.com/developerworks/xml/library/x-eleord.html   -  person mdma    schedule 27.05.2010
comment
именно то, что я имел в виду, используя кавычки. XML должен быть набором, но почти все относятся к нему как к восходящему порядку. Я уверен, что тоже наткнулся на этот веб-сайт, когда искал спецификации XML для подтверждения своего утверждения, так что, возможно, здесь немного виновен в плагиате... простите меня, ibm... ;-)   -  person blissapp    schedule 29.05.2010


Ответы (4)


Я бы использовал XSLT, у него есть проблемы с датами сортировки, которые вам нужно будет обойти, самый простой способ, если вы можете это контролировать, - это иметь сортируемый формат даты, такой как ггггммдд

<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>
person blissapp    schedule 26.05.2010
comment
у меня такой же случай - но формат даты другой - например 2015-12-27T16:44:07 , так что как можно сделать в этом случае - person Ashish Shetkar; 02.12.2015

Я также думаю, что сортировка XSL была бы лучше и быстрее.

Проверьте следующие ссылки,

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

благодаря.

person Parth    schedule 27.05.2010

Если вы хотите, чтобы результатом сортировки был один список, отсортированный по дате, вам нужно поместить все узлы в один список массива. Если два типа (node1 и node2) расширяют общий базовый класс, вы можете использовать Java Generics для своего списка.

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

Если два типа узлов не наследуются от общего класса, вы можете просто использовать список объектов.

Теперь вам нужно будет написать свой собственный компаратор. вот пример того, который вы могли бы использовать, если типы узлов имеют общий суперкласс, который содержит поле Date.

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

Теперь, когда у вас есть собственный компаратор и массив со всеми узлами, для сортировки списка требуется всего одна строка кода Java.

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

Документ Javadoc для вышеуказанного метода можно найти здесь, если вам нужна дополнительная информация о его поведении.

Используя описанный выше метод, легко увидеть, как вы можете написать функцию сравнения любого типа, чтобы изменить поведение вашего вида. Вы также можете написать столько пользовательских классов Comparator, сколько захотите, чтобы переключать их во время выполнения. Надеюсь это поможет! :)

person Jesse Webb    schedule 26.05.2010

Я использовал XSLT и XALAN.

XSL приведен ниже. Дата имеет формат мм/дд/гггг.

<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>

и код Java

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 *************");
  }
}
person Java Guy    schedule 27.05.2010
comment
Круто, приятно посмотреть, как это реализовать на Java. Ваш ответ здесь выглядит довольно странно - прокрутка текстовых областей внутри прокручиваемых текстовых областей - я уверен, что это ТАК ошибка... - person blissapp; 29.05.2010
comment
Я ничего не делал намеренно, чтобы иметь две тестовые области с прокруткой.. Просто так получилось.. Я тоже удивлен этим.. :) - person Java Guy; 31.05.2010