java - 如何以流式传输方式迭代巨大 XML 中的节点?

标签 java xml stream iterator

我有一个巨大的 XML 文件,如下所示:

<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
   </book>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
   </book>
   [... one gazillion more entries ...]
</catalog>

我想以流的方式迭代这个文件,这样我就不必将整个文件加载到内存中,例如:

InputStream stream = new FileInputStream("gigantic-book-list.xml");
String nodeName = "book";
Iterator it = new StreamingXmlIterator(stream, nodeName);
Document bk101 = it.next();
Document bk102 = it.next();

此外,我希望它能够处理不同的 XML 输入文件,而无需创建特定对象(例如 Book.java)。

@McDowell 有一个很有前途的方法,使用 XMLStreamReaderStreamFilter,地址为 https://stackoverflow.com/a/16799693/13365 ,但这仅提取单个节点。

此外,Camel's .tokenizeXML正是我想要的,所以我想我应该查看源代码。

最佳答案

@XmlRootElement
public class Book {
  // TODO: getters/setters
  public String author;
  public String title;
}

假设您希望将数据作为强类型对象进行处理,您可以使用实用程序类型组合 StAX 和 JAXB:

  class ContentFinder implements StreamFilter {
    private boolean capture = false;

    @Override
    public boolean accept(XMLStreamReader xml) {
      if (xml.isStartElement() && "book".equals(xml.getLocalName())) {
        capture = true;
      } else if (xml.isEndElement() && "book".equals(xml.getLocalName())) {
        capture = false;
        return true;
      }
      return capture;
    }
  }

  class Limiter extends StreamReaderDelegate {
    Limiter(XMLStreamReader xml) {
      super(xml);
    }

    @Override
    public boolean hasNext() throws XMLStreamException {
      return !(getParent().isEndElement()
               && "book".equals(getParent().getLocalName()));
    }
  }

用法:

XMLInputFactory inFactory = XMLInputFactory.newFactory();
XMLStreamReader reader = inFactory.createXMLStreamReader(inputStream);
reader = inFactory.createFilteredReader(reader, new ContentFinder());
Unmarshaller unmar = JAXBContext.newInstance(Book.class)
    .createUnmarshaller();
Transformer tformer = TransformerFactory.newInstance().newTransformer();
while (reader.hasNext()) {
  XMLStreamReader limiter = new Limiter(reader);
  Source src = new StAXSource(limiter);
  DOMResult res = new DOMResult();
  tformer.transform(src, res);
  Book book = (Book) unmar.unmarshal(res.getNode());
  System.out.println(book.title);
}

关于java - 如何以流式传输方式迭代巨大 XML 中的节点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23676373/

相关文章:

java - 如何使用 HashMap 作为一个参数使用 HTTPClient 发送 POST 请求

java - 所有 SuppressWarnings 值?

html - XSL/XML : HOw to put html tags in an xml doc so they render

xml - 使用 XSLT 用 href 属性包装所有元素

c# - 如何使用 Amazon S3 ResponseStream 返回 FileResult?

java - 传统的开源 Java 应用程序

java - 用户注册的确认电子邮件如何工作?

python - 如何从日志文件中提取xml以在python中解析

javascript - 如何处理奇怪组合的 websocket 消息?

c# - 我们如何有效地从 C# 中的文本文件中只读取整数