代码之家  ›  专栏  ›  技术社区  ›  DigitalZebra

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

  •  1
  • DigitalZebra  · 技术社区  · 15 年前

    我相信这可能已经被详细讨论过或回答过了,但是我需要更多的信息来了解适合我的情况的最佳方法。。。

    问题:
    我们有一些大的XML数据(从100k到5MB不等),需要将其膨胀为Java对象。问题是数据实际上根本没有很好地映射到对象上,所以我们只需要将数据的某些部分提取出来并创建对象。鉴于此,JAXB或XStream之类的解决方案确实不合适。

    因此,我们需要将XML数据提取出来,并尽可能高效地将其放入java对象中。


    可能的解决方案:
    在我看来,我们有三种可能的解决方案:

    • SAX解析
    • DOM解析
    • XSLT

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


    问题
    我有几个问题/担心:

    • 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 回复  |  直到 15 年前
        1
  •  3
  •   Jherico    15 年前

    使用XSLT将大型XML文件转换为本地域模型,该模型通过JAXB映射到java objets。

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

    不要关注SAX/DOM的相对性能,要关注如何编写XPath表达式和使用XSLT,然后在发现性能有问题时才考虑性能问题。

    EclipseXML编辑器很不错,但是如果您负担得起的话,可以使用SpringforOxygenXML,它可以让您实时地进行XPath评估。

        2
  •  2
  •   Fortyrunner    15 年前

    我们也遇到过类似的情况,我只是拼凑了一些XPath代码来解析我需要的东西。

    即使在100k多个XML文件上,它的速度也惊人地快。我们尽可能低技术含量。我们每天处理大约1000个这样大小的文件,解析时间非常短。我们没有内存问题、漏洞等。

    我们用Groovy编写了一个快速的原型(如果我的内存是准确的话)-概念验证花了我大约10分钟

        3
  •  2
  •   Jim Ferrans    15 年前

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

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

        4
  •  1
  •   Jim Garrison    15 年前

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

    DOM解析将整个文档加载到内存中,10万到5兆字节(按今天的标准来说非常小)就可以了。

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

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

        5
  •  1
  •   bdoughan    15 年前

    您可以在 EclipseLink JAXB (MOXy) 以便于处理这个用例。有关详细示例,请参见:

    示例代码:

    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;
    
    }