Ускорение xpath

У меня есть документ с 1000 документами, формат которого похож на

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

Здесь имеется более 1000 узлов ввода. Я пишу программу Java, которая в основном получает все node по одному и анализирует каждый node. Но проблема в том, что время поиска узлов увеличивается с его no. Например, для получения второго node 100 мс для получения второго требуется 78 миллисекунд, и он продолжает увеличиваться. А для получения 999 node требуется больше 5 секунд. Это очень медленно. Мы будем подключать этот код к файлам XML, которые имеют даже более 1000 записей. Некоторые вроде миллионов. Общее время для анализа всего документа составляет более 5 минут.

Я использую этот простой код для его перемещения. Здесь nxp - мой собственный класс, который имеет все методы для получения узлов из xpath.

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

и doc - это документ для файла. i - это no из node для извлечения.

Также, когда я пытаюсь что-то вроде этого

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

Я сталкиваюсь с той же проблемой.

У любого есть решение о том, как ускорить tretirival узлов, поэтому требуется один и тот же промежуток времени, чтобы получить 1-й node, а также 1000 node из файла 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);  
    }  
}  

и вот код для из-квантонодов.

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

Ответ 3

У меня была аналогичная проблема с оценкой Xpath, я попытался использовать CachedXPathAPI, который быстрее на 100X, чем XPathApis, который использовался ранее. Дополнительная информация об этом Api предоставляется здесь: http://xml.apache.org/xalan-j/apidocs/org/apache/xpath/CachedXPathAPI.html

Надеюсь, это поможет. Ура, Madhusudhan

Ответ 4

Какой парсер вы используете?

DOM извлекает весь документ в памяти - как только вы вытаскиваете весь документ в памяти, ваши операции могут быть быстрыми, но это может произойти в веб-приложении или в цикле for.

САКС-парсер выполняет по запросу синтаксический анализ и загрузку узлов по мере запроса.

Поэтому попробуйте использовать реализацию парсера, которая вам подходит.

Ответ 5

Если вам нужно разбирать огромные, но плоские документы, 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 для выполнения грязной работы и использовать с обработчиками, зависящими от типа документа.