Cómo analizar XML utilizando el analizador SAX

Estoy siguiendo este tutorial .

Funciona muy bien, pero me gustaría que devuelva una matriz con todas las cadenas en lugar de una sola cadena con el último elemento.

¿Alguna idea de como hacer esto?

Por lo tanto, desea crear un analizador XML para analizar un feed RSS como éste.

<rss version="0.92"> <channel> <title>MyTitle</title> <link>http://myurl.com</link> <description>MyDescription</description> <lastBuildDate>SomeDate</lastBuildDate> <docs>http://someurl.com</docs> <language>SomeLanguage</language> <item> <title>TitleOne</title> <description><![CDATA[Some text.]]></description> <link>http://linktoarticle.com</link> </item> <item> <title>TitleTwo</title> <description><![CDATA[Some other text.]]></description> <link>http://linktoanotherarticle.com</link> </item> </channel> </rss> 

Ahora tiene dos implementaciones SAX con las que puede trabajar. Puede utilizar la org.xml.sax o android.sax . Voy a explicar los pro y los contras de ambos después de publicar un ejemplo corto hander.

Implementación de android.sax

Comencemos con la implementación de android.sax .

Primero hay que definir la estructura XML utilizando los objetos RootElement y Element .

En cualquier caso, yo trabajaría con POJOs (Plain Old Java Objects) que mantendría sus datos. Aquí estarían los POJOs necesarios.

Channel.java

 public class Channel implements Serializable { private Items items; private String title; private String link; private String description; private String lastBuildDate; private String docs; private String language; public Channel() { setItems(null); setTitle(null); // set every field to null in the constructor } public void setItems(Items items) { this.items = items; } public Items getItems() { return items; } public void setTitle(String title) { this.title = title; } public String getTitle() { return title; } // rest of the class looks similar so just setters and getters } 

Esta clase implementa la interfaz Serializable para que puedas ponerla en un Bundle y hacer algo con ella.

Ahora necesitamos una clase para sostener nuestros artículos. En este caso sólo voy a extender la clase ArrayList .

Items.java

 public class Items extends ArrayList<Item> { public Items() { super(); } } 

Eso es para nuestro contenedor de artículos. Ahora necesitamos una clase para almacenar los datos de cada elemento.

Item.java

 public class Item implements Serializable { private String title; private String description; private String link; public Item() { setTitle(null); setDescription(null); setLink(null); } public void setTitle(String title) { this.title = title; } public String getTitle() { return title; } // same as above. } 

Ejemplo:

 public class Example extends DefaultHandler { private Channel channel; private Items items; private Item item; public Example() { items = new Items(); } public Channel parse(InputStream is) { RootElement root = new RootElement("rss"); Element chanElement = root.getChild("channel"); Element chanTitle = chanElement.getChild("title"); Element chanLink = chanElement.getChild("link"); Element chanDescription = chanElement.getChild("description"); Element chanLastBuildDate = chanElement.getChild("lastBuildDate"); Element chanDocs = chanElement.getChild("docs"); Element chanLanguage = chanElement.getChild("language"); Element chanItem = chanElement.getChild("item"); Element itemTitle = chanItem.getChild("title"); Element itemDescription = chanItem.getChild("description"); Element itemLink = chanItem.getChild("link"); chanElement.setStartElementListener(new StartElementListener() { public void start(Attributes attributes) { channel = new Channel(); } }); // Listen for the end of a text element and set the text as our // channel's title. chanTitle.setEndTextElementListener(new EndTextElementListener() { public void end(String body) { channel.setTitle(body); } }); // Same thing happens for the other elements of channel ex. // On every <item> tag occurrence we create a new Item object. chanItem.setStartElementListener(new StartElementListener() { public void start(Attributes attributes) { item = new Item(); } }); // On every </item> tag occurrence we add the current Item object // to the Items container. chanItem.setEndElementListener(new EndElementListener() { public void end() { items.add(item); } }); itemTitle.setEndTextElementListener(new EndTextElementListener() { public void end(String body) { item.setTitle(body); } }); // and so on // here we actually parse the InputStream and return the resulting // Channel object. try { Xml.parse(is, Xml.Encoding.UTF_8, root.getContentHandler()); return channel; } catch (SAXException e) { // handle the exception } catch (IOException e) { // handle the exception } return null; } } 

Ahora que fue un ejemplo muy rápido como se puede ver. La principal ventaja de usar la implementación de SAX de android.sax es que puedes definir la estructura del XML que tienes que analizar y luego simplemente agregar un detector de eventos a los elementos apropiados. La desventaja es que el código se repite bastante y hinchado.

Org.xml.sax Implementación

La implementación del manejador SAX org.xml.sax es un poco diferente.

Aquí no se especifica ni se declara la estructura XML, sino que solo se escuchan los eventos. Los más ampliamente utilizados son los siguientes:

  • Inicio del documento
  • Fin del documento
  • Elemento de inicio
  • Element End
  • Caracteres entre el inicio del elemento y el final del elemento

Un ejemplo de implementación del manejador que utiliza el objeto Canal anterior se ve así.

Ejemplo

 public class ExampleHandler extends DefaultHandler { private Channel channel; private Items items; private Item item; private boolean inItem = false; private StringBuilder content; public ExampleHandler() { items = new Items(); content = new StringBuilder(); } public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { content = new StringBuilder(); if(localName.equalsIgnoreCase("channel")) { channel = new Channel(); } else if(localName.equalsIgnoreCase("item")) { inItem = true; item = new Item(); } } public void endElement(String uri, String localName, String qName) throws SAXException { if(localName.equalsIgnoreCase("title")) { if(inItem) { item.setTitle(content.toString()); } else { channel.setTitle(content.toString()); } } else if(localName.equalsIgnoreCase("link")) { if(inItem) { item.setLink(content.toString()); } else { channel.setLink(content.toString()); } } else if(localName.equalsIgnoreCase("description")) { if(inItem) { item.setDescription(content.toString()); } else { channel.setDescription(content.toString()); } } else if(localName.equalsIgnoreCase("lastBuildDate")) { channel.setLastBuildDate(content.toString()); } else if(localName.equalsIgnoreCase("docs")) { channel.setDocs(content.toString()); } else if(localName.equalsIgnoreCase("language")) { channel.setLanguage(content.toString()); } else if(localName.equalsIgnoreCase("item")) { inItem = false; items.add(item); } else if(localName.equalsIgnoreCase("channel")) { channel.setItems(items); } } public void characters(char[] ch, int start, int length) throws SAXException { content.append(ch, start, length); } public void endDocument() throws SAXException { // you can do something here for example send // the Channel object somewhere or whatever. } } 

Ahora, para ser honesto, no puedo decirle realmente ninguna ventaja real de esta implementación de manejador sobre el android.sax uno. Sin embargo, puedo decirle la desventaja que debería ser bastante obvio por ahora. Eche un vistazo a la instrucción else if en el método startElement . Debido al hecho de que tenemos las etiquetas <title> , link y description que tenemos que rastrear allí en la estructura XML que estamos en el momento. Es decir, si nos encontramos con una etiqueta de partida <item> establecemos el indicador inItem como true para asegurar que inItem los datos correctos al objeto correcto y en el método endElement establecemos ese indicador como false si encontramos una etiqueta </item> . Para señalar que hemos terminado con esa etiqueta de artículo.

En este ejemplo es bastante fácil de manejar, pero tener que analizar una estructura más compleja con la repetición de etiquetas en diferentes niveles se vuelve complicado. Allí usted tendría que usar Enums por ejemplo para establecer su estado actual y un montón de statemenets de switch / case para comprobar dónde está o una solución más elegante sería algún tipo de rastreador de etiquetas con una pila de etiquetas.

En muchos problemas es necesario utilizar diferentes tipos de archivos xml para diferentes propósitos. No intentaré captar la inmensidad y contar desde mi propia experiencia lo que necesitaba todo esto.

Java, tal vez, mi lenguaje de programación favorito. Además, este amor se ve reforzado por el hecho de que usted puede resolver cualquier problema y llegar a una bicicleta no es necesario.

Por lo tanto, me tomó para crear un montón de cliente-servidor que ejecuta una base de datos que permitiría al cliente de forma remota hacer entradas en el servidor de base de datos. No hace falta estar comprobando los datos de entrada, etc. y similares, pero no se trata de eso.

Como principio de trabajo, yo, sin dudarlo, elegí la transmisión de información en forma de archivo xml. De los siguientes tipos:

 <? xml version = "1.0" encoding = "UTF-8" standalone = "no"?> <doc> <id> 3 </ id> <fam> Ivanov </ fam> <name> Ivan </ name> <otc> I. </ otc> <dateb> 10-03-2005 </ dateb> <datep> 10-03-2005 </ datep> <datev> 10-03-2005 </ datev> <datebegin> 09-06-2009 </ datebegin> <dateend> 10-03-2005 </ dateend> <vdolid> 1 </ vdolid> <specid> 1 </ specid> <klavid> 1 </ klavid> <stav> 2.0 </ stav> <progid> 1 </ progid> </ doc> 

Hacer más fácil leer más, excepto para decir que es la información sobre las instituciones de los médicos. Apellido, nombre, identificador único, y así sucesivamente. En general, la serie de datos. Este archivo con seguridad se puso en el lado del servidor, y luego comenzar a analizar el archivo.

De las dos opciones de análisis (SAX vs DOM) He elegido SAX vista del hecho de que él trabaja más brillante, y él fue el primero que cayó en las manos 🙂

Asi que. Como saben, para trabajar con éxito con el analizador, tenemos que anular los métodos necesarios DefaultHandler. Para empezar, conecte los paquetes requeridos.

 import org.xml.sax.helpers.DefaultHandler; import org.xml.sax. *; 

Ahora podemos empezar a escribir nuestro parser

 public class SAXPars extends DefaultHandler {  ... } 

Comencemos con el método startDocument (). Él, como su nombre lo indica, reacciona a un evento que comienza con el documento. Aquí puede colgar una variedad de acciones, como la asignación de memoria, o para restablecer los valores, pero nuestro ejemplo es bastante simple, por lo que sólo marca el inicio del trabajo de un mensaje apropiado:

 Override public void startDocument () throws SAXException {  System.out.println ("Start parse XML ..."); } 

Siguiente. El analizador pasa por el documento cumple con el elemento de su estructura. Inicia el método startElement (). Y de hecho, su apariencia esto: startElement (String namespaceURI, String localName, String qName, Atributos atts). Aquí namespaceURI – el espacio de nombres, localName – el nombre local del elemento, qName- una combinación de nombre local con un espacio de nombres (separados por dos puntos) y atts – los atributos de este elemento. En este caso, todo simple. Basta con usar qName'om y lanzarlo a alguna línea de servicio thisElement. Así marcamos en que el elemento en el momento que somos.

 @Override public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {  thisElement = qName; } 

A continuación, el tema de la reunión llegamos a su significado. Aquí se incluyen métodos characters (). Tiene la forma: caracteres (char [] ch, int start, int length). Bueno, aquí todo está claro. Ch – un archivo que contiene la propia auto-importancia dentro de este elemento. Inicio y longitud – el número de servicio que indica el punto de inicio en la línea y la longitud.

 @Override public void characters (char [] ch, int start, int length) throws SAXException {  if (thisElement.equals ("id")) {     doc.setId (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("fam")) {     doc.setFam (new String (ch, start, length));  }  if (thisElement.equals ("name")) {     doc.setName (new String (ch, start, length));  }  if (thisElement.equals ("otc")) {     doc.setOtc (new String (ch, start, length));  }  if (thisElement.equals ("dateb")) {     doc.setDateb (new String (ch, start, length));  }  if (thisElement.equals ("datep")) {     doc.setDatep (new String (ch, start, length));  }  if (thisElement.equals ("datev")) {     doc.setDatev (new String (ch, start, length));  }  if (thisElement.equals ("datebegin")) {     doc.setDatebegin (new String (ch, start, length));  }  if (thisElement.equals ("dateend")) {     doc.setDateend (new String (ch, start, length));  }  if (thisElement.equals ("vdolid")) {     doc.setVdolid (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("specid")) {     doc.setSpecid (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("klavid")) {     doc.setKlavid (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("stav")) {     doc.setStav (new Float (new String (ch, start, length)));  }  if (thisElement.equals ("progid")) {     doc.setProgid (new Integer (new String (ch, start, length)));  } } 

Ah, sí. Casi lo olvido. Como el objeto de que será doblar datos naparsennye habla al tipo de médicos. Esta clase se define y tiene todos los setters-getters necesarios.

El siguiente elemento obvio termina y es seguido por el siguiente. Responsable de terminar el endElement (). Nos indica que el tema ha terminado y que puedes hacer algo en este momento. Se procedera. Limpie el elemento.

 @Override public void endElement (String namespaceURI, String localName, String qName) throws SAXException {  thisElement = ""; } 

Llegando a todo el documento, llegamos al final del archivo. Trabajo endDocument (). En él, podemos liberar memoria, hacer algunos diagnósticos de impresión, etc En nuestro caso, sólo tiene que escribir sobre lo que termina el análisis.

 @Override public void endDocument () {  System.out.println ("Stop parse XML ..."); } 

Así que tenemos una clase para analizar xml nuestro formato. Aquí está el texto completo:

 import org.xml.sax.helpers.DefaultHandler; import org.xml.sax. *; public class SAXPars extends DefaultHandler { Doctors doc = new Doctors (); String thisElement = ""; public Doctors getResult () {  return doc; } @Override public void startDocument () throws SAXException {  System.out.println ("Start parse XML ..."); } @Override public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {  thisElement = qName; } @Override public void endElement (String namespaceURI, String localName, String qName) throws SAXException {  thisElement = ""; } @Override public void characters (char [] ch, int start, int length) throws SAXException {  if (thisElement.equals ("id")) {     doc.setId (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("fam")) {     doc.setFam (new String (ch, start, length));  }  if (thisElement.equals ("name")) {     doc.setName (new String (ch, start, length));  }  if (thisElement.equals ("otc")) {     doc.setOtc (new String (ch, start, length));  }  if (thisElement.equals ("dateb")) {     doc.setDateb (new String (ch, start, length));  }  if (thisElement.equals ("datep")) {     doc.setDatep (new String (ch, start, length));  }  if (thisElement.equals ("datev")) {     doc.setDatev (new String (ch, start, length));  }  if (thisElement.equals ("datebegin")) {     doc.setDatebegin (new String (ch, start, length));  }  if (thisElement.equals ("dateend")) {     doc.setDateend (new String (ch, start, length));  }  if (thisElement.equals ("vdolid")) {     doc.setVdolid (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("specid")) {     doc.setSpecid (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("klavid")) {     doc.setKlavid (new Integer (new String (ch, start, length)));  }  if (thisElement.equals ("stav")) {     doc.setStav (new Float (new String (ch, start, length)));  }  if (thisElement.equals ("progid")) {     doc.setProgid (new Integer (new String (ch, start, length)));  } } @Override public void endDocument () {  System.out.println ("Stop parse XML ..."); } } 

Espero que el tema ayude a presentar fácilmente la esencia del analizador SAX.

No juzgue estrictamente el primer artículo 🙂 Espero que al menos alguien útil.

UPD: Para ejecutar este analizador, puede utilizar este código:

 SAXParserFactory factory = SAXParserFactory.newInstance (); SAXParser parser = factory.newSAXParser (); SAXPars saxp = new SAXPars (); parser.parse (new File ("..."), saxp); 

  • La barra de herramientas no se oculta mientras se desplaza
  • JetBrain Idea android elemento xml no está permitido aquí
  • Cómo establecer una altura máxima con contenido de recapitulación en android?
  • Múltiples animaciones en 1 imageview android
  • Frontera de elementos de listview en android
  • Problema de espaciado de la barra de herramientas con Android Design Support Library
  • Android hacer? Attr / selectableItemBackgroundBorderless ir más lejos?
  • cómo establecer la flecha desplegable en el hilandero con el fondo?
  • Cómo manejar clics de botón utilizando el XML onClick dentro de Fragmentos
  • Selector con android: drawable = atributo "@ color / transparent"
  • ¿Cómo se exportan los elementos extraíbles del vector XML de Android a otro formato?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.