Contenido

Formatos simples: XML, Yaml, Json, Properties e 'Ini'

Cuando queremos transmitir datos entre dos máquinas, almacenar la configuración o guardar datos para un uso posterior, tenemos que decidir el formato del archivo que estamos usando.

En algunos casos la decisión pasa por un archivo binario, lo cual puede estar bien en muchos casos. En otros puede ser un gran error, ya que siempre es mejor utilizar formatos existentes. Estos formatos suelen proporcionarnos librerías con el fin de facilitarnos la creación y/o el uso de los archivos.

Me voy a centrar en 5 de estos formatos. No voy a compararlos, ya que creo que cada uno está bien para un grupo de casos concretos. Ya hice una comparativa entre XML y JSON, que suelen ser en los que más discrepancias pueden aparecer, y creo que es suficiente.

XML

Aunque XML es de todo menos simple, he decidido incluirlo ya que suele utilizarse en los mismos casos que otros de los incluidos.

Es un formato extensible (eXtensible Markup Language), que tiene un montón de herramientas asociadas (CSS, DTD, XPATH, Schema, …). Es más que un formato: es un lenguaje.

Es muy potente, pero a menudo resulta demasiado verboso, resultando así bastante incómodo de modificar a mano. Tiene una estructura bien definida que puede comprobarse mediante DTD o Schema, lo que es un arma de dos filos: Por un lado, nos asegura que cumple el formato que queremos; por otro, resulta más fácil equivocarse al modificarlo a mano.

Hay dos maneras básicas de procesarlo: mediante la gestión del árbol completo (DOM) o según se lee (SAX). DOM permite mayor potencia a costa de recursos y SAX ofrece mayor velocidad y menor consumo. Evidentemente, SAX permite la lectura de documentos más grandes que DOM.

Se utiliza en sistemas de comunicación complejos, como SOAP o Web Services. Al tener un formato extricto, permitir comentarios, etc. puede ser fácilmente auto-explicativo, lo que permite una manera sencilla comunicar a otros la interfaz de nuestra aplicación.

Permite utilizar cualquier encoding y referencias externas, así como obtener un identificador único para cualquier nodo.

Ejemplo con datos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <list type="cdrom">
     <item title="cd 1">Descripción de cd 1</item>
     <item title="cd 2">Descripción de cd 2</item>
  </list>
  <list type="dvd">
     <item title="dvd 1">Descripción de dvd 1</item>
  </list>
</root>

Ejemplo de configuración:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<config>
  <main>
    <line_feed>\
</line_feed>
  </main>
  <item>
    <separator>|</separator>
    <escape>&</escape>
  </item>
</config>

JSON

Consiste en una representación en formato cadena de una combinación de hashes, vectores y pares clave-valor.

Se ha estandarizado como método de comunicaciones entre métodos de la misma aplicación, como ocurre entre la parte Java y la parte JSP de un servlet.

Resulta muy útil y sencillo para estructuras pequeñas (puede que con muchos datos, pero con una estructura pequeña), pero tiende a complicarse rápidamente. Aunque para pocos datos es muy intuitivo, con muchos datos resulta difícil de seguir, aunque es fácil procesarlo automáticamente.

Siempre debe ir codificado en UTF-8.

Ejemplo:

1
2
3
4
5
6
7
8
9
{ "root": [
     "cdrom": [
        { "title" : "cd 1", "description": "Descripción de cd 1" },
        { "title" : "cd 2", "description": "Descripción de cd 2" }
     ],
     "dvd": [
        { "title" : "dvd 1", "description": "Descripción de dvd 1" }
     ]
}

Ejemplo de configuración:

1
2
3
4
5
[
  { "main" : { "line_feed": "\
" } },
  { "item" : { "separator": "|", "escape": "&" } }
]

Yaml

Es un formato pensado para ser leído por el ser humano más que por la máquina. Se basa en saltos de línea e indentaciones.

Para cosas sencillas puede ser muy válido, pero puede complicarse cuando hay saltos de línea. Puede resultar muy útil para describir archivos de configuración.

No requiere un nodo raíz del que cuelga todo, como ocurre con XML.

Ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cdrom:
  item:
    title: cd 1
    description: Descripción de cd 1
  item:
    title: cd 2
    description: Descripción de cd 2
dvd:
    title: dvd 1
    description: Descripción de dvd 1

Ejemplo de configuración:

1
2
3
4
5
6
main:
  line_feed: "\"

item:
  separator: "|"
  escape: "&"

INI

Numerosos programas antiguos y modernos utilizan este tipo de codificación para almacenar sus datos, como por ejemplo el registro de windows o apache.

Consiste en un conjunto de secciones, cuyo título va entre corchetes, que contienes pares clave-valor.

Aunque resulta fácil de entender para un informático, he descubierto por experiencia que no es tan intuitivo para un no-informático, ya que suelen pensar que el orden no importa (importa dentro de una sección), y he visto casos en los que se han agrupado las secciones por un lado y los datos por otro.

No resultan útiles para describir colecciones, pero sí para describir valores. No admite más de un nivel de sección, pero puede representarse utilizando un separador común en el nombre de la sección.

En teoría, las claves no deben repetirse en la misma sección, aunque he visto implementaciones que sí lo permiten.

Ejemplo:

1
2
3
4
5
6
7
8
9
[cdrom/cd_1]
title = cd 1
description = Descripción de cd 1
[cdrom/cd_2]
title = cd 2
description = Descripción de cd 2
[dvd/dvd_1]
title = dvd 1
description = Descripción de dvd 1

Ejemplo configuración:

1
2
3
4
5
6
7
[main]
line_feed = \


[item]
separator = |
escape = &

ConfigObj

Python incorpora un dialecto de los INIs que permite mantener anidaciones dentro de las secciones. Este formato se llama configobj.

Por ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[cdrom]
      [[cd 1]]
      title = cd 1
      description = Descripción de cd 1

      [[cd_2]]
      title = cd 2
      description = Descripción de cd 2
[dvd]
      [[dvd_1]]
      title = dvd 1
      description = Descripción de dvd 1

Y el ejemplo de configuración:

1
2
3
4
5
6
7
[main]
line_feed = \


   [[item]]
   separator = |
   escape = &

En mi opinión personal no deja de ser una manera de complicar lo sencillo, pero puede ser útil en algunos casos.

Properties

Los archivos de propiedades son típicos de java, aunque no exclusivos.

Consisten en una lista de la forma clave-valor. Es un formato parecido al de los INIs, pero sin secciones. Las claves son únicas.

Resulta muy intuitivo para utilizarlo en archivos de configuración.

1
2
3
4
5
6
cdrom.cd_1.title = cd 1
cdrom.cd_1.description = Descripción de cd 1
cdrom.cd_2.title = cd 2
cdrom.cd_2.description = Descripción de cd 2
cdrom.dvd_1.title = cd 1
cdrom.dvd_1.description = Descripción de dvd 1

Ejemplo de configuración:

1
2
3
4
main.line_feed = \

item.separator = |
item.escape = &

Conclusión

Si lo que queremos es un formato con un tiempo de vida corto, da igual lo que usemos. En este caso podemos estar usando Java y JSP, que trabajan cómodamente con JSON, por lo que podría ser el más adecuado.

Para definir un protocolo entre dos aplicaciones, JSON puede no ser el más adecuado, dejando el caso para XML. Estos protocolos suelen ir evolucionando con el tiempo, y es más difícil mantener esta compatibilidad con JSON que con XML.

A la hora de generar informes puede ser interesante utilizar YAML debido a su sencillez, pero resulta muy sencillo equivocarse al editar este formato.

Si queremos configurar una aplicación, me decanto por los INIs o Properties. En mi opinión, me decantaré por los properties en todos los casos por las siguientes razones:

  • Son unívocos. Una clave sólo aparece una vez.
  • Se pueden agrupar mediante parte del nombre.
  • Son rápidos de entender por la máquina.
  • Son sencillos de editar.
  • No dependen de ningún orden.
  • Internamente, manejar un INI requiere una lista de hashes, mientras que un properties puede representarse óptimamente como una única hash.

Sin embargo, el formato INI está mucho más extendido actualmente.

Pero lo más importante de todo esto es: No inventéis formatos raros. Nada de guardar en binario ni cosas por el estilo. Sed compatibles. Y si no queréis serlo, cifradlo, o utilizad una base de datos embebible.