繁体   English   中英

加速 xpath

[英]Speeding up xpath

我有一个 1000 个条目的文档,其格式类似于:

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

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

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

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

doc是文件的文档。 i是要检索的节点编号。

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

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

我面临同样的问题。

任何人都有关于如何加速节点更新的任何解决方案,因此从 XML 文件中获取第一个节点和第 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>();  
}  

试试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++;
}

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

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

请参阅XPath.evaluate 多次调用性能下降(荒谬地)

我在 Xpath Evaluation 上遇到了类似的问题,我尝试使用 CachedXPathAPI,它比之前使用的 XPathApi 快 100 倍。 此处提供了有关此 Api 的更多信息: http : //xml.apache.org/xalan-j/apidocs/org/apache/xpath/CachedXPathAPI.html

希望能帮助到你。 干杯,马杜苏丹

如果您需要解析庞大而扁平的文档,SAX 是一个不错的选择。 它允许您将 XML 作为流处理,而不是构建一个巨大的 DOM。 可以使用 ContentHandler 解析您的示例,如下所示:

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;

public class ExampleHandler extends DefaultHandler2 {

    private StringBuffer chars = new StringBuffer(1000);

    private MyEntry currentEntry;
    private MyEntryHandler myEntryHandler;

    ExampleHandler(MyEntryHandler myEntryHandler) {
        this.myEntryHandler = myEntryHandler;
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        chars.append(ch);
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        if ("Entry".equals(localName)) {
            myEntryHandler.handle(currentEntry);
            currentEntry = null;
        }
        else if ("n1".equals(localName)) {
            currentEntry.setN1(chars.toString());
        }
        else if ("n2".equals(localName)) {
            currentEntry.setN2(chars.toString());
        }
    }


    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        chars.setLength(0);
        if ("Entry".equals(localName)) {
            currentEntry = new MyEntry();
        }
    }
}

如果文档具有更深、更复杂的结构,您将需要使用堆栈来跟踪文档中的当前路径。 然后,您应该考虑编写一个通用的 ContentHandler 来完成繁琐的工作并与您的文档类型相关处理程序一起使用。

您使用的是哪种解析器?

DOM 将整个文档拉入内存 - 一旦您将整个文档拉入内存,您的操作就会很快,但在 Web 应用程序或 for 循环中这样做可能会产生影响。

SAX 解析器按需解析并在您请求时加载节点。

因此,请尝试使用适合您需要的解析器实现。

JAXEN库用于 xpath: http ://jaxen.codehaus.org/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM