Ускорение XPath
У меня есть 1000 документов, чей формат что-то вроде
<Example>
<Entry>
<n1></n1>
<n2></n2>
</Entry>
<Entry>
<n1></n1>
<n2></n2>
</Entry>
<!--and so on-->
Здесь более 1000 узлов входа. Я пишу Java-программу, которая в основном получает все узлы один за другим и проводит анализ каждого узла. Но проблема в том, что время поиска узлов увеличивается с его нет. Например, для извлечения первого узла требуется 78 миллисекунд, а для извлечения второго - 100 мс, и он продолжает увеличиваться. И для получения узла 999 требуется более 5 секунд. Это очень медленно. Мы будем подключать этот код к XML-файлам, которые имеют даже более 1000 записей. Некоторым нравятся миллионы. Общее время разбора всего документа составляет более 5 минут.
Я использую этот простой код, чтобы пройти его. Вот nxp
мой собственный класс, который имеет все методы для получения узлов из xpath.
nxp.fromXpathToNode("/Example/Entry" + "[" + i + "]", doc);
а также doc
это документ для файла. i
это номер узла для извлечения.
Также, когда я пытаюсь что-то вроде этого
List<Node> nl = nxp.fromXpathToNodes("/Example/Entry",doc);
content = nl.get(i);
Я сталкиваюсь с той же проблемой.
У любого есть какое-либо решение о том, как ускорить третичное сравнение узлов, поэтому для получения 1-го узла, а также 1000-го узла из файла XML требуется одинаковое количество времени.
Спасибо
Вот код для 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);
}
}
и вот код для xpathtonodes.
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>();
}
6 ответов
Попробуйте 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, я пытался использовать CachedXPathAPI, который в 100 раз быстрее, чем XPathApi, который использовался ранее. дополнительная информация об этом 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 извлекает весь документ из памяти - как только вы извлекаете весь документ из памяти, ваши операции могут быть быстрыми, но это может оказать влияние на веб-приложение или цикл for.
SAX-парсер выполняет синтаксический анализ по требованию и загружает узлы по мере необходимости.
Поэтому попробуйте использовать реализацию парсера, которая соответствует вашим потребностям.
Используйте библиотеку JAXEN для xpaths: http://jaxen.codehaus.org/