我有一个1000条目文档,其格式类似于
<Example>
<Entry>
<n1></n1>
<n2></n2>
</Entry>
<Entry>
<n1></n1>
<n2></n2>
</Entry>
<!--and so on-->
这里有超过1000个Entry节点。我正在编写一个Java程序,它基本上逐个获取所有节点并对每个节点进行一些分析。但问题是节点的检索时间随着它的增加而增加。例如,检索第一个节点100毫秒以检索第二个节点需要78毫秒,并且它继续增加。要检索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;
}
这是开始
公共类NativeXpathEngine实现XpathEngine
{
私有的最终XPathFactory工厂;
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>();
}
答案 0 :(得分:10)
试试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++;
}
答案 1 :(得分:5)
正确的解决方案是在调用item(i)之后立即分离节点,如下所示:
Node node = results.item(index)
node.getParentNode().removeChild(node)
nodes.add(node)
请参阅XPath.evaluate performance slows down (absurdly) over multiple calls
答案 2 :(得分:3)
我在Xpath评估中遇到了类似的问题,我尝试使用CachedXPathAPI,它比之前使用的XPathApi快100倍。 这里提供了有关此Api的更多信息: http://xml.apache.org/xalan-j/apidocs/org/apache/xpath/CachedXPathAPI.html
希望它有所帮助。 干杯, Madhusudhan
答案 3 :(得分:2)
如果您需要解析大而扁平的文档,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();
}
}
}
如果文档具有更深入和更复杂的结构,则您将需要使用Stacks来跟踪文档中的当前路径。然后你应该考虑编写一个通用的ContentHandler来做脏工作并与你的文档类型相关的处理程序一起使用。
答案 4 :(得分:1)
你使用什么样的解析器?
DOM将整个文档拉入内存 - 一旦将整个文档拉入内存中,您的操作就会很快,但在Web应用程序或for循环中这样做会产生影响。
SAX解析器按需解析并在您请求时加载节点。
因此,请尝试使用适合您需要的解析器实现。
答案 5 :(得分:0)
将 JAXEN 库用于xpath: http://jaxen.codehaus.org/