Perl Datadumper recursivo

Hola amigos,

Hoy os traigo una cosita que hice ayer para probar. Estaba trabajando con unos archivos XML en Perl y resulta que tenía una estructura de datos bastante complicada como resultado de un parseo.

Lo que tenía era, básicamente, Array cuyos contenidos eran o Scalars $ (el tipo básico, pueden ser Strings también), Hashes % (lista con Clave => Valor) o Arrays @ (lista numerada N => Valor).

Si lo tradujésemos a Python sería: una List cuyos contenidos son Strings (en este caso eran Strings), Dictionaries o Lists.

Quería mostrarlo en la pantalla todo, para ver el contenido y para ver si era capaz de recorrer todo de forma ordenada y con el mínimo código posible.

Para mostrarlo simplemente en pantalla se puede usar el módulo Data::Dumper, que mola bastante y hace lo que nosotros queremos. Hace un volcado de todos los datos a la pantalla. Pero yo quería tener control para luego poder sustituir los print por un poco de tratamiento.

Y esto es lo que hice:

extractData(@data);

sub extractData{
    my $value = shift; # Take first argument (first value from @_)

    if(ref($value) eq "HASH"){
        isHash( $value );
    }
    elsif(ref($value) eq "ARRAY"){
        isArray( $value );
    }
    else{
        print "$value\n";
    }
}

sub isHash{
    my $content = shift;
    while( my ($field, $value) = each %$content ){ # Iterate Hash
        print "$field:\n";
        extractData($value);
    }

}

sub isArray{
    my $content = shift;
    my $value;
    foreach $value (@$content){ # Iterate Array
        extractData($value);
    }
}

El resultado no se visualiza muy bien pero la idea es que veáis cómo enfoco el problema.

Ya hablé de las funciones recursivas en otro post hace tiempo y este no es más que otro ejemplo de lo mismo.

A parte de la recursividad se basa en enviar los datos como referencia en lugar de por valor. En Perl, las referencias son un Scalar (un string del pelo de: ARRAY(Dirección) o HASH(Dirección)) así que se pueden enviar a las funciones y tratarlos como si sólo fuesen eso: un simple Scalar.

La función ref extrae el tipo referenciado para que se pueda comparar como hago en la función extractData. Como se puede apreciar, la función extractData funciona igualmente con Scalars, Arrays o Hashes, porque tomará la referencia y dependiendo del tipo que se le haya enviado hará una cosa u otra.

En caso de que sea un Hash el contenido, la función isHash se encargará de iterar por el Hash para pintar las claves y mandarle los contenidos a extractData para que compruebe el tipo y decida que hace.

En caso de que sea un Array, la función isArray hace un poco lo mismo.

Si recordáis, la última vez que hablé de esto dije que las funciones recursivas tienen que tener un final. ¿Sabríais decirme cuál es en ésta?

(La respuesta está en el siguiente párrafo, pero no lo leáis todavía, pensadlo)

Para que la función deje de llamarse a si misma tiene que llegar a Scalars, es decir, tiene que caer en el else de extractData. Estos Scalars van a estar siempre al final de las ramas del árbol, como expliqué en la entrada aquella que menciono más arriba y que te tienes que leer.

😉

Espero que os haya gustado. Entended lo que hace y jugad con ello. Si se os ocurren otras formas de hacerlo, no dudéis en añadirlas. ¿Cómo sería de complicado sin funciones recursivas? ¿Igual sería más simple?

Un abrazo.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s