如果性能是一个重要因素,和/或文档大小很大(这里似乎都是这种情况),那么事件解析器(如 SAX 或 StAX)与本机 Java XPath 实现之间的区别在于后者构建评估 XPath 表达式之前的 W3C DOM 文档。[有趣的是,所有 Java 文档对象模型实现,如 DOM 或 Axiom 都使用事件处理器(如 SAX 或 StAX)来构建内存表示,所以如果你只使用事件处理器就可以了节省内存和构建 DOM 所需的时间。]
正如我所提到的,JDK 中的 XPath 实现在 W3C DOM 文档上运行。您可以通过查看 Java JDK 源代码实现来看到这一点com.sun.org.apache.xpath.internal.jaxp.XPathImpl
,其中在调用 evaluate() 方法之前,解析器必须首先解析源代码:
Document document = getParser().parse( source );
在此之后,您的 10GB XML 将在内存中表示(加上任何开销)——可能不是您想要的。虽然您可能想要一个更“通用”的解决方案,但您的示例 XPath 和您的 XML 标记看起来都相对简单,因此 XPath 似乎没有一个真正强有力的理由(除了编程优雅之外)。XProc 建议也是如此:这也将构建一个 DOM。如果你真的需要一个 DOM,你可以使用 Axiom 而不是 W3C DOM。Axiom 有一个更友好的 API,并且在 StAX 上构建它的 DOM,所以它速度很快,并且使用 Jaxen 来实现它的 XPath。Jaxen 需要一些一种 DOM(W3C DOM、DOM4J 或 JDOM)。这对于所有 XPath 实现都是正确的,因此如果您并不真正需要 XPath,建议您只使用事件解析器。
SAX 是旧的流式 API,StAX 较新,速度要快得多。无论是使用本机 JDK StAX 实现 ( javax.xml.stream
) 还是Woodstox StAX 实现(根据我的经验,这明显更快),我建议创建一个 XML 事件过滤器,它首先匹配元素类型名称(以捕获您的<txn>
元素)。这将创建少量事件(元素、属性、文本),可以检查匹配的用户值。在合适的匹配上,如果您发现结果更易于导航,您可以从事件中提取必要的信息或通过管道传输有界事件以从中构建迷你 DOM。但如果标记很简单,这听起来可能有点矫枉过正。
这可能是最简单、最快的方法,并且避免了构建 DOM 的内存开销。如果您将元素和属性的名称传递给过滤器(以便您的匹配算法是可配置的),您可以使其相对通用。