Попытка получить следующий и предыдущий одноуровневый узел после анализа xml для определенного узла с использованием java

У меня есть xml, содержащий журнал 1000 событий, у каждого из которых есть ключ. Моя цель - когда пользователь ищет ключ события, я должен отобразить ему xml узла события, имеющего этот ключ, и подготовить информацию о предыдущем и следующий брат.

Структура xml выглядит следующим образом:

<LOG>
   <EVENT_SET>
      <DOCGET system="T610_00" fingerPrint="NO_SIGNATURE">
         <event>
            <key>382</key>
            <date>2015-01-28T09:15:15.350+0000</date>
            <service>CORE</service>
            <class>APPLICATION</class>
         </event>
         <document>
            <docuri>getdocs:///DocMapCSDOCS.dPortal/1</docuri>
            <sign_info>
               <signature>VqtR9Gpny/MPE43/5o4hJXp8bR7gbsVUJqHlTI+VfztMSQecTpZwAQpxmorrdBJKvmn+h7eZzV1geVodkVECvOjQMRmRbnpT6mrpbiXxjDOsZsQRDNemTYUKETrQFIBRtXcjoP61une1LOsS5C749ehwbZ1jEaNH6fPjH4n+OH4=</signature>
            </sign_info>
         </document>
      </DOCGET>
      <DOCGET system="T610_00" fingerPrint="NO_SIGNATURE">
         <event>
            <key>383</key>
            <date>2015-01-28T09:15:18.310+0000</date>
            <service>CORE</service>
            <class>APPLICATION</class>
         </event>
         <document>
            <docuri>getdocs:///DocMapCSDOCS.dPortal/2</docuri>
            <sign_info>
               <signature>VqtR9Gpny/MPE43/5o4hJXp8bR7gbsVUJqHlTI+VfztMSQecTpZwAQpxmorrdBJKvmn+h7eZzV1geVodkVECvOjQMRmRbnpT6mrpbiXxjDOsZsQRDNemTYUKETrQFIBRtXcjoP61une1LOsS5C749ehwbZ1jEaNH6fPjH4n+OH4=</signature>
            </sign_info>
         </document>
      </DOCGET>
      .......
  </EVENT_SET>
</LOG>

И мой код до сих пор, чтобы получить узел ключа:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
//parsing the xml file
journaldoc = builder.parse(journalFile);
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();

//xpath to search for the event having the key requated by the user
String sXpath = "//DOCGET[event/key='"+eventkey+"']";
XPathExpression expr = xpath.compile(sXpath);
Object result = expr.evaluate(journaldoc, XPathConstants.NODE);
Node eventnode = (Node) result;

//return to the user the xml part with root DOCGET, and having the key requested
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Node copyNode = document.importNode(eventNode, true);
document.appendChild(copyNode);
DOMImplementationLS domImplementationLS = (DOMImplementationLS) document.getImplementation();
LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
String xmlNode =  lsSerializer.writeToString(document);

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

Проблема в том, что при выполнении eventnode.getPreviousSibling и eventnode.getNextSibling я получаю поврежденную информацию и не могу получить ключ этих событий.

У кого-нибудь есть лучшая идея сделать это?

Спасибо, Карин


person user2318955    schedule 01.02.2015    source источник


Ответы (1)


Я думаю, вы ищете оси XPath preceding-sibling и following-sibling. Они выбирают все узлы на одном уровне, поэтому, если вам нужны только следующие соседи, вам нужно добавить предикат для выбора только первого: following-sibling::*[1]. Но вам нужны только узлы событий, а узлы событий не являются сиблинами напрямую, а элементы <DOCGET> являются. Таким образом, из узла событий вам нужно подняться, найти следующего/предыдущего брата и снова спуститься. Это сводится к следующему выражению: ../preceding-sibling::*[1]/event для оценки на узле события.

Вы можете упростить задачу, используя проекцию данных (Раскрытие информации: я связан с этим проектом), чтобы иметь объектно-ориентированный доступ к событий, но по-прежнему отделяют структуру кода Java от структуры XML:

public class ReadEvents {

public interface Event {
    @XBRead("./key")
    String getKey();

    @XBRead("./date using yyyy-MM-dd'T'HH:mm:ss.SSSZ")
    Date getDate();

    @XBRead("../document/docuri")
    String getDocumentURI();

    @XBRead("../preceding-sibling::*[1]/event")
    Event getPreviousEvent();

    @XBRead("../following-sibling::*[1]/event")
    Event getNextEvent();
}

public static void main(String... args) {
    List<Event> allEvents = new XBProjector().io().url("res://log.xml").evalXPath("//event").asListOf(Event.class);
    for (Event event : allEvents) {
        System.out.print(event.getDate()+ ": Event " + event.getKey());
        if (event.getPreviousEvent() != null) {
            System.out.print(" previous event has key " + event.getPreviousEvent().getKey());
        }
        if (event.getNextEvent() != null) {
            System.out.print(" next event has key " + event.getNextEvent().getKey());
        }
        System.out.println();
    }
  }
}

Для вашего примера эта программа распечатывает:

Wed Jan 28 10:15:15 CET 2015: Event 382 next event has key 383
Wed Jan 28 10:15:18 CET 2015: Event 383 previous event has key 382
person Cfx    schedule 02.02.2015