加快 xpath

2022-09-02 10:16:07

我有一个1000个条目文档,其格式如下:

<Example>
     <Entry>
          <n1></n1>
          <n2></n2>
      </Entry>
      <Entry>
          <n1></n1>
          <n2></n2>
      </Entry>
      <!--and so on-->

这里有 1000 多个入口节点。我正在编写一个Java程序,它基本上可以逐个获取所有节点,并对每个节点进行一些分析。但问题是节点的检索时间随着其no的增加而增加。例如,检索第一个节点需要78毫秒,检索第二个节点需要100毫秒,并且它不断增加。要检索 999 节点,需要 5 秒以上。这是非常缓慢的。我们将此代码插入到甚至有超过1000个条目的XML文件中。有些人喜欢数百万人。分析整个文档的总时间超过 5 分钟。

我正在使用这个简单的代码来遍历它。这是我自己的类,它具有从xpath获取节点的所有方法。nxp

nxp.fromXpathToNode("/Example/Entry" + "[" + i  + "]", doc);    

并且是文件的文档。 是要检索的节点的编号。doci

另外,当我尝试这样的事情时

List<Node> nl = nxp.fromXpathToNodes("/Example/Entry",doc);  
      content = nl.get(i);    

我面临同样的问题。

任何人都有任何关于如何加速节点的重试的解决方案,因此从XML文件中获取第1个节点和1000个节点需要相同的时间。


这是 xpathtonode 的代码。

public Node fromXpathToNode(String expression, Node context)  
{  
    try  
    {  
        return (Node)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODE);  
    }  
    catch (Exception cause)  
    {  
        throw new RuntimeException(cause);  
    }  
}  

这是 fromxpathtonodes 的代码。

public List<Node> fromXpathToNodes(String expression, Node context)  
{  
    List<Node> nodes = new ArrayList<Node>();  
    NodeList results = null;  
    
    try  
    {  
        results = (NodeList)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODESET);  
          
        for (int index = 0; index < results.getLength(); index++)  
        {  
            nodes.add(results.item(index));  
        }  
    }  
    catch (Exception cause)  
    {  
        throw new RuntimeException(cause);  
    }  
    
    return nodes;  
}  

这是开始

public class NativeXpathEngine implements XpathEngine  
{      
private final XPathFactory factory;  
  
private final XPath engine;  

/**
 * Cache for previously compiled XPath expressions. {@link XPathExpression#hashCode()}
 * is not reliable or consistent so use the textual representation instead.
 */  
private final Map<String, XPathExpression> cachedExpressions;  
  
public NativeXpathEngine()  
{
    super();  
    
    this.factory = XPathFactory.newInstance();  
    this.engine = factory.newXPath();  
    this.cachedExpressions = new HashMap<String, XPathExpression>();  
}  

答案 1

请尝试 VTD-XML。它使用的内存比 DOM 少。它比 SAX 更易于使用,并且支持 XPath。下面是一些示例代码,可帮助您入门。它应用 XPath 来获取 Entry 元素,然后打印出 n1 和 n2 子元素。

final VTDGen vg = new VTDGen();
vg.parseFile("/path/to/file.xml", false);

final VTDNav vn = vg.getNav();
final AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/Example/Entry");
int count = 1;
while (ap.evalXPath() != -1) {
    System.out.println("Inside Entry: " + count);

    //move to n1 child
    vn.toElement(VTDNav.FIRST_CHILD, "n1");
    System.out.println("\tn1: " + vn.toNormalizedString(vn.getText()));

    //move to n2 child
    vn.toElement(VTDNav.NEXT_SIBLING, "n2");
    System.out.println("\tn2: " + vn.toNormalizedString(vn.getText()));

    //move back to parent
    vn.toElement(VTDNav.PARENT);
    count++;
}

答案 2

正确的解决方案是在调用 item(i) 后立即分离节点,如下所示:

Node node = results.item(index)
node.getParentNode().removeChild(node)
nodes.add(node)

请参阅 XPath.评估性能在多次调用时性能降低(荒谬地)


推荐