java - 如何用DOM解析大型xml文档?

标签 java xml

我想解析具有以下事件的 xml 元素:

  • 并且没有 xml 声明
  • 可以不按特定顺序提供元素
<employees>
   <employee>
      <details>
         <name>Joe</name>
         <age>34</age>
      </details>
      <address>
         <street>test</street>
         <nr>12</nr>
      </address>
   </employee>
   <employee>
      <address>....</address>
      <details>
         <!-- note the changed order of elements! -->
         <age>24</age>
         <name>Sam</name>
      </details>
   </employee>
</employees>

输出应为 csv:

name;age;street;nr
Joe,34,test,12
Sam,24,...

问题:当使用像 stax/sax 这样的事件驱动解析器时,我必须创建一个临时的 Employee我在每个事件节点上设置其属性的 bean,然后将 bean 转换为 csv。

但是由于我的 xml 文件大小有几 GB,我希望避免为每个条目创建额外的 bean 对象。

因此我可能不得不使用普通的旧 DOM解析?如果我错了,请纠正我,我很高兴收到任何建议。

我尝试如下。问题是doc.getElementsByTagName("employees")返回一个空节点列表,而我期望一个 xml 元素。为什么?

StringBuilder sb = new StringBuilder();

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xml)));
doc.getDocumentElement().normalize();

NodeList employees = doc.getElementsByTagName("employees");
for (int i = 0; i < employees.getLength(); i++) {
    Node employee = employees.item(i);
    if (employees.getNodeType() == Node.ELEMENT_NODE) {
        NodeList employee = ((Element) employees).getElementsByTagName("employee");
        for (int j = 0; j < employee.getLength(); j++) {
            NodeList details = ((Element) employee).getElementsByTagName("details");

            //the rest is pseudocode
            for (details)
                sb.append(getElements("name").item(0) + ",");
                sb.append(getElements("age").item(0) + ",");    

            for (address) 
                sb.append(getElements("street").item(0) + ",");
                sb.append(getElements("nr").item(0) + ",");
        }
    }
}

最佳答案

DOM 解决方案将使用大量内存,SAX/Stax 解决方案将涉及编写和调试大量代码。这项工作的理想工具是 XSLT 3.0 可流式转换:

<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:mode streamable="yes" on-no-match="shallow-skip"/>
  <xsl:template match="employee">
    <xsl:value-of select="copy-of(.)!(.//name, .//age, .//street, .//nr)" 
                  separator=","/>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>
</xsl:transform>

注意

我最初将选择表达式编写为copy-of(.)//(name,age,street,nr)。这是不正确的,因为 // 运算符将结果按文档顺序排序,这是我们不希望的。使用 !, 小心地避免了排序。

关于java - 如何用DOM解析大型xml文档?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50231072/

相关文章:

java - 警告对话框点击

xml - XSLT,如何获取和输出组合元素

java - 奇怪的(对我来说)循环错误

java - Primefaces - 如何获取 CellEditEvent 的列

java - 如何解决 INKApi 错误

.net - 创建 XML 并通过 HTTP post 发送

xml - 用于提取值列表的 Haskell HXT

java - 如何在 XSLT 2.0 中获取当前 xml 文件名?

java - 运行 JUNIT 测试用例时无法加载 ApplicationContext

java - 使用此问题中提供的数据递归创建 TreeView?