2010-11-07 7 views
6

J'ai de la difficulté à comprendre l'analyse des structures XML avec SAX. Disons qu'il est le code XML suivant:SAX: Comment obtenir le contenu d'un élément

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

et une chaîne de variable myString. Juste en passant par les méthodes startElement, endElement() et characters() est facile. Mais je ne comprends pas comment je peux réaliser ce qui suit:

Si l'élément courant est égal à element1 stocker sa valeur value1 dans . Pour autant que je comprends, il n'y a rien comme:

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

pense que je suis en train de penser trop compliqué :-)

Robert

Répondre

6

Avec SAX vous devez maintenir votre propre pile. Vous pouvez faire quelque chose comme ça pour le traitement très basique:

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 vous voulez code comme dans votre exemple, vous devez utiliser le modèle DOM plutôt que SAX. DOM est plus facile à coder, mais il est généralement plus lent et plus coûteux en mémoire que SAX.

Je recommande d'utiliser une bibliothèque tierce plutôt que les bibliothèques Java XML intégrées pour la manipulation DOM. Dom4J semble plutôt bien mais il y a probablement d'autres bibliothèques aussi.

+0

Merci Cameron, qui est ce que je l'ai prévu :-) Comme mon application fonctionnera sur un smartphone Android Je pense que mieux via le haut- dans l'analyseur syntaxique SAX plutôt que de passer à DOM. –

+0

Peut-être utiliser le StringBuilder préféré –

6

Vous devez enregistrer le contenu via characters(), ajoutez à un StringBuilder pour chaque appel et stocker uniquement la valeur concaténée lors de l'appel endElement().

Pourquoi? Parce que characters() peut être appelé plusieurs fois pour le contenu de l'élément - chaque appel référençant une sous-séquence successive de cet élément de texte.

9

Cette solution fonctionne pour un seul élément avec du contenu textuel. Quand element1 a plus de sous-éléments, un travail supplémentaire est nécessaire. La remarque de Brian est très importante. Lorsque vous avez plusieurs éléments ou que vous voulez une solution plus générique, cela peut vous aider. Je l'ai testé avec un fichier xml 300 + Mo et il est toujours très rapide:

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))); 
Questions connexes