• Publicidad

Perl, XML y tablas en Latex

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Perl, XML y tablas en Latex

Notapor ana gonzález ledesma » 2008-12-30 19:54 @870

Hola, buenas, quiero hacer un programa que haga tablas en Latex a partir de documentos etiquetados en XML para que la información sea más legible. A continuación voy a poner una muestra de un texto de etiquetas en XML con las que trabajo.

Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
<etiquetas>
<PI ID="8aa" Lema1="principio" GC="Adverb" DP="1" Range="Operator" FU="No" MET="No" DR="Coargumentation1" ED="No" MOD="No" EVI="No" SA="No" DEX="No">en parte</PI>

<PI ID="9a" Lema1="aparte" Lema2="de" GC="Adverb" DP="1" Range="Operator" FU="No" MET="No" DR="Coargumentation1" ED="No" MOD="No" EVI="No" SA="No" DEX="No">aparte de</PI>
</etiquetas>
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
(este es como digo una pequeña muestra del documento real)

Lo que quiero hacer es extraer los nombres de los atributos y colocarlos en formato tabular de Latex como elementos de la primera fila de la tabla, mientras que el contenido de los atributos irán en la segunda fila de la tabla. De tal manera que quede así en la tabla en Latex, más o menos, solo que con las líneas que ahora no voy a poner:

Código: Seleccionar todo
ID     Lema1 etc.
8aa   aparte etc.

ID     Lema1  Lema2   etc.
9a   aparte   que       etc.


Así es más fácil leer la información sobre el significado de estas palabras que están etiquetadas en mi corpus.

De momento solo quiero hacer una pequeña tabla por cada etiqueta.

Ya lo tengo todo hecho. Pero me gustaría saber dos cosas que mejorarían el programa. Hasta el momento con respecto a la primera fila, como son valores fijos, al crear el documento Latex he puesto simplemente:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
print "ID \& Lemal1 \& etc."; # y así consigo la primera columna.
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


con respecto a la segunda fila se extrae después de pasar el módulo de XML.

EL programa que genera parte de lo que luego será el documento en Latex es este:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
  use XML::Simple;
  my $mds = XMLin("coargumentacion1.xml");
  for( @{$mds->{PI}} ) {
   
  print "begin\{tabular\}\{\|\|l \| c \| r\|\|\}\n";
  print "\\hline\n";
  print "ID \& Lema1 \& GC \& DP \& Range \& FU \& MET \& DR \& ED \& MOD \& EVI \& SA \& DEX \\\\\n";
  print "\\hline\n";
  print "$_->{ID} \& $_->{Lema1} \& $_->{GC} \& $_->{DP} \& $_->{Range} \& $_->{FU} \& $_->{MET} \& $_->{DR} \& $_->{ED} \& $_->{MOD} \& $_->{EVI} \& $_->{SA} \& $_->{DEX} \& \\\\ \n";
  print "\\hline\n";
  print "end\{tabular\}\n";
                               }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

y el resultado es este:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
begin{tabular}{||l | c | r||}
\hline
ID & Lema1 & GC & DP & Range & FU & MET & DR & ED & MOD & EVI & SA & DEX \\
\hline
8aa & principio & Adverb & 1 & Operator & No & No & Coargumentation1 & No & No & No & No & No & \\
\hline
end{tabular}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


y luego esto se procesa en Latex con una cabecera y las marcas de inicio y final de documento y ya tengo la tabla en Latex.

Bien.

El caso es que este programa tiene un problema notorio, no siempre los nombres de atributos son los mismos, con lo que no pueden ser fijos. Por ejemplo, a veces hay Lema1, y otras veces hay Lema1 y Lema2, porque Lema2 es opcional, depende de si la palabra que queremos etiquetar es una multiword o no.

Pues bien. Me gustaría saber cómo se convoca desde el módulo de XML::Simple los nombres de los atributos (que no su contenido), en este caso: ID, Lema1, etc. para poder meterlos en un array e imprimirlos como fila 1 de la tabla de Latex.

Al mismo tiempo, el programa de antes también saca los contenidos de los atributos cuando estos son conocidos, pero en el fondo desconozco si una etiqueta va a tener dos lemas o uno, con lo que necesito hacer un hash entre nombre de atributo y su valor y luego llamar al valor para construir la segunda fila.

Estas son mis dudas, por favor, ¿me podéis contestar a estas dos preguntas? Y en el caso de que sea demasiado básico, ¿me podéis recomendar un manual sobre el módulo XML de perl donde se explique específicamente cómo meter en variables los nombres de los atributos y asociarlos en hash a sus contenidos?
ana gonzález ledesma
Perlero nuevo
Perlero nuevo
 
Mensajes: 17
Registrado: 2006-11-02 10:25 @475

Publicidad

Notapor explorer » 2008-12-31 00:26 @060

Esta es una alternativa...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

use LaTeX::Table;
use XML::Simple;

## Atributos que esperamos, y en este orden
my @ATTR = qw(
    ID
    Lema1 Lema2
    GC DP Range
    FU MET DR ED
    MOD EVI SA DEX
);

## Y su alineación
my %ATTR_ALINEA = (
    ID      => 'l',
    Lema1   => 'c', Lema2   => 'c',
    GC      => 'l', DP      => 'c',
    Range   => 'l',
    FU      => 'l', MET     => 'l',
    DR      => 'l', ED      => 'l',
    MOD     => 'l', EVI     => 'l',
    SA      => 'l', DEX     => 'l',
);

## Leemos el XML
my $xml = XMLin('kk.xml');

## Por cada PI
for my $pi (@{$xml->{PI}}) {

    ## Extramos los atributos en el orden que nos interesan
    my @hdr;
    my @attr;
    my @alin;

    for my $attr (@ATTR) {
        if ($pi->{$attr}) {           # Guardamos si existe ese atributo
            push @attr, $pi->{$attr};        # El atributo
            push @hdr,  $attr;               # Su cabecera
            push @alin, $ATTR_ALINEA{$attr}; # Su alineación
        }
    }

    ## Creamos la tabla
    my $table = LaTeX::Table->new({
                    filename => "latex_$pi->{ID}.tex",
                    coldef   => '||' . join('|', @alin) . '||',
                    header   => [ [ @hdr  ] ],
                    data     => [ [ @attr ] ],
    });

    ## Lo grabamos a disco
    $table->generate();
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Si kk.xml es el XML que nos has puesto, la salida de este programa son dos ficheros Latex. Uno de ellos tiene este aspecto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
\begin{table}
\centering
\begin{tabular}{||l|c|l|c|l|l|l|l|l|l|l|l|l||}
\toprule
\multicolumn{1}{c}{\textbf{ID}} & \multicolumn{1}{c}{\textbf{Lema1}} & \multicolumn{1}{c}{\textbf{GC}} & \multicolumn{1}{c}{\textbf{DP}} & \multicolumn{1}{c}{\textbf{Range}} & \multicolumn{1}{c}{\textbf{FU}} & \multicolumn{1}{c}{\textbf{MET}} & \multicolumn{1}{c}{\textbf{DR}} & \multicolumn{1}{c}{\textbf{ED}} & \multicolumn{1}{c}{\textbf{MOD}} & \multicolumn{1}{c}{\textbf{EVI}} & \multicolumn{1}{c}{\textbf{SA}} & \multicolumn{1}{c}{\textbf{DEX}} \\
\midrule
8aa & principio & Adverb & 1 & Operator & No & No & Coargumentation1 & No & No & No & No & No \\
\bottomrule
\end{tabular}
\end{table}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
que, como ves, con un poco de código Perl, y un módulo adecuado, nos permite generar código Latex sin tener que escribir Latex.

En la carpeta examples del módulo LaTeX::Table tienes un ejemplo muy bueno de lo que se puede hacer con él. Y el resultado en PDF.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

gracias

Notapor ana gonzález ledesma » 2009-01-01 06:24 @308

¡Vaaaya! Estoy muy sorprendida, ¿seguro que los reyes magos no existen? Muuuuchas gracias por tu tiempo, ayuda, conocimiento y conexiones neuronales.
ana gonzález ledesma
Perlero nuevo
Perlero nuevo
 
Mensajes: 17
Registrado: 2006-11-02 10:25 @475

Notapor explorer » 2009-01-01 12:11 @549

Quizás, el uso del módulo LaTeX::Table sea demasiado pesado para lo que parece que necesitas, así que te mando otra posibilidad:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

use XML::Simple;

my $mds = XMLin("kk.xml");

my @atributos_posibles = qw(
    ID Lema1 Lema2 GC DP Range FU MET DR ED MOD EVI SA DEX
);

for my $pi (@{$mds->{PI}}) {

    my @atributos_presentes;
    for my $atributo_posible (@atributos_posibles) {
        push @atributos_presentes, $atributo_posible if exists $pi->{$atributo_posible};
    }

    if (@atributos_presentes) {
        print 'begin{tabular}{|| l | c | r ||}', "\n";
        print '\\hline', "\n";

        print join(' & ',        @atributos_presentes ), ' \\\\', "\n";
        print '\\hline', "\n";

        print join(' & ', @{$pi}{@atributos_presentes}), ' \\\\', "\n";
        print '\\hline', "\n";

        print 'end{tabular}', "\n";

        print "\n"; # opcional
    }
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Este programa hace lo mismo que el tuyo, pero antes de crear las líneas de la tabla mira a ver qué atributos existen. Luego, con un par de join() se crean las líneas.

Quizás lo más difícil de entender sea la expresión @{$pi}{@atributos_presentes}.

Sabemos que $pi es una referencia a un hash. Luego $pi->{ID} nos accede, dentro del hash, al valor de la clave ID. Accedemos a un solo valor, por lo que hay un '$' delante.

En cambio, en esta línea queremos acceder a varias claves a la vez, por lo que deberíamos poner un '@' delante de la variable. Si tuviéramos, por ejemplo, el hash %pi, entonces la forma de sacar varias claves sería: @pi{'ID','Lema1','Lema2'}.

Lo que pasa es que pi es un escalar que almacena una referencia. Hay que desarrollarlo así: @{$pi}{'ID','Lema1','Lema2'}.

Las primeras llaves, junto con el '@' aplican el efecto de "lista de valores" (o referencia a un array) a lo que hay dentro de ellas (en efecto, $pi es una referencia). Ahora bien, la presencia de unas segundas llaves conteniendo a los atributos implica ahora que la supuesta referencia a un array en realidad es una referencia a una lista de valores extraídos de un hash, que es justo lo que es $pi.

De forma abreviada, también podríamos haberlo escrito así: @$pi{@atributos_presentes}, que se podría explicar de la misma manera que antes, si sabemos que cuando vemos varios "sigil" seguidos, hay que resolverlos antes de lo que hay a la derecha. Así, @$pi se refiere a que $pi contiene una referencia a un array o lista de valores. Y esa lista de valores salen de los correspondientes de un hash con los atributos indicados dentro del array @atributos_presentes.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados

cron