stax - получить узел XML в виде строки - PullRequest
6 голосов
/ 04 декабря 2010

xml выглядит так:

<statements>
   <statement account="123">
      ...stuff...
   </statement>
   <statement account="456">
      ...stuff...
   </statement>
</statements>

Я использую stax для обработки одного "<statement>" за раз, и я получил это сработало. Мне нужно получить весь узел оператора в виде строки, чтобы я мог создать «123.xml» и «456.xml» или даже загрузить его в таблицу базы данных, проиндексированную по учетной записи.

с использованием этого подхода: http://www.devx.com/Java/Article/30298/1954

Я хочу сделать что-то вроде этого:

String statementXml = staxXmlReader.getNodeByName("statement");

//load statementXml into database

Ответы [ 5 ]

7 голосов
/ 25 июля 2012

У меня была похожая задача, и хотя первоначальный вопрос был старше года, я не смог найти удовлетворительного ответа.Самым интересным ответом до сих пор был ответ Блеза Дафана, но я не смог запустить его на ожидаемом XML (может быть, некоторые параметры для базового синтаксического анализатора могли бы изменить это?).Вот XML, очень просто:

<many-many-tags>
    <description>
        ...
        <p>Lorem ipsum...</p>
        Devils inside...
        ...
    </description>
</many-many-tags>

Мое решение:

public static String readElementBody(XMLEventReader eventReader)
    throws XMLStreamException {
    StringWriter buf = new StringWriter(1024);

    int depth = 0;
    while (eventReader.hasNext()) {
        // peek event
        XMLEvent xmlEvent = eventReader.peek();

        if (xmlEvent.isStartElement()) {
            ++depth;
        }
        else if (xmlEvent.isEndElement()) {
            --depth;

            // reached END_ELEMENT tag?
            // break loop, leave event in stream
            if (depth < 0)
                break;
        }

        // consume event
        xmlEvent = eventReader.nextEvent();

        // print out event
        xmlEvent.writeAsEncodedUnicode(buf);
    }

    return buf.getBuffer().toString();
}

Пример использования:

XMLEventReader eventReader = ...;
while (eventReader.hasNext()) {
    XMLEvent xmlEvent = eventReader.nextEvent();
    if (xmlEvent.isStartElement()) {
        StartElement elem = xmlEvent.asStartElement();
        String name = elem.getName().getLocalPart();

        if ("DESCRIPTION".equals(name)) {
            String xmlFragment = readElementBody(eventReader);
            // do something with it...
            System.out.println("'" + fragment + "'");
        }
    }
    else if (xmlEvent.isEndElement()) {
        // ...
    }
}

Обратите внимание, что извлеченный фрагмент XML будет содержать полныйизвлеченный контент тела, включая пробелы и комментарии.Фильтрация по требованию или параметризация размера буфера были исключены для краткости кода:

'
    <description>
        ...
        <p>Lorem ipsum...</p>
        Devils inside...
        ...
    </description>
    '
6 голосов
/ 04 декабря 2010

Вы можете использовать StAX для этого.Вам просто нужно продвинуть XMLStreamReader к элементу start для оператора.Проверьте атрибут учетной записи, чтобы получить имя файла.Затем используйте API-интерфейсы javax.xml.transform для преобразования StAXSource в StreamResult, обертывающий файл.Это улучшит XMLStreamReader, а затем просто повторите этот процесс.

import java.io.File;
import java.io.FileReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;

public class Demo {

    public static void main(String[] args) throws Exception  {
        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
        xsr.nextTag(); // Advance to statements element

        while(xsr.nextTag() == XMLStreamConstants.START_ELEMENT) {
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer t = tf.newTransformer();
            File file = new File("out" + xsr.getAttributeValue(null, "account") + ".xml");
            t.transform(new StAXSource(xsr), new StreamResult(file));
        }
    }

}
2 голосов
/ 04 декабря 2010

Stax - это низкоуровневый API доступа, и у него нет ни поиска, ни методов, которые рекурсивно обращаются к контенту.Но что вы на самом деле пытаетесь сделать?И почему вы рассматриваете Stax?

Помимо использования древовидной модели (DOM, XOM, JDOM, Dom4j), которая будет хорошо работать с XPath, лучшим выбором при работе с данными обычно является библиотека привязки данных, такая как JAXB.С его помощью вы можете передать Stax или SAX Reader и попросить его связать XML-данные с Java-бинами, а не связываться с Java-объектами процесса XML.Это часто более удобно, и это обычно довольно производительность.Единственная хитрость с большими файлами состоит в том, что вы не хотите связывать все целиком сразу, а связываете каждое поддерево (в вашем случае, одно «утверждение» за раз).Это проще всего сделать, перебирая Stax XmlStreamReader, а затем используя JAXB для привязки.

1 голос
/ 04 декабря 2010

Почему бы просто не использовать xpath для этого?

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

Примерно так:

//statement

РЕДАКТИРОВАНИЕ № 1: Если возможно, взгляните на dom4j .Вы можете прочитать String и получить все узлы операторов достаточно просто.

РЕДАКТИРОВАТЬ # 2: Используя dom4j, вы так и сделаете: (из их кулинарной книги)

String text = "your xml here";
Document document = DocumentHelper.parseText(text);

public void bar(Document document) {
   List list = document.selectNodes( "//statement" );
   // loop through node data
}
1 голос
/ 04 декабря 2010

Я гуглил, и это кажется мучительно трудным.

учитывая мой xml, я думаю, может быть проще:

StringBuilder buffer = new StringBuilder();
for each line in file {
   buffer.append(line)
   if(line.equals(STMT_END_TAG)){
      parse(buffer.toString())
      buffer.delete(0,buffer.length)
   }
 }

 private void parse(String statement){
    //saxParser.parse( new InputSource( new StringReader( xmlText ) );
    // do stuff
    // save string
 }
...