Perl en Español

  1. Home
  2. Tutoriales
  3. Foro
  4. Artículos
  5. Donativos
  6. Publicidad
 

Convertir XML en TXT
Ir a página 1, 2  Siguiente
 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico
Mensaje Mie Jul 02, 2008 10:26 am
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Convertir XML en TXT Responder citando

Hola soy nuevo usando Perl y el asunto es que tengo que hacer un programita que me convierta un archivo XML en un archivo TXT. Estuve viéndolo hacer con Java, pero al parecer con Perl es mucho más sencillo; sin embargo, estoy atascado en varios puntos.

Primero que todo el archivo XML es muy sencillo, a continuación muestro como es:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<datos xsi:noNamespaceSchemaLocation="D:\Work\prueba.xsd" opr="0">
        <letra>V</letra>
        <cedula>123</cedula>
        <PNombre>nombre</PNombre>
        <SNombre>Segundo Nombre</SNombre>
        <PApellido>apellido</PApellido>
        <FechaNac>1980-07-25</FechaNac>
        <FechaCedOrg>2005-03-31</FechaCedOrg>
        <CodObjecion>00</CodObjecion>
        <CodOficina>AB</CodOficina>
        <CodEstadoCivil>2</CodEstadoCivil>
        <Naturalizado>0</Naturalizado>
        <Sexo>M</Sexo>
</datos>


y el código que he creado en Perl es el siguiente:

Perl:
use XML::Simple;

my $datos = XMLin('./prueba.xml');

print join q{|},
        $datos->{letra}          ,
        $datos->{cedula}         , 
        $datos->{PNombre}        ,
        $datos->{SNombre}        ,
        $datos->{PApellido}      ,
        $datos->{FechaNac}       ,
        $datos->{FechaCedOrg}    ,
        $datos->{CodObjecion}    ,
        $datos->{CodOficina}     ,
        $datos->{CodEstadoCivil} ,
        $datos->{Naturalizado}   ,
        $datos->{Sexo};
print "\n";


Hasta ahora esto me está funcionando bien, sin embargo aún no es lo que deseo obtener, ya que necesito que el programa me lea el atributo "opr " del elemento datos; si este atributo es 0 me debe marcar la información para "insertar" y si es 1, lo debe marcar como "actualizar".

No he conseguido entonces cómo leer este atributo del elemento.

Además de ello, este archivo xml se encontrará en un carpeta con varios archivos xml más, con la misma estructura; tampoco entonces he encontrado una función o librería que me lea todo el folder y me vaya leyendo xml por xml y pienso que me los cargue en un array donde después los pueda vaciar en el txt.

Hasta ahora estoy muy básico en este asunto, lo bueno es que he podido apreciar la potencialidad de este lenguaje.
Mensaje Mie Jul 02, 2008 11:11 am
monoswim
Vive para Perl en Español
Vive para Perl en Español
Registrado: 18 Nov 2003
Mensajes: 691
Ubicación: Buenos Aires
Responder citando

Programándolo a mano se puede hacer bien fácil... no necesitas módulos... vamos por partes.

Perl:
my $opr;
if ($datos->{opr} == 0){
   $opr = 'insertar';
}else{
   $opr = 'actualizar';
}


Ahora solo tienes que colocar a $opr en tu lista de join...

Y para abrir el directorio y cargarlo a un array:

Perl:
opendir(DIR, "directorio");
my @files = sort readdir(DIR);
closedir(DIR);


Y recuerda hacer un chop doble para eliminar los archivos . y ..

Espero que te sirva.

Saludos
PD: ¡¡¡ BIENVENIDO A LOS FOROS !!!
Mensaje Mie Jul 02, 2008 12:25 pm
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

Hola, gracias por responderme. Lo de la variable $opr está funcionando de maravilla, al código le hice varios cambios ahora, y ya puede guardar la información en un archivo txt y hacer un salto de línea para el siguiente xml, sin embargo el problema que me falta resolver es que lea todos los xml que se encuentren en un directorio "x" y los cargue en un array, después, que este array sea guardado en el txt; ahora por un lado no veo cómo integrar el código que escribiste sobre la lectura del directorio dentro de mi código; aquí coloco el código nuevo:

Perl:
use XML::Simple;

my $datos = XMLin('./prueba.xml');
my $opr;
if ($datos->{opr} == 0){
        $opr = 'insertar';
}else{
        $opr = 'actualizar';
}
open (prueba, ">>","/home/principal/prueba.txt") or (prueba, ">", "/home/principal/prueba.txt");
print prueba join q{|},
        $opr ,
        $datos->{letra}          ,
        $datos->{cedula}         ,
        $datos->{PNombre}        ,
        $datos->{SNombre}        ,
        $datos->{PApellido}      ,
        $datos->{FechaNac}       ,
        $datos->{FechaCedOrg}    ,
        $datos->{CodObjecion}    ,
        $datos->{CodOficina}     ,
        $datos->{CodEstadoCivil} ,
        $datos->{Naturalizado}   ,
        $datos->{Sexo};
print prueba "\n";
close prueba;
Mensaje Mie Jul 02, 2008 3:26 pm
monoswim
Vive para Perl en Español
Vive para Perl en Español
Registrado: 18 Nov 2003
Mensajes: 691
Ubicación: Buenos Aires
Responder citando

Cuando cargas en un array los nombres de cada archivo tienes que hacer un bucle que ejecute tu código por cada archivo...

Perl:
foreach my $file (@files){
   my $datos = XMLin("./directorio/$file");
   ...
   close prueba;
}


¿Me expliqué bien?

Saludos
Mensaje Mie Jul 02, 2008 3:49 pm
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

Casualmente se me había ocurrido hacer una solución similar a la que colocaste y quedo así:
Perl:
use XML::Simple;
opendir(DIR, "/home/principal/xml/xml1/");
my @files=readdir(DIR);
foreach my $a (@files){
my $datos = XMLin("./$a");
my $opr;
open (prueba, ">>","/home/principal/xml/prueba.txt") or (prueba, ">", "/home/principal/xml/prueba.txt");
print prueba join q{|},
        $datos->{opr}            ,
        $datos->{letra}          ,
        $datos->{cedula}         ,
        $datos->{PNombre}        ,
        $datos->{SNombre}        ,
        $datos->{PApellido}      ,
        $datos->{FechaNac}       ,
        $datos->{FechaCedOrg}    ,
        $datos->{CodObjecion}    ,
        $datos->{CodOficina}     ,
        $datos->{CodEstadoCivil} ,
        $datos->{Naturalizado}   ,
        $datos->{Sexo};
print prueba "\n";
close prueba;
}
closedir(DIR);


Sin embargo no funciona Sad , da el siguiente error:
bash:
read error at /usr/lib/perl5/XML/Parser/Expat.pm line 469.


P.D.: En la ruta de my $datos probé con varios opciones y tampoco funcionó, lo hice por si el error era producto de no conseguir el archivo.
Mensaje Mie Jul 02, 2008 4:29 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3823
Ubicación: Valladolid, España
Responder citando

El error ha ocurrido en la interpretación del xml. Es posible que esté mal.

Esta variación es algo mejor: el open() solo se hace una vez.
Perl:
use XML::Simple;

opendir(DIR, "/home/principal/xml/xml1/");
my @files=readdir(DIR);
closedir(DIR);

my $opr;

open (prueba, ">","/home/principal/xml/prueba.txt") or die "$!\n";

foreach my $a (@files) {
    my $datos = XMLin("./$a");
    print prueba join q{|},
        $datos->{opr}            ,
        $datos->{letra}          ,
        $datos->{cedula}         ,
        $datos->{PNombre}        ,
        $datos->{SNombre}        ,
        $datos->{PApellido}      ,
        $datos->{FechaNac}       ,
        $datos->{FechaCedOrg}    ,
        $datos->{CodObjecion}    ,
        $datos->{CodOficina}     ,
        $datos->{CodEstadoCivil} ,
        $datos->{Naturalizado}   ,
        $datos->{Sexo};
    print prueba "\n";
}

close prueba;

Recuerda, también, que cuando trabajes con XML::Simple, Data::Dumper es tu amigo.
Mensaje Mie Jul 02, 2008 6:12 pm
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

Hola, bueno hago dos veces el open porque con el primero agrego en caso de que el archivo exista, y el segundo es por si el archivo prueba.txt no ha sido creado y así lo crea y adjunta la información.

Estuve leyendo algo sobre el error y pareciera que fuera un problema con el archivo XML pero no le veo nada que esté mal; de todas formas aquí lo copio por si uds. observan algo errado.

XML:
<?xml version="1.0" encoding="UTF-8"?>
<datos xsi:noNamespaceSchemaLocation="D:\Work\prueba.xsd" opr="0">
        <letra>V</letra>
        <cedula>123</cedula>
        <PNombre>nombre</PNombre>
        <SNombre>Segundo Nombre</SNombre>
        <PApellido>apellido</PApellido>
        <FechaNac>1980-07-25</FechaNac>
        <FechaCedOrg>2005-03-31</FechaCedOrg>
        <CodObjecion>00</CodObjecion>
        <CodOficina>AB</CodOficina>
        <CodEstadoCivil>2</CodEstadoCivil>
        <Naturalizado>0</Naturalizado>
        <Sexo>M</Sexo>
</datos>


También probé eliminarle al XML toda la ruta del xsi y siguió dando el problema, cosa que me hace dudar entonces que el problema sea el archivo XML.

Sin embargo aunque genera el error, el programa está creando el archivo prueba,txt. Lo malo es que solo está guardando los datos del primer archivo que consigue. Si hay más de uno no guarda el resto; revisé el bucle y no sé por qué sucede esto.
Mensaje Mie Jul 02, 2008 7:23 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3823
Ubicación: Valladolid, España
Responder citando

A mí el error que me da es que el namespace (espacio de nombres) xsi no ha sido declarado:
Código:
Undeclared prefix: xsi at /usr/lib/perl5/site_perl/5.8.8/XML/NamespaceSupport.pm line 298.

Según la documentación de XML::Simple, debes usar el modo de interpretación con SAX.

Si eliminamos 'xsi:' del xml, entonces sí que funciona:
Perl:
#!/usr/bin/perl
use XML::Simple;
use Data::Dumper;
my $xml = XMLin('kk.xml');

print Dumper($xml);

Código:
$VAR1 = {
          'opr' => '0',
          'CodEstadoCivil' => '2',
          'CodOficina' => 'AB',
          'letra' => 'V',
          'FechaCedOrg' => '2005-03-31',
          'noNamespaceSchemaLocation' => 'D:\\Work\\prueba.xsd',
          'SNombre' => 'Segundo Nombre',
          'cedula' => '123',
          'Sexo' => 'M',
          'PNombre' => 'nombre',
          'FechaNac' => '1980-07-25',
          'Naturalizado' => '0',
          'CodObjecion' => '00',
          'PApellido' => 'apellido'
        };


(Humm... los '\' en el valor de xsi me dan mala espina...)
Mensaje Mie Jul 02, 2008 10:03 pm
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

Bueno, el error me sigue dando, sin embargo el programa está haciendo su función y lee todos los xml de un directorio especifico, los guarda en el array y después los vacía en un txt, ahora lo que no veo cómo hacer, es implementar la función "chop" para que me elimine el . y el .. del array.
Mensaje Jue Jul 03, 2008 2:15 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3823
Ubicación: Valladolid, España
Responder citando

La línea siguiente al foreach, pones
Perl:
next if $a =~ /^\./;
que lo que hace es saltar al siguiente fichero si el actual ($a) comienza (^) por '.'.
Mensaje Jue Jul 03, 2008 8:32 am
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

Tengo que darles todas las gracias por la ayuda que me han prestado. Me he quedado impresionado en estos dos días por el uso de Perl; es un lenguaje demasiado potente y muy práctico, pude hacer el programita con una sola librería y sin necesidad de muchas líneas de código (37) y muy rápido.

Les adjunto el código por si alguien quiere un conversor de archivos xml a txt:

Perl:
use XML::Simple;
use Data::Dumper;

opendir(DIR, "/home/principal/xml/xml1/");
        my @files= readdir(DIR);
closedir(DIR);

open (xml, ">>","/home/principal/xml/xml.txt") or (xml, ">", "/home/principal/xml/xml.txt");
        foreach my $a (@files){
                next if $a =~ /^\./;
                print "Archivos Cargados";
                print $a;
                print "\n";

                my $datos = XMLin("/home/principal/xml/xml1/$a");

                print xml join q{|},
                        $datos->{opr}            ,
                        $datos->{letra}          ,
                        $datos->{cedula}         ,
                        $datos->{PNombre}        ,
                        $datos->{SNombre}        ,
                        $datos->{PApellido}      ,
                        $datos->{FechaNac}       ,
                        $datos->{FechaCedOrg}    ,
                        $datos->{CodObjecion}    ,
                        $datos->{CodOficina}     ,
                        $datos->{CodEstadoCivil} ,
                        $datos->{Naturalizado}   ,
                        $datos->{Sexo};
                print xml "\n";

        }
print "Fin Carga";
print "\n";

close xml;
Mensaje Jue Jul 03, 2008 9:15 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3823
Ubicación: Valladolid, España
Responder citando

Según lo que indica la página de manual de open, en el uso del modo de concatenar ('>>'), si el fichero no existe, es creado.

Así que la línea
Perl:
open (xml, ">>","/home/principal/xml/xml.txt") or (xml, ">", "/home/principal/xml/xml.txt");
se puede dejar en
Perl:
open (xml, ">>/home/principal/xml/xml.txt") or die "$!\n";
Mensaje Jue Jul 03, 2008 10:03 am
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

¡¡Cierto maestro!! Lo corregí y si no existe el archivo la aplicación lo crea; así quedó mejor el código; gracias otra vez Wink
Mensaje Vie Jul 11, 2008 2:19 pm
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

Tengo un problema con el código, ya que sucede que a veces ¡el archivo XML que pongo a leer tiene algunos elementos con valores vacíos! es decir, como lo pongo ahorita en el código XML en las etiquetas CodOficina o Naturlizados por ejemplo:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<datos xsi:noNamespaceSchemaLocation="D:\Work\prueba.xsd" opr="0">
        <letra>V</letra>
        <cedula>123</cedula>
        <PNombre>nombre</PNombre>
        <SNombre>Segundo Nombre</SNombre>
        <PApellido>apellido</PApellido>
        <FechaNac>1980-07-25</FechaNac>
        <FechaCedOrg>2005-03-31</FechaCedOrg>
        <CodObjecion>00</CodObjecion>
        <CodOficina></CodOficina>
        <CodEstadoCivil>2</CodEstadoCivil>
        <Naturalizado></Naturalizado>
        <Sexo>M</Sexo>
</datos>

El hecho es que no sé cómo hacer para que el programa en Perl me valide que si encuentra un elemento vacío le coloque la palabra NULL al archivo txt y si tiene datos, bueno, debe seguir haciendo lo que hacía.
Mensaje Vie Jul 11, 2008 10:18 pm
chechoman
Perlero Nuevo
Perlero Nuevo
Registrado: 02 Jul 2008
Mensajes: 19
Responder citando

Aparte del problema de colocar NULL en elementos que no tengan valores al leer el xml, ¡¡¡también encontré otra falla y mas grave!!!, y es cómo hacer para que el programa me procese aquellos datos con "caracteres especiales", ya que para Perl me arroja que el xml está mal formado, y es porque algunos valores tienen ñ o Ñ o acentos, entonces, ¿cómo hacer para poder leer estos datos o poder sustituirlos?
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico Todas las horas son GMT - 6 Horas
Ir a página 1, 2  Siguiente
Página 1 de 2



Powered by phpBB © 2001, 2005 phpBB Group