DeferredDocumentImpl上的XPath需要花费很长时间评估

时间:2018-07-25 07:45:01

标签: java xml performance 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 node =(Node)xPath.evaluate(expression,masterCbCollDocument,XPathConstants.NODE);

这是为什么?

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

有人可以建议替代方法吗?

1 个答案:

答案 0 :(得分:0)

另一种方法是避免使用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);

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