Perl en Español

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

Extracción de datos de XML

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio
Mensaje Mar Oct 16, 2007 9:13 am
caribesoft
Perlero Nuevo
Perlero Nuevo
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
Extracción de datos de XML Responder citando

Hola Amigos Perlianos:

Tengo una duda para la extracción de información de un XML.

Estoy utilizando XML::Simple y me ha funcionado muy bien, pero ahora tengo una estructura un poco más compleja, creo que es un array dentro de un hash :
XML:
<xml>
- <Accommodation>
- <Hotel>
  <Name>Azul Beach</Name>
  <Hcode>HOT0000503</Hcode>
  <Type>Resort</Type>
  <Rating>5</Rating>
  <MitSiteCode />
+ <Descriptions>
+ <Descriptions>
+ <Descriptions>
+ <Descriptions>
+ <Descriptions>
+ <Descriptions>
+ <Descriptions>
+ <Descriptions>
+ <Descriptions>
- <Room>
  <Hucode>HOT0000503000003</Hucode>
  <RoomType>Azul Suite</RoomType>
  <MaxOccupancy>4</MaxOccupancy>
  </Room>
+ <Room>
  <Hucode>HOT0000503000002</Hucode>
  <RoomType>Deluxe Room</RoomType>
  <MaxOccupancy>4</MaxOccupancy>
  </Room>
+ <Room>
  <Hucode>HOT0000503000001</Hucode>
  <RoomType>Superior Room</RoomType>
  <MaxOccupancy>3</MaxOccupancy>
  </Room>
  </Hotel>


Necesito obtener la información que viene en los campos Hucode, RoomType y MaxOccupancy.

Después de recibir el XML, hago esto
Perl:
      for( @{$respuesta->{Accommodation}->{Hotel}} ) {
           $hotel_code = $_->{Hcode};
           $room_code  = $_->{Room}->{Hucode};
           $room_type  = $_->{Room}->{RoomType};
           print "$hotel_code | $room_code | $room_type \n";
      }


Pero estoy recibiendo este mensaje de error:
Código:
Bad index while coercing array into hash


Me pueden dar un "tip" para evitar este error.

Muchas gracias,

Caribesoft Cool
Mensaje Mar Oct 16, 2007 11:02 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
Responder citando

El 'tip' podría ser: usa Data::Dumper.

XML::Simple es simple en el hecho de que deja a los programadores con la tarea de pegarnos con las estructuras de datos que crea. Y según cómo hayas hecho la lectura del XML, serán de una forma o de otra.

Cada vez que tengo que leer un XML con ese módulo, ya tengo la costumbre de hacer un Dump() para saber qué forma tiene lo que he leído, y a partir de ahí, saber qué arrays/hashes existen.

El mensaje de error dice que estás intentando leer una clave de un hash cuando en realidad se ha encontrado con un array.

Lo más seguro es que XML::Simple, al ver la estructura jerárquica, haya metido los distintos nodos que se pueden repetir en elementos de arrays. Te faltará un '[0]' en alguna parte.
Mensaje Mar Oct 16, 2007 11:25 am
caribesoft
Perlero Nuevo
Perlero Nuevo
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
Sí, eso es lo que está pasando Responder citando

Hola Explorer:

Si, eso es lo que está pasando, mira, aquí tengo una parte del print Dumper:

Código:
$VAR1 = {
    'Accommodation' => {
        'Hotel' =>  [
                     {
                         'Type' => 'Resort',
                         'MitSiteCode' => {},
                         'Descriptions' => [
                                             {
                                                 'CommentType' => 'Body Text',
                                                 'Image' => {},
                                                 'Comment' => "On a beautiful stretch of the Bahia"
                                             },
                                             {
                                                 'CommentType' => 'Image 1',
                                                 'Image' => {},
                                                 'Comment' => "",
                                             },
                                             {
                                                 'CommentType' => 'Image 2',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Image 3',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Image 4',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Summary',
                                                 'Image' => {},
                                                 'Comment' => 'On a beautiful stretch of the Bahia'
                                             },
                                             {
                                                 'CommentType' => 'Supplementary 1',
                                                 'Image' => {},
                                                 'Comment' => 'Here comes information about the rates inclusions.'
                                             },
                                             {
                                                 'CommentType' => 'Thumbnail 1',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Thumbnail 2',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Thumbnail 3',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Thumbnail 4',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             }
                                           ],
                         'Room' => [
                                     {
                                         'RoomType' => 'Azul Suite',
                                         'Hucode' => 'HOT0000503000003',
                                         'MaxOccupancy' => '4'
                                     },
                                     {
                                         'RoomType' => 'Deluxe Room',
                                         'Hucode' => 'HOT0000503000002',
                                         'MaxOccupancy' => '4'
                                     },
                                     {
                                         'RoomType' => 'Superior Room',
                                         'Hucode' => 'HOT0000503000001',
                                         'MaxOccupancy' => '3'
                                     }
                                   ],
                         'Rating' => '5',
                         'Hcode' => 'HOT0000503',
                         'Name' => 'Azul',
                     },
                     {
                         'Type' => 'Hotel',
                         'MitSiteCode' => {},
                         'Descriptions' => [
                                             {
                                                 'CommentType' => 'Image 1',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Image 2',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Summary',
                                                 'Image' => {},
                                                 'Comment' => 'Here comes the summary description of this hotel, bla, bla, bla, bla'
                                             },
                                             {
                                                 'CommentType' => 'Thumbnail 1',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             },
                                             {
                                                 'CommentType' => 'Thumbnail 2',
                                                 'Image' => '',
                                                 'Comment' => {}
                                             }
                                           ],
                         'Room' => [
                                     {
                                         'RoomType' => {},
                                         'Hucode' => 'HOT0000502000008',
                                         'MaxOccupancy' => '0'
                                     },
                                     {
                                         'RoomType' => 'Date Test Room',
                                         'Hucode' => 'HOT0000502000005',
                                         'MaxOccupancy' => '3'
                                     },
                                     {
                                         'RoomType' => 'Free night example',
                                         'Hucode' => 'HOT0000502000003',
                                         'MaxOccupancy' => '4'
                                     },
                                     {
                                         'RoomType' => 'Ocean Front Jacuzzi Junior Suite',
                                         'Hucode' => 'HOT0000502000001',
                                         'MaxOccupancy' => '3'
                                     },
                                     {
                                         'RoomType' => 'Ocean Front Jacuzzi Junior Suite',
                                         'Hucode' => 'HOT0000502000001',
                                         'MaxOccupancy' => '3'
                                     },
                                     {
                                         'RoomType' => 'Ocean Front Jacuzzi Junior Suite',
                                         'Hucode' => 'HOT0000502000001',
                                         'MaxOccupancy' => '3'
                                     },
                                     {
                                         'RoomType' => 'Price based on party size',
                                         'Hucode' => 'HOT0000502000004',
                                         'MaxOccupancy' => '10'
                                     },
                                     {
                                         'RoomType' => 'Price based on party size',
                                         'Hucode' => 'HOT0000502000004',
                                         'MaxOccupancy' => '10'
                                     },
                                     {
                                         'RoomType' => 'Price based on party size',
                                         'Hucode' => 'HOT0000502000004',
                                         'MaxOccupancy' => '10'
                                     },
                                     {
                                         'RoomType' => 'Superior Room',
                                         'Hucode' => 'HOT0000502000002',
                                         'MaxOccupancy' => '3'
                                     },
                                     {
                                         'RoomType' => 'Superior Room',
                                         'Hucode' => 'HOT0000502000002',
                                         'MaxOccupancy' => '3'
                                     },
                                     {
                                         'RoomType' => 'Superior Room',
                                         'Hucode' => 'HOT0000502000002',
                                         'MaxOccupancy' => '3'
                                     }
                                   ],
                         'Rating' => '5',
                         'Hcode' => 'HOT0000503',
                         'Name' => 'Azul',
                     }
                    ]
    }
};

ya intenté ponerle el [0] en diferentes partes, pero me sigue enviando el error.

El script lo que hace es enviar un GET a un ASP, por medio de LWP::UserAgent y la respuesta viene en XML.

Perl:
####  AQUI SE EJECUTA EL REQUEST  ####
     my $req = GET "$part1$dbn$xtra";
     my $res = $ua->request($req);
     if ($res->is_success) {
       my $respuesta= $xs->XMLin($res->content);
       my $xml = $xs->XMLout($respuesta);
       #print Dumper($respuesta);
      #####  RECUPERO LOS ROOMTYPES  #####
      for( @{$respuesta->{Accommodation}->{Hotel}} ) {
           $hotel_code = $_->{Hcode};
           $room_code  = $_->{Room}->{Hucode};
           $room_type  = $_->{Room}->{RoomType};
           print "$hotel_code | $room_code | $room_type \n";
      }
      exit;

    }else{
       print $res->as_string;
       print "<p>Server Error, please try later ...</p>";
       exit;
    }


¿Cómo podré extraer los datos correctamente?

Saludos,
Caribesoft Cool
Mensaje Mar Oct 16, 2007 11:55 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
Responder citando

Luego lo pruebo, pero creo que el Hcode sí que lo recuperas bien. El Hucode y Roomtype forman parte de otro array. Es decir, en tu código intentas recuperar el código por cada Hotel, pero Room es un array de habitaciones, cada una con su código y estilo.
Mensaje Mar Oct 16, 2007 12:19 pm
caribesoft
Perlero Nuevo
Perlero Nuevo
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
Así es Responder citando

Hola Explorer :

Así es, hay un array de Rooms dentro del Array de Accommodation, eso no le sé manejar...


Gracias,

Caribesoft. Cool
Mensaje Mar Oct 16, 2007 7:12 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
Responder citando

Pues con otro bucle, claro... Very Happy
Perl:
foreach my $hotel ( @{$respuesta->{Accommodation}->{Hotel}} ) {
    my $hotel_code = $hotel->{Hcode};
    foreach my $room ( @{$hotel->{Room}} ) {
        my $room_code  =  $room->{Hucode};
        my $room_type  =  $room->{RoomType};
        print "$hotel_code | $room_code | $room_type \n";
    }
}

Código:
HOT0000503 | HOT0000503000003 | Azul Suite
HOT0000503 | HOT0000503000002 | Deluxe Room
HOT0000503 | HOT0000503000001 | Superior Room
HOT0000503 | HOT0000502000008 | HASH(0x183af00)
HOT0000503 | HOT0000502000005 | Date Test Room
HOT0000503 | HOT0000502000003 | Free night example
HOT0000503 | HOT0000502000001 | Ocean Front Jacuzzi Junior Suite
HOT0000503 | HOT0000502000001 | Ocean Front Jacuzzi Junior Suite
HOT0000503 | HOT0000502000001 | Ocean Front Jacuzzi Junior Suite
HOT0000503 | HOT0000502000004 | Price based on party size
HOT0000503 | HOT0000502000004 | Price based on party size
HOT0000503 | HOT0000502000004 | Price based on party size
HOT0000503 | HOT0000502000002 | Superior Room
HOT0000503 | HOT0000502000002 | Superior Room
HOT0000503 | HOT0000502000002 | Superior Room
Mensaje Mie Oct 17, 2007 11:10 am
caribesoft
Perlero Nuevo
Perlero Nuevo
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
¡¡¡ Perfectamente !!! Responder citando

Gracias Explorer:

Esa era la solución, y me funcionó muy bien, siempre tienes una buena idea...

Saludos,

Caribesoft
Mensaje Mie Oct 24, 2007 11:03 am
caribesoft
Perlero Nuevo
Perlero Nuevo
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
Otra pregunta del mismo tema Responder citando

Hola Explorer :

Volviendo al mismo ejemplo, tengo un problema, cuando hago referencia al segundo hash foreach my $room ( @{$hotel->{Room}} y solo tiene un elemento, me enviar un error : Not an ARRAY reference

Perl:
foreach my $hotel ( @{$respuesta->{Accommodation}->{Hotel}} ) {
    my $hotel_code = $hotel->{Hcode};
    foreach my $room ( @{$hotel->{Room}} ) {
        my $room_code  =  $room->{Hucode};
        my $room_type  =  $room->{RoomType};
        print "$hotel_code | $room_code | $room_type \n";
    }
}


Mi pregunta, para este caso y más en el futuro, ¿cómo puedo validar si un hash, tiene un solo par o elemento, para no tratarlo como hash sino como array? ¿sería lo correcto?

Saludos,
Caribesoft Cool
Mensaje Mie Oct 24, 2007 1:47 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
Responder citando

Con ref() se puede saber qué tipo de referencia es una variable, pero eso te complica bastante el código para lo que quieres hacer.

El problema está en XML::Simple. Resulta que, cuando un nodo sólo tiene un elemento, en vez de crear un array de un solo elemento lo que hace es integrar el elemento como atributos del elemento padre.

En algún caso está bien porque así no crea estructuras de datos muy complicadas, pero lo complica cuando en nuestro programa usamos sentencias de control simples (como las que has puesto) para recorrer la estructura. Si la estructura no es igual en todos los nodos, pues se nos complica la vida.

La solución es muy simple: decirla a XML::Simple que NO haga eso. Que SIEMPRE ponga arrays en los elementos hijos de otros.

Esto se consigue en el momento de leer el xml, con la opción ForceArray => 1. Con ello, tendremos todo organizado como arrays, y los tributos, como hashes.

Aquí viene otro problema: puede que tener TODO en esta forma sea complicarlo más. Bueno, pues hay otra opción, la ForceArray => ['Room'] le indicamos qué nodo sí queremos que convierta a array.

Con una buena combinación de los atributos en XMLin(), XML::Simple te dejará tu xml de una forma muy cómoda, para que luego puedas leerlo.

Como ya he comentado antes, Data::Dumper es tu mejor aliado frente al enemigo XML::Simple.
Mensaje Mie Oct 24, 2007 4:16 pm
caribesoft
Perlero Nuevo
Perlero Nuevo
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
Eres un sabio Responder citando

Hola Explorer :

La verdad eres un Sabio; sí me funcionó con el
Código:
ForceArray =>['Room'])


Solo que me tarde un poco más por no leer bien tus instrucciones y haberme comido las comillas del Room, y por ende, no funcionaba, pero así como lo muestro arriba, funcionó de maravilla.

Muchas gracias nuevamente por compartir tu sabiduría, con todos los aprendices como yo.

Y quiero felicitar nuevamente a "Kid" por haber creado y mantener este maravilloso SITIO y FORO.

Saludos desde Cancún.

Caribesoft Cool
Publicar nuevo tema   Responder al tema    Foros de discusión -> Intermedio Todas las horas son GMT - 6 Horas
Página 1 de 1



Powered by phpBB © 2001, 2005 phpBB Group