2010-03-02 13 views
17

tengo un documento de 1000 de entrada cuyo formato es algo así comoLa aceleración de XPath

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

Hay más de 1000 nodos de entrada aquí. Estoy escribiendo un programa Java que básicamente obtiene todos los nodos uno por uno y analiza algunos en cada nodo. Pero el problema es que el tiempo de recuperación de los nodos aumenta con su no. Por ejemplo, toma 78 milisegundos para recuperar el primer nodo 100 ms para recuperar el segundo y sigue aumentando. Y para recuperar el nodo 999 lleva más de 5 segundos. Esto es extremadamente lento Estaríamos conectando este código a archivos XML que tienen incluso más de 1000 entradas. Algunos como millones. El tiempo total para analizar el documento completo es de más de 5 minutos.

Estoy usando este código simple para recorrerlo. Aquí nxp es mi propia clase que tiene todos los métodos para obtener nodos de xpath.

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

y doc es el documento para el archivo. i es el no de nodo para recuperar.

también cuando intento algo como esto

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

que se enfrentan al mismo problema.

Cualquiera tiene alguna solución sobre cómo acelerar el tretirival de los nodos, por lo que toma el mismo tiempo para obtener el primer nodo y el nodo 1000 del archivo XML.

Gracias


Este es el código para 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); 
    } 
} 

y aquí está el código de 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; 
} 

y aquí está la puesta en

NativeXpathEngine clase pública implementa XpathEngine
{
fábrica XPathFactory final privado;

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

El código en '' fromXpathToNode' y fromXpathToNodes 'parece ser bastante relevante aquí. ¿Puedes proporcionar ese código? –

+0

necesita ver su código que carga el documento. –

+2

Si va a tocar cada entrada, ¿por qué usar XPath? –

Respuesta

1

¿Qué tipo de analizador está utilizando?

DOM extrae todo el documento en la memoria: una vez que extrae todo el documento en la memoria, sus operaciones pueden ser rápidas, pero hacerlo en una aplicación web o en un bucle for puede tener un impacto.

El analizador SAX realiza el análisis bajo demanda y carga los nodos cuando lo solicite.

Intente utilizar una implementación de analizador que se adapte a sus necesidades.

+0

Si planea usar esto en un documento con millones de entradas, SAX es probablemente la mejor manera de hacerlo. EN MI HUMILDE OPINIÓN. –

+0

estoy usando un analizador dom. – jon

+0

, pero ¿por qué es tan lento? Debería ser rápido para todas las etiquetas de entrada – jon

1

Si necesita analizar documentos enormes pero planas, SAX es una buena alternativa. Le permite manejar el XML como una secuencia en lugar de construir un DOM enorme.Su ejemplo se ha podido analizar el uso de un ContentHandler así:

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

Si el documento tiene una estructura más profunda y más compleja, que va a tener que utilizar pilas para realizar un seguimiento de la ruta actual en el documento. Entonces debería considerar escribir un ContentHandler de propósito general para hacer el trabajo sucio y usarlo con sus manejadores dependientes del tipo de documento.

+1

Usar VTD-XML, es * la * solución :) –

10

Probar VTD-XML. Utiliza menos memoria que DOM. Es más fácil de usar que SAX y es compatible con XPath. Aquí hay un código de muestra para ayudarlo a comenzar. Aplica una XPath para obtener los elementos de entrada y luego imprime los elementos secundarios n1 y 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 por mencionar esta impresionante lib. Me enfrenté a un problema similar al analizar algunos xPathExpressions que tardaron cerca de 1 minuto en completarse. VTD-XML hace el mismo trabajo en 2seks. – onigunn

+0

La biblioteca mencionada es realmente sorprendente. Dependiendo del caso de uso, uno tiene que verificar si el envío de un código usando esta biblioteca GPL conlleva dependencias legales, ya que se basa en las patentes estadounidenses 7133857, 7260652 y 7761459. – Moreaki

Cuestiones relacionadas