Livello di difficoltà: facileVersione SDK utilizzata: 1.6Link al file compresso del progetto eclipse: file in allegatoQuesto Thread è una versione rivista per anddev.it in del tutorial originale in inglese sviluppato da plusminus.
Riferimento a piè pagina e all'interno della documentazione.
Ecco una breve schermata del risultato, per dimostrare i valori ricavati dal seguente XML:
<?xml version="1.0" encoding="utf-8"?>
<stuff>
<junk site="http://mazin.altervista.org">
<test lang="it">Ciau belli!</test>
<aforisma>XML è meglio</aforisma>
<tab></tab>
</junk>
</stuff>per l'occasione ospitato sul mio (ridicolo) spazio web all'url:
http://mazin.altervista.org/sample.xmlQuesto è un dettaglio importante, perché, come vedremo, l'XML da analizzare nel tutorial è ricavato da un URL... ma nulla vieta di passarlo anche come file (ma questo è un eventuale approfondimento).
Come si vede dal primo allegato, i campi degli attributi e i valori degli ultimi due tag vengono estratti e passati in una TextView (un po' scarna, ma accontentiamoci).
Nel secondo allegato, invece, è disponibile il project di eclipse, sprovvisto del mio classpath (sarebbe stato inutile visto che ognuno ha il suo), quindi quando lo importate, ricordate di reimpostare le path correttamente. All'interno è presente, nella root, anche l'XML che ho usato.
Sommariamente i concetti chiave sono 3, cioè le rispettive classi (contenute in Parser.java):
- Parser - prende l'XML, e chiama tutti i metodi.
- Handler - logica di controllo dei nodi.
- SingleData - valori passati e salvati.
Mi concentrerò sugli ultimi due per cercare di spiegare al meglio come funziona il codice, mentre il Parser credo sia sufficientemente commentato all'interno del codice.
In sintesi, tramite la classe SAXparser, scorriamo l'intero XML dall'inizio alla fine e, quando troviamo un tag aperto, come ad esempio:
<test>riferendoci all'xml visto in precedenza, viene chiamato il metodo startElement:
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
...
...
if (localName.equals("test")) {
this.in_test = true;Dove, con localName, viene passata la stringa all'interno del tag, in questo caso "junk", e in atts i relativi attributi in caso ci siano (ed è questo il caso, con il tag "site").
Uguale discorso si può fare per il metodo di chiusura endElement:
</test>public void endElement(String namespaceURI, String localName, String qName)
...
...
if (localName.equals("test")) {
this.in_test = false;La variabile booleana, serve per il metodo character che viene richiamato se all'interno del tag, si trovano dei caratteri. Compito di gestirli è quindi di startElement ed endElement. Che chiamerà un metodo apposta per salvare da qualche parte (consiglio delle liste) i parametri interessati.
public void characters(char ch[], int start, int length) {
if(this.in_test){
xmlparsing.setExtractedString_01(new String(ch, start, length));Infine, come è stato segnalato, non dimenticate di inserire il permesso per l'accesso ad Internet all'applicazione. Questa riga di codice è da inserire nel file AndroidManifest.xml del vostro progetto.
<uses-permission android:name="android.permission.INTERNET" />Sorgenti:package it.anddev;
import java.net.URL;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
/**
* Classe che fornisce un esempio di parsing xml per il forum anddev.it,
* basato sul tutorial di plusminus
* http://www.anddev.org/parsing_xml_from_the_net_-_using_the_saxparser-t353.html
*
* @author Mazinkaiser
*/
public class Parser extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = new TextView(this);
try {
/* URL passato con l'XML da interrogare*/
URL url = new URL("http://mazin.altervista.org/sample.xml");
/* Creiamo un SAXParser dalla classe SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Prendiamo un formato XMLReader dal SAXParser creato */
XMLReader xr = sp.getXMLReader();
/* Creiamo un nuovo Handler e passiamoci l'XMLReader*/
Handler handler = new Handler();
xr.setContentHandler(handler);
/* parsing dei xml aprendo lo stream dell'URL. */
xr.parse(new InputSource(url.openStream()));
/* Interroghiamo i dati ricavati per estrarne i singoli valori */
SingleData parsedData = handler.getParsedData();
/* passiamo il risultato alla TextView per visualizzarli. */
tv.setText(parsedData.toString());
} catch (Exception e) {
/* In caso di errore, passiamo l'errore alla TextView. */
tv.setText("House abbiamo un problema: \n" + e.getMessage());
Log.e("Error", e.toString());
}
/* Montiamo il contenuto della TextView all'interno della View dell'Activity. */
this.setContentView(tv);
}
/**
* Inner class che gestisce i nodi e salva i parametri
*
* @author Mazinkaiser
*
*/
public class Handler extends DefaultHandler{
// ===========================================================
// Fields
// ===========================================================
private boolean in_stuff = false;
private boolean in_junk = false;
private boolean in_test = false;
private boolean in_aforisma = false;
private boolean in_tab = false;
private SingleData xmlparsing = new SingleData();
// ===========================================================
// Getter & Setter
// ===========================================================
public SingleData getParsedData() {
return this.xmlparsing;
}
// ===========================================================
// Metodi
// ===========================================================
@Override
public void startDocument() throws SAXException {
this.xmlparsing = new SingleData();
}
@Override
public void endDocument() throws SAXException {
/* Niente di utile da inserire */
}
/* startElement viene richiamata quando c'è un nuovo tag xml
* recuperandone i singoli parametri */
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
if (localName.equals("stuff")) {
this.in_stuff = true;
}else if (localName.equals("junk")) {
this.in_junk = true;
String attrValue = atts.getValue("site");
xmlparsing.setExtractedStringAttr_01(attrValue);
}else if (localName.equals("test")) {
this.in_test = true;
// Estrazione dell'attributo
String attrValue = atts.getValue("lang");
xmlparsing.setExtractedStringAttr_02(attrValue);
}else if (localName.equals("aforisma")) {
this.in_aforisma = true;
}else if (localName.equals("tab")) {
this.in_tab = true;
}
}
/* endElement viene richiamata quando c'è la chiusura di un tag xml */
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("stuff")) {
this.in_stuff = false;
}else if (localName.equals("junk")) {
this.in_junk = false;
}else if (localName.equals("test")) {
this.in_test = false;
}else if (localName.equals("aforisma")) {
this.in_aforisma = false;
}else if (localName.equals("tab")) {
this.in_tab = false;
}
}
/* characters prende i caratteri presenti all'interno di un tag*/
@Override
public void characters(char ch[], int start, int length) {
if(this.in_test){
xmlparsing.setExtractedString_01(new String(ch, start, length));
}else if (this.in_aforisma) {
xmlparsing.setExtractedString_02(new String(ch, start, length));
}
}
}
/**
* Inner class che salva i parametri usando setter & getter dedicate per ogni nodo.
*
* @author Mazinkaiser
*
*/
public class SingleData {
private String extractedItem_01 = null;
private String extractedItem_02 = null;
private String extractedItemAttr_01 = null;
private String extractedItemAttr_02 = null;
public String getExtractedString_01() {
return extractedItem_01;
}
public void setExtractedString_01(String extractedString) {
this.extractedItem_01 = extractedString;
}
public String getExtractedString_02() {
return extractedItem_02;
}
public void setExtractedString_02(String extractedString) {
this.extractedItem_02 = extractedString;
}
public String getExtractedStringAttr_01() {
return extractedItemAttr_01;
}
public void setExtractedStringAttr_01(String extractedString) {
this.extractedItemAttr_01 = extractedString;
}
public String getExtractedStringAttr_02() {
return extractedItemAttr_02;
}
public void setExtractedStringAttr_02(String extractedString) {
this.extractedItemAttr_02 = extractedString;
}
public String toString(){
return "Stringhe estratte:\n\n" +
this.extractedItemAttr_01+ "\n"+
this.extractedItemAttr_02+ "\n"+
this.extractedItem_01+ "\n"+
this.extractedItem_02+ "\n";
}
}
}Bibliografia:
Spannometricamente, questo è quanto. Forse non è la soluzione migliore, ma io l'ho trovata molto pratica, tantè che per una mia applicazione (tanto per dire) gestivo tramite questi metodi, l'XML disponibile al seguente url (ora recupero i dati da server, cosa un po' diversa):
http://mazin.altervista.org/Configurazione_1.xmlSpero si capisca e torni utile, ovviamente discutiamone

che conviene a tutti... approposito, non c'è stato verso di usare attributi che contenesserò "xml" come stringa, quelli non riuscivo a passarli, e anche dopo 1 giornata non ne sono venuto a capo -.-