首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java XPath (Apache JAXP实现)性能

Java XPath (Apache JAXP实现)性能
EN

Stack Overflow用户
提问于 2011-06-14 16:14:17
回答 3查看 24.4K关注 0票数 56

注意:如果你也遇到了这个问题,请在Apache:上向上投票。

https://issues.apache.org/jira/browse/XALANJ-2540

我得出了一个令人惊讶的结论:

代码语言:javascript
复制
Element e = (Element) document.getElementsByTagName("SomeElementName").item(0);
String result = ((Element) e).getTextContent();

看起来比这个快了100倍:

代码语言:javascript
复制
// Accounts for 30%, can be cached
XPathFactory factory = XPathFactory.newInstance();

// Negligible
XPath xpath = factory.newXPath();

// Negligible
XPathExpression expression = xpath.compile("//SomeElementName");

// Accounts for 70%
String result = (String) expression.evaluate(document, XPathConstants.STRING);

我使用的是JVM的默认JAXP实现:

代码语言:javascript
复制
org.apache.xpath.jaxp.XPathFactoryImpl
org.apache.xpath.jaxp.XPathImpl

我真的很困惑,因为很容易看出JAXP如何优化上面的XPath查询来实际执行一个简单的getElementsByTagName()。但它似乎并没有做到这一点。这个问题仅限于5-6个频繁使用的XPath调用,这些调用被API抽象并隐藏起来。这些查询只涉及针对始终可用的DOM文档的简单路径(例如,/a/b/c、无变量、条件)。因此,如果可以进行优化,这将是相当容易实现的。

我的问题是:XPath的缓慢是一个公认的事实,还是我忽略了什么?有没有更好(更快)的实现?或者,对于简单的查询,我应该完全避免使用XPath吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-14 17:45:03

我已经调试和分析了我的测试用例和Xalan/JAXP。我设法找出了

代码语言:javascript
复制
org.apache.xml.dtm.ObjectFactory.lookUpFactoryClassName()

可以看出,10k个测试XPath评估中的每一个都会导致类加载器尝试在某种默认配置中查找DTMManager实例。此配置不会加载到内存中,但每次都会被访问。此外,这种访问似乎受到ObjectFactory.class本身的锁的保护。当访问失败时(默认情况下),将从xalan.jar文件的

代码语言:javascript
复制
META-INF/service/org.apache.xml.dtm.DTMManager

配置文件。每次都是

幸运的是,可以通过如下所示指定JVM参数来覆盖此行为:

代码语言:javascript
复制
-Dorg.apache.xml.dtm.DTMManager=
  org.apache.xml.dtm.ref.DTMManagerDefault

代码语言:javascript
复制
-Dcom.sun.org.apache.xml.internal.dtm.DTMManager=
  com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault

上面的方法是有效的,因为如果工厂类名是默认的,这将允许在lookUpFactoryClassName()中绕过昂贵的工作:

代码语言:javascript
复制
// Code from com.sun.org.apache.xml.internal.dtm.ObjectFactory
static String lookUpFactoryClassName(String factoryId,
                                     String propertiesFilename,
                                     String fallbackClassName) {
  SecuritySupport ss = SecuritySupport.getInstance();

  try {
    String systemProp = ss.getSystemProperty(factoryId);
    if (systemProp != null) { 

      // Return early from the method
      return systemProp;
    }
  } catch (SecurityException se) {
  }

  // [...] "Heavy" operations later

下面是对一个90kXML文件(用System.nanoTime()测量)进行10k次连续XPath评估的//SomeNodeName性能改进概览

代码语言:javascript
复制
measured library        : Xalan 2.7.0 | Xalan 2.7.1 | Saxon-HE 9.3 | jaxen 1.1.3
--------------------------------------------------------------------------------
without optimisation    :     10400ms |      4717ms |              |     25500ms
reusing XPathFactory    :      5995ms |      2829ms |              |
reusing XPath           :      5900ms |      2890ms |              |
reusing XPathExpression :      5800ms |      2915ms |      16000ms |     25000ms
adding the JVM param    :      1163ms |       761ms |        n/a   |

注意,基准测试是一个非常原始的基准测试。您自己的基准测试很可能会显示saxon优于xalan

我已经将此作为bug提交给Apache的Xalan人员:

https://issues.apache.org/jira/browse/XALANJ-2540

票数 63
EN

Stack Overflow用户

发布于 2011-12-23 15:32:06

不是一个解决方案,而是指向主要问题的指针:相对于任意节点计算xpath的过程中,最慢的部分是DTM管理器查找节点句柄所用的时间:

http://javasourcecode.org/html/open-source/jdk/jdk-6u23/com/sun/org/apache/xml/internal/dtm/ref/dom2dtm/DOM2DTM.html#getHandleOfNode%28org.w3c.dom.Node%29

如果有问题的节点在文档的末尾,那么对于每个查询,它可能会遍历整个树来查找有问题的节点。

这解释了为什么孤立目标节点的黑客攻击有效。应该有一种方法来缓存这些查找,但在这一点上,我看不到如何缓存。

票数 6
EN

Stack Overflow用户

发布于 2013-07-29 16:14:49

为了回答你的问题,vtd-xml比Jaxen或Xalan快得多(我会说平均快10倍,据报道是60倍……

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6340802

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档