【问题标题】:How to deserialize Java objects from XML?如何从 XML 反序列化 Java 对象?
【发布时间】:2010-11-10 22:32:31
【问题描述】:

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

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

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


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

  • 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 代码中的?

【问题讨论】:

  • 在下面查看我的答案。解析几个字段的 XPath 通常确实非常简单,而且通常非常快。
  • XSLT 使用 XML 树,因此它使用一些 DOM 提供程序。但是在这里,您必须测量“普通”DOM 实现和转换的焦点语言之间的性能(和开发时间)...... XSLT 也可以与 SAX 和流式处理(检查 Saxon XSLT 处理器)一起使用。我认为您可以从这个链开始,然后使用一些桥接器,这样流式传输的结果将直接提供一些 SAX,以便使用众所周知的 XML-Java 对象库。
  • @vtd-xml-author - JAXB 是一种无模式数据绑定技术。仅仅因为您可以使用 JAXB 从模式生成对象模型,并不意味着您也可以。您发布的文章还错误地将 Castor 描述为需要架构。

标签: java xml performance xslt


【解决方案1】:

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

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

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

Eclipse XML 编辑器很不错,但如果您负担得起,请选择 Oxygen XML,它可以让您实时进行 XPath 评估。

【讨论】:

  • 为什么在使用 XSLT 处理 XML 时不能只将 XML 映射到我的域模型?我不明白使用 XSLT 将其转换为 JAXB 可以使用的格式的好处,只是让 JAXB 再次解析 XML。
  • IME,SAX 和 DOM 之间并没有太多的性能比较,它真的只是归结为“你的文档足够小,可以在内存中解析吗?”如果是这样,那么基于 DOM 的解析器就是要走的路。如果没有,那么你需要去 SAX。如果您的需求非常简单,请不要害怕跳过整个 API,只需将您的文档视为文本流并自己解析即可。我经常为消息路由器这样做,我需要解析的几个字段位于文档的开头。
【解决方案2】:

我们遇到了类似的情况,我只是将一些 XPath 代码拼凑在一起,以解析我需要的东西。

即使是 100k+ XML 文件,它的速度也快得惊人。我们尽可能地低科技。我们每天处理大约 1000 个这种大小的文件,解析时间非常短。我们没有内存问题、泄漏等。

我们用 Groovy 编写了一个快速原型(如果我没记错的话)——概念验证花了我大约 10 分钟

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 这就是我询问 XSLT 的原因……我需要知道 XSLT 处理器是如何工作的……最常见的实现是 DOM 还是 SAX。 XSLT 比 SAX 更易于使用,但如果它对性能的要求太大,那么我们就不得不使用 SAX。
    • JAXB 可以从 Java 类开始。查看如何使用 EclipseLink JAXB (MOXy) 中的 @XmlPath 扩展在此用例中利用 XPath:stackoverflow.com/questions/4149776/…
    【解决方案4】:

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

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

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

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

    【讨论】:

      【解决方案5】:

      您可以使用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;
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-24
        • 1970-01-01
        • 1970-01-01
        • 2013-01-23
        • 2018-10-11
        • 2017-08-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多