2011-06-24 12 views
5

Estoy usando javax.xml.xpath para buscar cadenas específicas en archivos xml, sin embargo, debido a la gran cantidad de archivos xml que deben buscarse, esto resulta ser mucho más lento de lo esperado.¿Api más rápido que javax.xml.xpath para analizar el xml de un valor?

¿Hay alguna API compatible con java que sea más rápida que javax.xml.xpath o que es la más rápida que está disponible?

+1

Quizás solo esté utilizando la API de forma inapropiada. Una nueva API no es una bala mágica. Muéstranos tu código, tal vez podamos sugerir mejoras. – skaffman

+0

Me pueden abuchear aquí, pero ¿ha intentado usar expresiones regulares? Regexes no funcionará para todos los tipos de archivos xml, pero si la estructura es bastante básica y está seguro de que las expresiones regulares no causarán problemas, podría acelerar el proceso. – Augusto

+0

@skaffman, lo siento, no puedo compartir el código debido a las políticas de la compañía – Nohsib

Respuesta

9

Como ha señalado skaffman usted quiere estar seguro de que está utilizando las bibliotecas javax.xml.xpath tan eficientemente como sea posible. Si está ejecutando una declaración XPath más de una vez, querrá asegurarse de compilarla en un XPathExpression.

XPathExpression xPathExpression = xPath.compile("/root/device/modelname"); 
nl = (NodeList) xPathExpression.evaluate(dDoc, XPathConstants.NODESET); 

demostración

En la opción de ejemplo # 2 será más rápida que la opción 1 #.

import java.io.File; 

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.xpath.XPath; 
import javax.xml.xpath.XPathConstants; 
import javax.xml.xpath.XPathExpression; 
import javax.xml.xpath.XPathFactory; 

import org.w3c.dom.Document; 
import org.w3c.dom.NodeList; 

public class Demo { 

    public static void main(String[] args) { 
     DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); 
     try { 
      DocumentBuilder builder = domFactory.newDocumentBuilder(); 
      File xml = new File("input.xml"); 
      Document dDoc = builder.parse(xml); 

      NodeList nl; 

      // OPTION #1 
      XPath xPath = XPathFactory.newInstance().newXPath(); 
      nl = (NodeList) xPath.evaluate("root/device/modelname", dDoc, XPathConstants.NODESET); 
      printResults(nl); 
      nl = (NodeList) xPath.evaluate("/root/device/modelname", dDoc, XPathConstants.NODESET); 
      printResults(nl); 

      // OPTION #2 
      XPathExpression xPathExpression = xPath.compile("/root/device/modelname"); 
      nl = (NodeList) xPathExpression.evaluate(dDoc, XPathConstants.NODESET); 
      printResults(nl); 
      nl = (NodeList) xPathExpression.evaluate(dDoc, XPathConstants.NODESET); 
      printResults(nl); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    private static void printResults(NodeList nl) { 
     for(int x=0; x<nl.getLength(); x++) { 
      System.out.println("the value is: " + nl.item(x).getTextContent()); 
     } 
    } 

} 

input.xml

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <blah>foo</blah> 
    <device> 
    <modelname>xbox</modelname> 
    </device> 
    <blah>bar</blah> 
    <device> 
    <modelname>wii</modelname> 
    </device> 
    <blah/> 
</root> 
1

Puedes mirar mi anterior answer para algo relacionado.

Básicamente utilicé JXpath y Xerces, así como Dom4J y javax. Puedo decir con confianza por mi experiencia que VTD-XML es la más rápida de estas opciones.

Hay muchas otras preguntas sobre el uso de VTD-XML en SO si desea buscar.

EDIT:
bien, así que basado en su comentario el fragmento de código sería algo como esto:

VTDGen vg = new VTDGen(); 
AutoPilot ap = new AutoPilot(); 
int i; 
ap.selectXPath("/root/device/modelname"); 
if (vg.parseFile(PATH_TO_FILE,true)){ 
    VTDNav vn = vg.getNav(); 
    ap.bind(vn); // apply XPath to the VTDNav instance 
    // AutoPilot moves the cursor for you 
    while((i=ap.evalXPath())!=-1){ 
     System.out.println("the value is: " + vn.toNormalizedString(vn.getText())); 
    } 
} 

Para el siguiente código XML:

<root> 
    <blah>foo</blah> 
    <device> 
    <modelname>xbox</modelname> 
    </device> 
    <blah>bar</blah> 
    <device> 
    <modelname>wii</modelname> 
    </device> 
    <blah/> 
</root> 

la salida será:

the value is: xbox 
the value is: wii 

Puede tomarlo desde aquí ...

+1

. Buscaré en su solución, gracias. – Nohsib

+1

@ Asaf: si tengo cadena s = " ... ..... xbox .... ..." cómo usar el VTD-XML para obtener el valor en el nodo modelname, puede amablemente compartes el fragmento de código. – Nohsib

+1

@Nohsib, editó la respuesta con el fragmento de código. debería ser lo suficientemente claro – Asaf

4

Me pregunto si la búsqueda de XPath es realmente su cuello de botella, o si es en realidad el análisis de XML? Sospecharía esto último. No sé qué tan persistentes son sus documentos XML, pero creo que la solución es almacenarlos en una base de datos XML para que solo incurra en el costo de análisis una vez, y para que puedan ser indexados para hacer que la búsqueda de XPath/XQuery sea más eficiente. .

0

Debe detallar qué tipo de cosas está buscando, si se trata de cadenas de contenido simple, consideraría usar Stax API (javax.xml.stream.XMLStreamReader), por ejemplo. XPath es bueno si necesita restringir su búsqueda de subconjuntos específicos.

Un problema con XPath es que dependiendo de la expresión puede terminar construyendo un árbol DOM en memoria, y esto es bastante costoso (relativo al análisis XML), tanto en términos de velocidad como de uso de memoria. Entonces, si esto se puede evitar, eso solo puede acelerar el procesamiento por fábrica de 3x.

Cuestiones relacionadas