如何从XML反序列化Java对象?

时间:2010-11-10 22:32:31

标签: java xml performance xslt

我确信这可能已经详细讨论过或者之前已经回答过,但是我需要更多关于我的情况的最佳方法的信息......

问题:
我们有一些大型XML数据(从100k到5MB不等),我们需要将它们扩展到Java对象中。问题是数据根本不能很好地映射到对象上,所以我们只需要拉出数据的某些部分并创建对象。鉴于此,JAXB或XStream等解决方案确实不合适。

因此,我们需要提取XML数据并尽可能高效地将其导入Java对象。


可能的解决方案:
我看到它的方式,我们有3种可能的解决方案:

  • SAX解析
  • DOM解析
  • XSLT

我们可以将XML加载到任何JAXP实现中,并使用上述方法之一拉出数据。


问题(S)
我有几个问题/担忧:

  • XSLT如何在幕后工作?它只是一个DOM解析器吗?我问,因为XSLT似乎是一个很好的方法,但我真的不想考虑它,如果它不会给我们比DOM更好的性能。
  • 哪些流行的库提供DOM,XSLT和SAX XML解析器?
  • 根据您的经验,选择DOM,SAX或XSLT的原因是什么? DOM或XSLT的易用性是否完全支配SAX提供的性能改进?
  • 那里有任何基准吗?我发现的那些是旧的(如8岁)。因此,最近的一些基准将不胜感激。
  • 除了上面提到的那些我可能会遗漏的其他解决方案吗?


修改
一些说明......您可以使用XSLT直接将值注入Java对象...它通常用于将XML转换为其他XML,但我是从调用XSLT到java的方法的角度来谈论注入价值。

我还不清楚XSLT处理器是如何正常工作的...它如何将XML提供给你编写的XSLT代码?

5 个答案:

答案 0 :(得分:3)

使用XSLT将大型XML文件转换为使用JAXB映射到java对象的本地域模型。

从内置XML库的JDK 5+开始(除非你绝对需要XSLT 2.0,在这种情况下使用Saxon)

不要专注于SAX / DOM的相对性能,专注于学习如何编写XPath表达式和使用XSLT,然后当且仅当您发现它是一个问题时才会担心性能。

Eclipse XML编辑器很不错,但如果你能负担得起,可以使用Oxygen XML,它可以让你实时进行XPath评估。

答案 1 :(得分:2)

我们有类似的情况,我只是将一些XPath代码整理在一起,解析了我需要的东西。

即使在100k + XML文件上也非常快。我们尽可能地低技术。我们每天处理大约1000个文件,并且解析时间非常短。我们没有内存问题,泄漏等。

我们在Groovy中写了一个快速原型(如果我的记忆准确的话) - 概念证明花了我大约10分钟

答案 2 :(得分:2)

JAXB,XML绑定的Java API可能就是您想要的。您可以使用它将XML文档扩展为由“Java内容对象”组成的Java对象图。这些内容对象是JAXB生成的类的实例,以匹配XML文档的模式

但是如果你已经拥有一组Java类,或者还没有该文档的架构,那么JAXB可能不是最好的方法。我建议做一个SAX解析,然后在解析期间构建你的Java对象。或者,您可以尝试DOM解析,然后遍历生成的Document树以提取感兴趣的部分(可能使用XPath) - 但是5MB的XML可能会变成Java中的50MB DOM树对象。

答案 3 :(得分:1)

DOM,SAX和XSLT是不同的动物。

DOM解析将整个文档加载到内存中,对于100K到5MB(按照今天的标准来说非常小)可以工作。

SAX是一个流解析器,它读取XML并将事件传递给每个标记的代码。

XSLT是一个将一个XML树转换为另一个XML树的系统。即使你编写了一个将输入转换为更合适的格式的转换,你仍然需要使用DOM或SAX编写一些东西来将其转换为Java对象。

答案 4 :(得分:1)

您可以使用EclipseLink JAXB (MOXy)中的@XmlPath扩展来轻松处理此用例。有关详细示例,请参阅:

示例代码:

package blog.geocode;

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

import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement(name="kml")
@XmlType(propOrder={"country", "state", "city", "street", "postalCode"})
public class Address {

    @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:Thoroughfare/ns:ThoroughfareName/text()")
    private String street;

    @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:LocalityName/text()")
    private String city;

    @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:AdministrativeAreaName/text()")
    private String state;

    @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:CountryNameCode/text()")
    private String country;

    @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:PostalCode/ns:PostalCodeNumber/text()")
    private String postalCode;

}