2010-03-02 27 views
17

Mam dokument 1000 wejścia, którego format jest cośPrzyspieszenie XPath

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

Istnieje ponad 1000 węzłów kwalifikacyjne tutaj. Piszę program w języku Java, który pobiera po kolei wszystkie węzły i analizuje je w każdym węźle. Problem polega jednak na tym, że czas pobierania węzłów rośnie wraz z jego nie. Na przykład potrzeba 78 milisekund, aby pobrać pierwszy węzeł 100 ms, aby pobrać drugi i stale rośnie. A odzyskanie węzła 999 zajmuje więcej niż 5 sekund. To jest bardzo powolne. Będziemy podłączać ten kod do plików XML, które mają nawet ponad 1000 wpisów. Niektórzy lubią miliony. Łączny czas przeanalizowania całego dokumentu wynosi więcej niż 5 minut.

Używam tego prostego kodu do przechodzenia przez niego. Tutaj nxp jest moją własną klasą, która ma wszystkie metody pobierania węzłów z xpath.

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

i doc jest dokumentem dla pliku. i to nr węzła do pobrania.

Również gdy próbuję coś takiego

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

I twarz ten sam problem.

Każdy ma jakieś rozwiązanie, aby przyspieszyć tretirival węzłów, więc zajmuje tyle samo czasu, aby uzyskać pierwszy węzeł, a także 1000 węzeł z pliku XML.

Dziękuję


oto kod dla 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); 
    } 
} 

i tutaj jest kod dla odxpathtonodes.

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

i oto począwszy

public class NativeXpathEngine realizuje XpathEngine
{
prywatny końcowy fabryczny 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

kodu w 'fromXpathToNode' i' fromXpathToNodes "wydaje się tutaj bardzo istotne. Czy możesz podać ten kod? –

+0

trzeba zobaczyć kod, który ładuje dokument. –

+2

Jeśli chcesz trafić w każdy wpis, po co używać XPath? –

Odpowiedz

1

Jakiego rodzaju analizatora składni używasz?

DOM pobiera cały dokument w pamięci - po przeciągnięciu całego dokumentu do pamięci operacja może być szybka, ale działanie w aplikacji internetowej lub pętli for może mieć wpływ.

Analizator składni SAX wykonuje parsowanie na żądanie i ładuje węzły zgodnie z żądaniem.

Spróbuj użyć implementacji parsera, która odpowiada Twoim potrzebom.

+0

Jeśli planuje użyć tego w dokumencie zawierającym miliony wpisów, SAX jest prawdopodobnie lepszym rozwiązaniem. MOIM ZDANIEM. –

+0

używam parser DOM. – jon

+0

, ale dlaczego jest tak powolny. Powinno być szybkie dla wszystkich znaczników wprowadzania – jon

1

Jeśli trzeba analizować ogromne ale płaskie dokumentów, SAX jest dobrą alternatywą. Pozwala on obsługiwać XML jako strumień zamiast budować ogromny DOM.Twój przykład może być analizowany przy użyciu ContentHandler tak:

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(); 
     } 
    } 
} 

Jeśli dokument ma głębszy i bardziej złożoną strukturę, będziesz musiał użyć Stosy śledzić bieżącej ścieżki w dokumencie. Następnie powinieneś rozważyć napisanie ContentHandler ogólnego przeznaczenia do brudnej pracy i używania z twoim handlem zależnym od dokumentu.

+1

Użyj VTD-XML, to jest * the * solution :) –

10

Wypróbuj VTD-XML. Wykorzystuje mniej pamięci niż DOM. Jest łatwiejszy w użyciu niż SAX i obsługuje XPath. Oto przykładowy kod, który pomoże Ci zacząć. Stosuje XPath, aby uzyskać elementy Entry, a następnie wypisuje elementy potomne n1 i 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++; 
} 
+2

+1 za wzmiankę o tej niesamowitej lib. Stawiłem czoła podobnemu problemowi, analizując niektóre parametry XPathExpressions, które trwały blisko 1 minuty. VTD-XML wykonuje to samo zadanie w 2seksach. – onigunn

+0

Wspomniana biblioteka jest naprawdę niesamowita. W zależności od użycia należy sprawdzić, czy wysyłka kodu przy użyciu tej biblioteki GPL niesie ze sobą prawne zależności, ponieważ opiera się na patentach USA 7133857, 7260652 i 7761459. – Moreaki