微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

以最少的内存使用量将 XML 转换为 Java

如何解决以最少的内存使用量将 XML 转换为 Java

我希望能够使用尽可能少的内存将大型 XML 文件中的一小部分数据转换为 Java。例如,在下面的代码中,我希望能够从 XML 中提取 id='3' 的文档及其属性,而无需遍历其他文档。我可以单独使用 JAXB 来做到这一点吗?我是否需要结合使用 XPath 和 JAXB?我应该使用 JAXB MOXy 吗?

<Example id="10" date="1970-01-01" version="1.0">
   <Properties>...</Properties>
   <Summary>...</Summary>
   <Document id="1">...</Document>
   <Document id="2">...</Document>
   <Document id="3">...</Document>
</Example>

解决方法

我有一段时间没有使用 JAXB,但无论选择什么解决方案,您都需要遍历 XML 文档以读取数据,隐式使用 DOM(然后可能是 XPath)或显式使用 SaX 等流 API(推送模型,您通过回调获取数据)或 StAX(拉模型,您通过调用方法获取数据)。

JAXB Users Guide 在“4.4. 处理大文档”部分,“4.4.1. 按块处理文档”小节中给出了以下信息。我在 Github 上添加了示例链接。我这里没有足够的空间来包含所有内容。

这种XML适用于chunk-processing;主要思想是使用 StAX API,运行一个循环,并分别解组单个块。您的程序作用于单个块,然后将其丢弃。这样,您最多只能在内存中保留一个块,这样您就可以处理大型文档。

有关如何执行此操作的更多信息,请参阅 JAXB RI 发行版中的 streaming-unmarshalling examplepartial-unmarshalling example。流式解组示例的优点是它可以在任意嵌套级别处理块,但它需要您处理推送模型 --- JAXB 解组器会将新块“推送”给您,您需要正确处理它们

相比之下,部分解组示例在拉模型中工作(这通常使处理更容易),但这种方法在数据绑定部分而不是重复部分有一些限制。

pull-parserxml-channel 示例看起来也很有希望。我根据 pull-parser 中的简单代码制作了一个 MWE。实现位于 Eclipse Implementation of JAXB

$ cat source.xml
<?xml version="1.0" encoding="UTF-8" ?>
<Example id="10" date="1970-01-01" version="1.0">
   <Properties>properties</Properties>
   <Summary>summary</Summary>
   <Document id="1">one</Document>
   <Document id="2">two</Document>
   <Document id="3">three</Document>
</Example>
$ cat document.xsd
<?xml version="1.0" encoding="UTF-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="Document">
    <xs:complexType>
      <xs:simpleContent>
        <xs:extension base="xs:string">
          <xs:attribute name="id" type="xs:int"/>
        </xs:extension>
      </xs:simpleContent>
    </xs:complexType>
  </xs:element>

</xs:schema>
$ cat Main.java
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Unmarshaller;
import java.io.FileReader;

import javax.xml.stream.*;
import static javax.xml.stream.XMLStreamConstants.*;
import generated.Document;

public class Main {
  public static void main(String[] args) throws Exception {
    int id = 3;
    JAXBContext jaxbContext = JAXBContext.newInstance("generated");
    Unmarshaller um = jaxbContext.createUnmarshaller();

    XMLInputFactory xmlif = XMLInputFactory.newInstance();
    XMLStreamReader xmlr  = xmlif.createXMLStreamReader(new FileReader("source.xml"));
    int event;
    while (true) {
      event = xmlr.next();
      if (event == END_DOCUMENT) break;
      if (event == START_ELEMENT && xmlr.getName().getLocalPart().equals("Document") && xmlr.getAttributeValue(null,"id").equals("3")) {
        Document document = (Document) um.unmarshal(xmlr);
        System.out.printf("Text is \"%s\"\n",document.getValue());
      }
    }
  }
}
$ java --version
openjdk 15.0.1 2020-10-20
OpenJDK Runtime Environment (build 15.0.1+9-18)
OpenJDK 64-Bit Server VM (build 15.0.1+9-18,mixed mode,sharing)

$ wget https://repo1.maven.org/maven2/com/sun/xml/bind/jaxb-ri/3.0.0/jaxb-ri-3.0.0.zip
$ unzip jaxb-ri-3.0.0.zip
$ export PATH=`pwd`/jaxb-ri/bin:$PATH
$ export CLASSPATH=.:jaxb-ri/mod/*

$ xjc.sh document.xsd
Java major version: 15
parsing a schema...
compiling a schema...
generated/Document.java
generated/ObjectFactory.java

$ javac generated/*.java
$ javac Main.java
$ java Main
Text is "three"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?