• Publicidad

XML::Parser dentro de mi clase

¿Ya sabes lo que es una referencia? Has progresado, el nível básico es cosa del pasado y ahora estás listo para el siguiente nivel.

XML::Parser dentro de mi clase

Notapor dabeat » 2009-09-04 03:35 @191

Hola,

Estoy utilizando el módulo XML::Parser para crear un parser XML. Me gustaría utilizarlo desde una clase. He creado una clase (MiClase.pm) y dentro he implementado el parser XML. Pero desde dentro de una clase no funciona, mientras que en un script Perl tal cual sí lo hace.

Creo que está relacionado con la manera que tiene Perl de definir los métodos de una clase. Se requiere que la primera línea sea algo así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my $self = shift;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Y parece que XML::Parser tiene problemas con esto. Supongo que los handlers que implemento para el parser los detecta como métodos de clase pero esto no le gusta al parser. No logro hacer funcionar el parser dentro de una clase.

Por otro lado, he encontrado que en PHP, el XML parser utiliza este método:

Sintáxis: [ Descargar ] [ Ocultar ]
Using php Syntax Highlighting
xml_set_object($this->parser, $this);
Coloreado en 0.019 segundos, usando GeSHi 1.0.8.4


para indicar que los handlers del parser están en la propia clase. ¿Hay alguna manera de poder implementar un parser con XML::Parser usando POO?

Gracias
Última edición por explorer el 2009-09-04 06:13 @300, editado 1 vez en total
Razón: Ortografía. Anglicismos. Bloques de código.
dabeat
Perlero nuevo
Perlero nuevo
 
Mensajes: 7
Registrado: 2009-09-04 03:27 @185

Publicidad

Re: XML::Parser dentro de mi clase

Notapor explorer » 2009-09-04 07:29 @354

Bienvenido a los foros de Perl en Español, dabeat.

¿Podrías poner un ejemplo, muy reducido, del código que no te funciona?
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

Re: XML::Parser dentro de mi clase

Notapor dabeat » 2009-09-05 06:01 @292

Por supuesto, explorer; adjuntado va el archivo MyClass.pm con una versión reducida de la clase en la que intento utilizar el parser XML.

En esta versión, los handlers del parser no son métodos de clase, sino que están tal cual en el mismo archivo. Cuando los utilizaba como métodos de clase en esta misma clase, todo estaba exactamente igual, lo único que cambiaba es que añadía la línea:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my $self = shift;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


como primera línea de código en cada handler, pero tampoco funcionaba. Ahora mismo, con la clase tal y como está, cuando llamo al método 'build_command', recibo como error:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
read error at /usr/lib/perl5/vendor_perl/5.8.6/i386-linux-thread-multi/XML/Parser/Expat.pm line 469.
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
Adjuntos
MyClass.zip
(790 Bytes) 70 veces
Última edición por explorer el 2009-09-05 09:36 @441, editado 1 vez en total
Razón: Acentos
dabeat
Perlero nuevo
Perlero nuevo
 
Mensajes: 7
Registrado: 2009-09-04 03:27 @185

Re: XML::Parser dentro de mi clase

Notapor explorer » 2009-09-05 12:14 @551

Exceptuando la curiosidad que veo en las líneas 54 a 56, donde no creas uno, sino dos objetos XML::Parser, el resto fundamentalmente está bien.

He construido un ejemplo.

Tenemos este código principal:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use MyClass;
  7.  
  8. use Data::Dumper;
  9.  
  10.  
  11. my $myclass = MyClass->new(file => 'fichero.xml');
  12.  
  13.  
  14. ## Inicio de la construción
  15. $myclass->build_command();
  16.  
  17. print Dumper $myclass;              # Ver nuestro objeto por dentro
  18.  
  19.  
  20. ## Resultado del comando
  21. print $myclass->{command};          # ¡Aaaggg! Mejor hacer métodos de acceso
  22.  
  23.  
  24. ## Acceso al intérprete
  25. my $parser = $myclass->{parser};    # ¡Aaaggg! Mejor hacer métodos de acceso
  26.  
  27. __END__
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Todo normal: importamos nuestra clase, creamos un objeto, invocamos un método, vemos cómo es por dentro y accedemos a sus atributos.

La clase es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. package MyClass;
  2. use strict;
  3. use warnings;
  4.  
  5. use XML::Parser;
  6.  
  7. my $XML_DIR = '.';
  8.  
  9. ## Constructor
  10. sub new {
  11.     my $this  = shift;                  # Cogemos la clase que somos o una referencia a la clase (si soy un objeto)
  12.     my $class = ref($this) || $this;    # Averigua la clase a la que pertenece
  13.     my %args  = @_;                     # Argumentos pasados al constructor
  14.  
  15.     my $self = \%args;                  # Aquí almacenamos los atributos del objeto
  16.  
  17.     bless $self, $class;                # Perl nos tiene que dar el visto bueno (bautismo)
  18.  
  19.     return $self;
  20. }
  21.  
  22. ## Creación de los elementos de construcción
  23. sub build_command{
  24.     my $self = shift;
  25.  
  26.     $self->{command} = '';
  27.  
  28.     # Realiza el interpretado del XML
  29.     $self->parseData();
  30.  
  31. }
  32.  
  33. sub parseData {
  34.     my $self = shift;
  35.  
  36.     my $parser                      # Mi intérprete ...
  37.         =  $self->{parser}          # ... es el que ya teníamos,
  38.         || XML::Parser->new(        # ... o uno nuevo.
  39.                 ErrorContext    => 2,
  40.                 Handlers        => {
  41.                                     Start => sub { $self->handle_start(@_) },
  42.                                     End   => sub { $self->handle_end(@_)   },
  43.                                     Char  => sub { $self->handle_char(@_)  },
  44.                                },
  45.         );
  46.  
  47.     $parser->parsefile("$XML_DIR/$self->{file}");
  48.  
  49.     $self->{parser} = $parser;      # Lo guardamos para la próxima ocasión
  50. }
  51.  
  52. sub handle_start {
  53. #use Data::Dumper;
  54. #print Dumper \@_;
  55. #exit;
  56.  
  57.     my $self = shift;
  58.     my ($parser, $tag, %attr) = @_;
  59.  
  60.     $self->{command} .= "(+$tag";
  61. #    print "$tag => \n";
  62.     for (sort keys %attr) {
  63.         $self->{command} .= "\[$_ => $attr{$_}\]";
  64. #        print "\t$_ => $attr{$_}\n";
  65.     }
  66.     $self->{command} .= ',';
  67. }
  68.  
  69. sub handle_end{
  70.     my $self = shift;
  71.     my ($parser, $tag) = @_;
  72.  
  73.     $self->{command} .= ")\n";
  74. #    print "$tag <= \n";
  75. }
  76.  
  77. sub handle_char {
  78.     my $self = shift;
  79.     my ($parser, $string) = @_;
  80.     chomp $string;
  81.  
  82.     $self->{command} .= "{$string}";
  83. #    print "\t[$string]\n";
  84. }
  85.  
  86. 1;
  87.  
  88.  
  89. __END__
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

Igual que lo que tenías antes, salvo que en parseData() nos aseguramos de que no hemos creado antes otro objeto XML::Parser. Lo guardaremos como uno de los atributos de nuestro objeto.

Todos los métodos del objeto que pueden ser invocados por el usuario les pondremos la línea my $self = shift; ya que en ella es donde recibimos la referencia al objeto que invoca el método (así sabemos de qué objeto se trata).

El resultado es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
explorer@casa:~/Documents/Desarrollo> cat fichero.xml; ./kk.pl
<?xml version="1.0" standalone="yes"?>
<Mibs>
        <UBR100000>
                <SNRTotal>a</SNRTotal>
                <SNR>b</SNR>
                <CW_UNER>c</CW_UNER>
                <CW_CORR>d</CW_CORR>
                <CW_UNCORR>e</CW_UNCORR>
                <FREQ>f</FREQ>
                <OCUPACION>g</OCUPACION>
                <MODCM>h</MODCM>
                <MOD>i</MOD>
        </UBR100000>
        <UBR7200>
                <SNRTotal>a</SNRTotal>
                <SNR>b</SNR>
                <CW_UNER>c</CW_UNER>
                <CW_CORR>d</CW_CORR>
                <CW_UNCORR>e</CW_UNCORR>
                <FREQ>f</FREQ>
                <OCUPACION>g</OCUPACION>
                <MODCM>h</MODCM>
                <MOD>i</MOD>
        </UBR7200>
</Mibs>
$VAR1 = bless( {
                 'parser' => bless( {
                                      'Non_Expat_Options' => {
                                                               'NoLWP' => 1,
                                                               'Non_Expat_Options' => 1,
                                                               '_HNDL_TYPES' => 1,
                                                               'Handlers' => 1,
                                                               'Style' => 1
                                                             },
                                      'Base' => './fichero.xml',
                                      'Pkg' => 'MyClass',
                                      '_HNDL_TYPES' => {
                                                         'CdataEnd' => sub { "DUMMY" },
                                                         'Start' => sub { "DUMMY" },
                                                         'Entity' => sub { "DUMMY" },
                                                         'ExternEntFin' => sub { "DUMMY" },
                                                         'End' => sub { "DUMMY" },
                                                         'Final' => 1,
                                                         'Doctype' => sub { "DUMMY" },
                                                         'Char' => sub { "DUMMY" },
                                                         'Init' => 1,
                                                         'XMLDecl' => sub { "DUMMY" },
                                                         'Default' => sub { "DUMMY" },
                                                         'CdataStart' => sub { "DUMMY" },
                                                         'Comment' => sub { "DUMMY" },
                                                         'Unparsed' => sub { "DUMMY" },
                                                         'ExternEnt' => sub { "DUMMY" },
                                                         'Element' => sub { "DUMMY" },
                                                         'Attlist' => sub { "DUMMY" },
                                                         'DoctypeFin' => sub { "DUMMY" },
                                                         'Notation' => sub { "DUMMY" },
                                                         'Proc' => sub { "DUMMY" }
                                                       },
                                      'Handlers' => {
                                                      'End' => sub { "DUMMY" },
                                                      'Char' => sub { "DUMMY" },
                                                      'ExternEnt' => sub { "DUMMY" },
                                                      'Start' => sub { "DUMMY" }
                                                    },
                                      'ErrorContext' => 2
                                    }, 'XML::Parser' ),
                 'file' => 'fichero.xml',
                 'command' => '(+Mibs,{}{        }(+UBR100000,{}{                }(+SNRTotal,{a})
{}{                }(+SNR,{b})
{}{                }(+CW_UNER,{c})
{}{                }(+CW_CORR,{d})
{}{                }(+CW_UNCORR,{e})
{}{                }(+FREQ,{f})
{}{                }(+OCUPACION,{g})
{}{                }(+MODCM,{h})
{}{                }(+MOD,{i})
{}{        })
{}{        }(+UBR7200,{}{                }(+SNRTotal,{a})
{}{                }(+SNR,{b})
{}{                }(+CW_UNER,{c})
{}{                }(+CW_CORR,{d})
{}{                }(+CW_UNCORR,{e})
{}{                }(+FREQ,{f})
{}{                }(+OCUPACION,{g})
{}{                }(+MODCM,{h})
{}{                }(+MOD,{i})
{}{        })
{})
'
               }, 'MyClass' );
(+Mibs,{}{        }(+UBR100000,{}{                }(+SNRTotal,{a})
{}{                }(+SNR,{b})
{}{                }(+CW_UNER,{c})
{}{                }(+CW_CORR,{d})
{}{                }(+CW_UNCORR,{e})
{}{                }(+FREQ,{f})
{}{                }(+OCUPACION,{g})
{}{                }(+MODCM,{h})
{}{                }(+MOD,{i})
{}{        })
{}{        }(+UBR7200,{}{                }(+SNRTotal,{a})
{}{                }(+SNR,{b})
{}{                }(+CW_UNER,{c})
{}{                }(+CW_CORR,{d})
{}{                }(+CW_UNCORR,{e})
{}{                }(+FREQ,{f})
{}{                }(+OCUPACION,{g})
{}{                }(+MODCM,{h})
{}{                }(+MOD,{i})
{}{        })
{})
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Actualización: Cambiado el código para que las subrutinas internas del intérprete tuvieran acceso a los atributos del objeto.
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

Re: XML::Parser dentro de mi clase

Notapor dabeat » 2009-09-05 12:36 @567

Muchas gracias explorer.

En cuanto a la creación de dos parsers en las lineas 54 y 55, supongo que de tanto hacer pruebas para lograr que funcionase he ido dejando 'incoherencias'.

Entonces, por lo que veo, los handlers, aún siendo métodos de clase, no tienen la referencia a '$self' (el propio objeto de la clase), sino al handler. Entonces, aún estando definidos en la propia clase, no parece que sean métodos de la clase, ¿no?

Por ejemplo, si se quisiera que la información extraída del documento XML se almacenara en atributos propios de la clase, los handlers no tienen referencia al '$self', por lo que no pueden acceder a los atributos de clase.
dabeat
Perlero nuevo
Perlero nuevo
 
Mensajes: 7
Registrado: 2009-09-04 03:27 @185

Re: XML::Parser dentro de mi clase

Notapor explorer » 2009-09-05 13:59 @624

Buen punto: las subrutinas adjuntas al intérprete XML::Parser no son métodos del objeto, por lo que no tienen acceso a las propiedades del mismo, aunque estén definidas dentro de él.

Yo creo que se podría resolver el asunto creando el hash que almacena los atributos del objeto como un objeto global, definido fuera del new(), con lo que sería conocido por todas las funciones. No lo he probado así que no sé si funcionará (bueno, en Perl, es muy probable de que sí :D )

El caso es que he modificado el código anterior con otra solución:
* He agregado la línea 21 al programa principal para pintar un atributo llamado 'command' donde esperamos recibir la interpretación del XML
* La clase es la misma, salvo que en las declaraciones de los Handlers a usar (41 a 43), lo hacemos de forma distinta: cada handler será una función que definimos justo en ese lugar, y que consiste en hacer la llamada a las funciones adjuntas, pero esta vez pasándoles como primera referencia la del objeto actual ($self), más el resto de parámetros que XML::Parser nos envía (@_):

Start => sub { $self->handle_start(@_) },

* Solo queda agregar el my $self = shift; a cada función adjunta para que recoja la referencia al objeto del que se trate.

Seguro que se puede hacer de más formas...
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

Re: XML::Parser dentro de mi clase

Notapor dabeat » 2009-09-05 15:13 @676

Perfecto explorer, muchas gracias. Tu solución me parece la ideal, al menos para mi caso.
dabeat
Perlero nuevo
Perlero nuevo
 
Mensajes: 7
Registrado: 2009-09-04 03:27 @185


Volver a Intermedio

¿Quién está conectado?

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

cron