首页 > 解决方案 > DeferredDocumentImpl 上的 XPath 需要很长时间来评估

问题描述

在 Java 中,我从这样的文件加载一个 XML 文件,它返回一个 DeferredDocumentImpl

private Document loadMasterFileXml(String path)
{
    File masterFilePath = new File(path);
    DocumentBuilderFactory masterDocBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder masterDocBuilder = masterCbcCollBuilderFactory.newDocumentBuilder();
    masterDocument = masterDocBuilder.parse(masterFilePath);
    return masterDocument;
}

XML 文件包含大约 1000 个元素,如下所示:

<com.something.something.Collection xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:com.something.something.model="http://www.something.com/something.1.0.0" xmi:id="_HklwsJnWEeeaddrVFPWCMg" name="SOME_THING">
  <signals xmi:id="_N0ir0ZnWEeeaddrVFPWCMg" id="10000">
    <signal href="#_6M0edJhNEeeNvfntr9AQ8g"/>
  </signals>
  <signals xmi:id="_N0jS4JnWEeeaddrVFPWCMg" id="10001">
    <signal href="#_6M1FgJhNEeeNvfntr9AQ8g"/>
  </signals>
  ...

对该文档执行的第一个 XPath 操作如下:

public long getMaximumSignalIdFromMasterDocument()
{
    Integer errorCode=-1;
    try 
    {
        XPathFactory xPathfactory = XPathFactory.newInstance();
        XPath xPath = xPathfactory.newXPath();
        String expression = "//signals[not(@id < //signals/@id)]";
        Node node = (Node) xPath.evaluate(expression, masterCbCollDocument, XPathConstants.NODE);
        return Long.parseLong(node.getAttributes().getNamedItem("id").getNodeValue());
    }
    catch(Exception e) 
    {
        return errorCode;
    }        
}

在调试模式下,以下行需要超过 1 小时才能执行。

节点节点 = (Node) xPath.evaluate(表达式, masterCbCollDocument, XPathConstants.NODE);

为什么是这样?

XPath 表达式是否有问题(使用 //)?是因为文档的具体实现被推迟了,所以文件 IO 太多了吗?

任何人都可以提出另一种方法吗?

标签: javaxmlperformancexpath

解决方案


另一种方法是避免使用 XPath。尽管长达一小时的计算似乎更可能成为您使用的调试器/IDE 的问题,但 XPath 表达式的效率也不是很高 (O(n^2)),并且无法在 XPath 1.0 中得到显着优化。在这种情况下直接使用 Java 似乎更合适。一种方法可以是:

NodeList signals = masterCbCollDocument.getElementsByTagName("signals");
long result = IntStream.range(0, signals.getLength()).mapToLong(i -> Long.parseLong(((Element)signals.item(i)).getAttribute("id"))).max().orElse(-1);

在这种情况下,它的作用与 XPath 表达式masterCbCollDocument.getElementsByTagName相同。//signals然后将 NodeList 中的结果signal元素映射到它们各自的 ID,并返回其中的最大值。


推荐阅读