【问题标题】:Reading a list of XML elements in Java在 Java 中读取 XML 元素列表
【发布时间】:2011-08-09 17:04:51
【问题描述】:

我想遍历一个 XML 文档,该文档本质上是一个结构相同的 XML 元素的列表。元素将被序列化为 Java 对象。

<root>
    <element attribute="value" />
    <element attribute="value" />
    <element attribute="value" />
    ...
</root>

根元素中有很多元素。我不希望将它们全部加载到内存中。我意识到我可以为此使用 SAX 处理程序,但是使用 SAX 处理程序将所有内容反序列化为 Java 对象似乎相当迟钝。我发现 JDOM 非常易于使用,但据我所知,JDOM 总是解析整个树。有没有一种方法可以使用 JDOM 一次解析一个子元素?

使用 JDOM 的另一个原因是它使得为相应的 Java 对象编写序列化/反序列化代码变得容易,如果不完全在内存中,这些对象就毫无意义。但是,我不想同时将所有 Java 对象加载到内存中。相反,我想对它们进行一次迭代。

更新:这是一个如何在 dom4j 中执行此操作的示例:http://docs.codehaus.org/display/GROOVY/Reading+XML+with+Groovy+and+DOM4J。无论如何要在 jdom 中执行此操作?

【问题讨论】:

  • 你可能应该看看JSefa 它不是很流行但简单易用。您应该下载它并查看示例。

标签: java xml


【解决方案1】:

简短的回答:没有。 Jdom 是关于解析 xml 并将其转换为数据结构以执行操作。这意味着总是反序列化整个 xml。

【讨论】:

  • 您会推荐什么替代方案?有没有办法结合使用 SAX 处理程序和 JDOM 来解析子树?
  • 我看不出 JDOM 非常适合您的需求。如果您仍然坚持使用它,我想您可以让 SAX 解析器在解析 XML 时创建过滤后的 JDOM 文档。
  • 让我澄清一下,子元素比上面的例子复杂得多。
  • 不过,如果你不想将整个xml存储在内存中,你需要在读取流时表达出要存储哪些部分。也许另一个 xml 解析器更合适。我的同事喜欢kxml。不过自己没试过。
【解决方案2】:

一种可以减少内存需求的简单方法是使用带有 JDOM 的 XPath 来查询 XML 的子集,并且只获取那些满足查询的位。

否则你可以看看这个interesting hint from Elliotte Rusty Harold,它表明你想要的流API在那里,只是没有宣传:

JDOM 确实有一个流式 API。它只是有点隐藏而不是广泛 广告或解释。在 XOM 中,我更多地采用了这种方法 明确并记录在案。如果你想要一个流树模型, 使用 XOM 可能会更好,但如果您必须坚持使用 JDOM 那么阅读 XOM 示例可能会给你足够的线索 如何在流模式下使用 JDOM。

【讨论】:

  • 感谢您的链接。我看到了 2001 年提到的流媒体功能 (jdom.org/pipermail/jdom-interest/2000-November/002876.html)。似乎有很多兴趣,但它似乎也没有去任何地方。我将调查 XPath,但我不确定它是否是我正在寻找的,因为我想要所有结果,但我一次只需要内存中的每个结果。
【解决方案3】:

你应该使用VTD-XML,它主要用于流处理。我用它来读取广告商的产品信息。

最大的优点是它只需要一个 XPath,它可以以极快的速度迭代 XML,并且内存占用非常小(在迭代 XML 时只保留几个指针)。

我知道该网站说它们的执行速度比解析 DOM 快 5-12 倍,但根据我对您的任务类型的经验(特别是如果大小在 100 MB 以内),您可以轻松获得 20 倍的速度。

下面是一个如何使用 VTD-XML 读取 XML 的简单示例:

VTDGen vg = new VTDGen();
AutoPilot ap = new AutoPilot();
int i;
ap.selectXPath("/root/element");
if (vg.parseFile(FILE_LOCATION,true)){
    VTDNav vn = vg.getNav();
    ap.bind(vn); // apply XPath to the VTDNav instance
    // AutoPilot moves the cursor for you
    while((i=ap.evalXPath())!=-1){
        System.out.println("the attribute index val is "+ 
            i +" the attribute string ==>"+vn.toString(vn.getAttrVal("attribute")));
    }
}

【讨论】:

    【解决方案4】:

    为什么不使用 StAX(javax.xml.stream.*,Java SE 6 中包含一个实现)在 XML 中进行流式传输,并将各个部分转换为对象?

    import java.io.FileReader;
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.stream.XMLInputFactory;
    import javax.xml.stream.XMLStreamReader;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Element.class);
            Unmarshaller unmarshaller = jc.createUnmarshaller();
    
            XMLInputFactory xif = XMLInputFactory.newFactory();
            XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
            xsr.nextTag();
            xsr.nextTag();
            while(xsr.hasNext()) {
                Element element = (Element) unmarshaller.unmarshal(xsr);
                System.out.println(element.getAttribute());
                if(xsr.nextTag() != XMLStreamReader.START_ELEMENT) {
                    break;
                }
            }
        }
    
    }
    

    在上面的示例中,每个单独的“元素”都使用 JAXB 解组到 POJO(Java SE 6 中包含一个实现),但是您可以按照您认为合适的方式处理片段。 JAXB 模型详情如下:

    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement
    public class Element {
    
        private String attribute;
    
        @XmlAttribute
        public String getAttribute() {
            return attribute;
        }
    
        public void setAttribute(String attribute) {
            this.attribute = attribute;
        }
    
    }
    

    注意:

    StAX 和 JAXB 也兼容 Java SE 5,您只需要单独下载实现即可。

    【讨论】:

      猜你喜欢
      • 2020-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-06
      • 2016-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多