Ускорение xpath

у меня есть 1 000 документов записи, формат которых - что-то как

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

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

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

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

и doc документ для файла. i не узел для получения.

Также, когда я пробую что-то вроде этого

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

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

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

и вот код для 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>();  
}  
18
задан Vincent Robert 10 August 2010 в 12:30
поделиться

4 ответа

Используйте библиотеку JAXEN для xpaths: http://jaxen.codehaus.org/

0
ответ дан 30 November 2019 в 08:52
поделиться

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

2
ответ дан 30 November 2019 в 08:52
поделиться

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

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

Парсер SAX выполняет парсинг по требованию и загружает узлы по мере поступления запроса.

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

1
ответ дан 30 November 2019 в 08:52
поделиться

Попробуйте 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++;
}
10
ответ дан 30 November 2019 в 08:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: