【问题标题】:Parse an xml file of the below format in Java在 Java 中解析以下格式的 xml 文件
【发布时间】:2017-01-28 05:04:14
【问题描述】:

我有一个以下格式的 xml 文件,作为来自服务的响应。它不是传统的 xml 格式,其中值包含在相应的标签中。这只是一个示例,而实际文件将包含数百个元素。我如何以最有效的方式到达我需要的节点(比如说“TDE-2”)并将其值放在像{map(TenderID, TDE-2), map(ContactID, null)}这样的地图中

<xml version="1.0" encoding="UTF-8"?>
<report>
<report_header>
<c1>TenderID</c1>
<c2>ContactID</c2>
<c3>Address</c3>
<c4>Description</c4>
<c5>Date</c5>
</report_header>
<report_row>
<c1>TDE-1</c1>
<c2></c2>
<c3></c3>
<c4>Tender 1</c4>
<c5>09/30/2016</c5>
</report_row>
<report_row>
<c1>TDE-2</c1>
<c2></c2>
<c3></c3>
<c4>Tender 2</c4>
<c5>10/02/2016</c5>
</report_row>
</report>

【问题讨论】:

  • 您在 cmets 中所说的与答案的“差异”究竟是什么?它是简单的 XML,只需要解析,不是吗?你能澄清一下具体的问题是什么吗?
  • 使用 SAX 或 StaX 解析 XML。在阅读标题时,您可以存储列描述。稍后在每一行上,您可以使用列描述到列的关系来识别感兴趣的列。但不要指望我们会为您编写整个代码。如果遇到困难,您应该自己开始并向我们展示您的代码。
  • @vanje 我已经按照你的建议编写了代码;但是如果我感兴趣的数据位于最后一个元素中,我将通过这种方式依次遍历直到 xml 文件的末尾。我正在寻找一条建议来优化我的代码而不是原始代码。
  • 如果您想更快地访问每个密钥,您有多种可能性。 (但它们都需要至少解析整个 XML 文档一次。) 1. 如果您的内存足够大,您可以创建一个哈希映射,然后使用该映射访问数据。 2. 将数据放入数据库表并创建适当的索引。您的数据结构非常适合普通关系数据库。 3. 使用 eXist 或 BaseX 等 XML 数据库。但我不建议将它用于您的数据,因为它本质上是一个没有层次结构的平面表。
  • 第四种选择: 4. 手动创建您自己的索引。解析 XML 文件并在索引哈希映射中存储每个元素的文件位置以及键列的值。这仅适用于关键数据对于主内存来说不是太大的情况,但它需要的空间比将所有数据保存在内存中要少。然后,您使用地图查找密钥的文件位置,然后使用随机访问文件从文件中仅读取该元素。但这是很多工作。我可能会使用一个数据库表,它可能带有像 H2 或 Apache Derby 这样的嵌入式数据库系统。

标签: java xml parsing xml-parsing


【解决方案1】:

JAXB 允许您将 XML 反序列化为 Java 对象。如果您创建 Java POJO 来匹配 XML 文档模型,那么您可以使用 JAXB 在 POJO 中解组 XML。

例如:

POJO:

Report.java

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Report {

    private List<ReportRow> reportRows;

    public List<ReportRow> getReportRows() {
        return reportRows;
    }

    @XmlElement(name = "report_row")
    public void setReportRows(List<ReportRow> reportRows) {
        this.reportRows = reportRows;
    }
}

ReportRow.java

import javax.xml.bind.annotation.XmlElement;

public class ReportRow {

private String c1;
private String c2;
private String c3;
private String c4;

public String getC1() {
    return c1;
}

@XmlElement
public void setC1(String c1) {
    this.c1 = c1;
}

public String getC2() {
    return c2;
}

@XmlElement
public void setC2(String c2) {
    this.c2 = c2;
}

public String getC3() {
    return c3;
}

@XmlElement
public void setC3(String c3) {
    this.c3 = c3;
}

public String getC4() {
    return c4;
}

@XmlElement
public void setC4(String c4) {
    this.c4 = c4;
}

}

读取 XML 并将其绑定到 java 对象的代码:

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.junit.Test;

public class JaxbTest {

    @Test
    public void testFoo() throws JAXBException {

        File xmlFile = new File("src/test/resources/reports.xml");
        JAXBContext context = JAXBContext.newInstance(Report.class, ReportRow.class);
        Unmarshaller jaxbUnmarshaller = context.createUnmarshaller();
        Report report = (Report) jaxbUnmarshaller.unmarshal(xmlFile);
        ReportRow reportYouWant = report.getReportRows().stream().filter(reportRow -> reportRow.getC1().equals("TDE-1"))
                .findFirst().get();

    }
}

您还需要在构建脚本中添加以下依赖项:

compile group: 'javax.xml', name: 'jaxb-impl', version: '2.1'
compile group: 'javax.xml', name: 'jaxb-api', version: '2.1'

【讨论】:

  • 当我创建一个 ReportCollection 类的对象时,我收到一个错误,因为“没有找到适合解组的方法”。你能指导我吗?
  • 我已经更新了答案中的示例。我已经测试了这段代码并且它有效。如果您对此感到满意,请接受它作为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多