2010-11-07 10 views
6

Tengo algunos problemas para entender el análisis de estructuras XML con SAX. Digamos que es el siguiente XML:SAX: Cómo obtener el contenido de un elemento

<root> 
    <element1>Value1</element1> 
    <element2>Value2</element2> 
</root> 

y una variable de cadena myString.

Simplemente haciendo los métodos startElement, endElement() y characters() es fácil. Pero no entiendo cómo puedo lograr lo siguiente:

Si el elemento actual es igual a element1 almacene su valor value1 en myString. Por lo que yo entiendo no hay nada como:

if (qName.equals("element1")) myString = qName.getValue(); 

Guess Sólo estoy pensando demasiado complicado :-)

Robert

Respuesta

6

Con SAX necesita mantener su propia pila. Se puede hacer algo como esto para el procesamiento muy básico:

void startElement(...) { 
    if (name.equals("element1")) { 
     inElement1 = true; 
     element1Content = new StringBuffer(); 
    } 
} 

void characters(...) { 
    if (inElement1) { 
     element1Content.append(characterData); 
    } 
} 

void endElement(...) { 
    if (name.equals("element2")) { 
     inElement1 = false; 
     processElement1Content(element1Content.toString()); 
    } 
} 

Si quieren código como en el ejemplo a continuación, es necesario utilizar el modelo DOM en lugar de SAX. DOM es más fácil de codificar, pero generalmente es más lento y más costoso que SAX.

Recomiendo usar una biblioteca de terceros en lugar de las bibliotecas XML de Java incorporadas para la manipulación de DOM. Dom4J parece bastante bueno, pero probablemente haya otras bibliotecas por ahí también.

+0

Gracias Cameron, que es lo que yo hubiera esperado :-) Como mi aplicación se ejecutará en un teléfono Android, creo que es mejor usar el incorporado en el analizador SAX en lugar de cambiar a DOM. –

+0

Quizás use el StringBuilder preferido –

6

Debe anotar el contenido a través de characters(), anexar a un StringBuilder para cada invocación y solo almacena el valor concatenado en la llamada endElement().

¿Por qué? Debido a que characters() se puede llamar varias veces para el contenido del elemento, cada llamada hace referencia a una subsecuencia sucesiva de ese elemento de texto.

9

Esta solución funciona para un único elemento con contenido de texto. Cuando element1 tiene más subelementos se necesita algo más de trabajo. La observación de Brian es muy importante. Cuando tiene varios elementos o quiere una solución más genérica, esto podría ayudarlo. Lo he comprobado con un archivo XML + 300 MB y sigue siendo muy rápido:

final StringBuilder builder=new StringBuilder(); 
XMLReader saxXmlReader = XMLReaderFactory.createXMLReader(); 

DefaultHandler handler = new DefaultHandler() { 
    boolean isParsing = false; 

    public void startElement(String uri, String localName, String qName, Attributes attributes) { 
     if ("element1".equals(localName)) { 
      isParsing = true; 
     } 
     if (isParsing) { 
      builder.append("<" + qName + ">"); 
     } 
    } 

    @Override 
    public void characters(char[] chars, int i, int i1) throws SAXException { 
     if (isParsing) { 
      builder.append(new String(chars, i, i1)); 
     } 
    } 

    @Override 
    public void endElement(String uri, String localName, String qName) throws SAXException { 
     if (isParsing) { 
      builder.append("</" + qName + ">"); 
     } 
     if ("element1".equals(localName)) { 
      isParsing = false; 
     } 
    } 
}; 

saxXmlReader.setContentHandler(handler); 
saxXmlReader.setErrorHandler(handler); 

saxXmlReader.parse(new InputSource(new FileInputStream(input))); 
Cuestiones relacionadas