Jul 112015
 
Artículo PHP

La distribución base del intérprete PHP incluye un función json_decode que hace muy sencillo el proceso de ficheros en formato JSON. Pero esta función trabaja sobre un string que debe haber sido completamente en memoria. Esto puede ser un problema si se trabaja con ficheros de varios cientos de megabytes, o incluso de más de un gigabyte, como es el caso en determinados escenarios (por ejemplo, cuando se procesan datos geográficos en formato GeoJSON). En este artículo se explica el uso de una librería “jsonstreamingparser” para PHP, que permite procesar los objetos contenidos en el fichero conforme se van leyendo, evitando un consumo excesivo de los recursos de memoria disponibles.

Descarga e instalación de la librería jsonstreamingparser

La librería se puede descargar desde Github: https://github.com/salsify/jsonstreamingparser Una vez descargado y descomprimido el paquete, la instalación se realiza con composer. En primer lugar, instalamos composer localmente en el directorio jsonstreamingparser-master:

y a continuación procedemos a la instalación del paquete jsonstreamingparser y sus dependencias:

Comprobación de la instalación

En el directorio “example” existe un ejemplo que podemos ejecutar para comprobar que la instalación se ha realizado sin problemas:

Bajo el directorio “example” hay también un subdirectorio “geojson” que contiene un ejemplo de proceso de un fichero en formato GeoJSON:

Implementación de un Listener para procesar los datos recibidos

Para procesar un documento JSON, debemos crear una clase “MiProcesadorJSON” que implemente el interfaz “\JsonStreamingParser\Listener”. El script abre el fichero a procesar con una llamada a fopen(), y le pasa a una instancia de la clase “MiProcesadorJSON” el descriptor del fichero obtenido:

La clase MiProcesadorJSON debe implementar los métodos definidos en el interfaz “\JsonStreamingParser\Listener”:

El parser se encarga de ir leyendo el fichero caracter a carácter, y llamar a las funciones definidas en el listener cada vez que se produce un evento. Normalmente, el listener utiliza una serie de variables privadas en las que guarda el estado del proceso.

Ejemplo: Proceso de un array de objetos sencillos

Un caso frecuente es el de un fichero JSON que consiste en un array con un gran número de objetos:

Cada objeto es una serie de pares (clave, valor):

En este ejemplo, queremos obtener cada uno de los objetos como una estructura PHP, para procesarlos a medida que se van leyendo del fichero. Cada uno de los valores puede ser un valor primitivo ( un número, una cadena de texto, un valor booleano). Pero también puede ser un array de valores, o un objeto, dando lugar a una estructura de varios niveles:

Para poder recoger estas estructuras anidadas en una variable PHP, deberemos utilizar una pila (en forma de un array PHP en la variable $_stack) en donde guardaremos la jerarquía de elementos que están siendo leidos. También utilizaremos una pila (en la variable $_keys) para guardar la jerarquía de claves, y una variable $_nivel para guardar el nivel en el que nos encontramos dentro de la jerarquía de elementos:

Como vemos, estas variables se inicializan en la función start_document(), y se actualizan cuando comienza a leerse un nuevo array u objeto. Por otra parte, cuando se lee una clave, se almacena en la pila de claves:

Y cuando se lee un valor: – Si el elemento que se está procesando es un array, se añade al mismo. – Si el elemento que se está procesando es un objeto, se extrae la última clave de la pila de claves, y se añade el par (clave, valor) al último objeto de la pila de objetos:

También, cuando finaliza la lectura de un objeto o de un array, el elemento leído es tratado de la misma forma que si fuera un valor simple, insertándolo en el array u objeto del nivel anterior en la jerarquía:

Como vemos, en el caso de un objeto, comprobamos si se trata de un objeto de primer nivel, en cuyo caso procedemos a procesarlo como sea necesario (p.ej., insertándolo en una base de datos). En el ejemplo, simplemente volcamos el objeto a standard output con una llamada a var_dump().

Proceso de un fichero GeoJSON

El formato GeoJSON es un formato JSON en donde el elemento del primer nivel es un objeto que contiene una serie de pares (clave,valor). Entre ellas, está la clave “features”, que tiene asignado como valor un array de objetos que puede llegar a tener un número muy elevado de elementos. Para procesar este tipo de ficheros, debemos modificar ligeramente la clase MiProcesadorJSON. El cambio más sencillo consiste en modificar la función end_object() para que el proceso de un elemento se realice si el nivel es mayor que 2:

Y eso es todo!

Indice de artículos sobre programación en PHP

 Publicado por en 7:04 pm

 Deja un comentario

(requerido)

(requerido)