Si nos vamos a dedicar a hacer aplicaciones para iOs y Android con grandes contenidos locales, posiblemente nos vendría bien una forma de poder pasar rápidamente los datos de un sitio a otro. En iOs los contenidos locales se suelen guardar en un fichero pList, mientras que en Android los xml son la base. O también puede ocurrir que necesitemos consumir desde un servicio web que nos envie los datos en un xml formateado como un plist. En este caso, lo más sencillo es tener un plist (sobre todo si primero hemos desarrollado sobre iOs) y poder leer desde este plist en ambas plataformas. Para ello he encontrado un parser basado en SAX para leer estos plist:


https://github.com/tenaciousRas/android-plist-parser

Aunque es muy comodo, tiene las siguientes desventajas ya que parece que está preparado para leer configuraciones, no utilizar plist como almacen de datos:

  • La raiz ha de ser obligatoriamente un diccionario, no podemos tener un array como raiz.
  • Utiliza tipos propios para representar el plist y los diccionarios
  • El contenido de los array siempre los guarda como Object, con lo cual un casting a String de algo que sabemos que es un String puede causarnos una excepción.
  • Aunque está pensado para Android, no se puede crear con un Resource id de un xml propio

Por el resto, es más o menos bastante cómodo de utilizar. Vamos a poner un ejemplo de como utilizar esta clase:


PListXMLParser parser = new PListXMLParser();
String xml = Utils.getStringFromAsset(ctx,"myData.plist"); //Función que nos devuelve el contenido del xml como un string
PListXMLHandler handler = new PListXMLHandler();

parser.setHandler(handler);
parser.parse(xml);
PList plist =handler.getPlist(); // Objeto Plist que representa al fichero.
Dict d=plist.getRootDictionary();
parseData( d.getConfigurationArray("root"));

Este es un ejemplo de como obtener el contenido, primero obtenemos el contenido del plist en forma de string. Y luego creando un parser y un handler, parseamos el fichero. Ahora solo hay que obtener el objeto del tipo PList y luego el diccionario que es la raiz del arbol de datos. En mi caso, el raiz era un array, pero tuve que envolverlo en un diccionario con un solo elemento llamado root, que es el array. Así que obtengo ese array y se lo paso a un método parseData que se encarga de parsear el contenido del array a mi modelo de datos. A continuación vamos a enseñar el contenido de la función getStringFromAsset que obtiene el contenido de un fichero. Este fichero ha de estar dentro de la carpeta asset de nuestro proyecto.

public static String getStringFromAsset(Context ctx,String filename){
    try{
        AssetManager manager = ctx.getAssets();
        InputStream input= manager.open(filename);
        InputStreamReader in = new InputStreamReader(input, "utf-8");
        StringBuffer xml = new StringBuffer();
        int c =0;
        while( (c = in.read()) != -1){
           xml.append((char)c);
        }
        in.close();
        return xml.toString();
     }catch(Exception e){
         e.printStackTrace();
         return null;
     }
 }

Creo que el código se autoexplica bastante bien. Simplemente obtenemos un AssetManager, que nos permite crear flujos a los ficheros de la carpeta asset y después creamos un InputStreamReader para leer de este fichero. Es importante utilizar un tipo de flujo como este que nos permita establecer la codificación, ya que si no, nos encontraremos con carácteres extraños. Luego solo es ir leyendo caracter por caracter y guardarlos en un stringBuffer. Sinceramente, esta no es la mejor opción, ya que es bastante lenta (en una app mia, cerca de 15 segundos para un plist no muy grande) así que cuando encuentre una forma más eficiente, actualizaré.

« »