stax - 将xml节点作为字符串

时间:2010-12-04 03:52:19

标签: java xml extract stax

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 个答案:

答案 0 :(得分:7)

我有类似的任务,虽然最初的问题超过一年,但我找不到令人满意的答案。到目前为止最有趣的答案是Blaise Doughan的答案,但我无法让它在我期望的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>
    '

答案 1 :(得分:6)

您可以使用StAX。您只需要将XMLStreamReader推进到start元素for语句。检查帐户属性以获取文件名。然后使用javax.xml.transform API将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 :(得分:2)

Stax是一种低级访问API,它没有查询或递归访问内容的方法。但你真正想做什么?你为什么要考虑Stax?

除了使用适用于XPath的树模型(DOM,XOM,JDOM,Dom4j)之外,处理数据时的最佳选择通常是数据绑定库,如JAXB。有了它,您可以传递Stax或SAX读取器并要求它将xml数据绑定到Java bean中,而不是弄乱xml进程Java对象。这通常更方便,而且通常性能相当。 只有较大文件的技巧是你不想一次绑定整个事物,而是绑定每个子树(在你的情况下,一次一个'语句')。 这是通过迭代Stax XmlStreamReader,然后使用JAXB绑定来完成的。

答案 3 :(得分:1)

我一直在谷歌搜索,这似乎很难。

鉴于我的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
 }

答案 4 :(得分:1)

为什么不直接使用xpath?

你可以有一个相当简单的xpath来获取所有'statement'节点。

像这样:

//statement

编辑#1:如果可能,请查看dom4j。您可以读取字符串并相当简单地获取所有“语句”节点。

编辑#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
}