• Publicidad

Extracción de datos de XML

¿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.

Extracción de datos de XML

Notapor caribesoft » 2007-10-16 10:13 @467

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 :
Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
 <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>
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


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

Después de recibir el XML, hago esto
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
      for( @{$respuesta->{Accommodation}->{Hotel}} ) {
           $hotel_code = $_->{Hcode};
           $room_code  = $_->{Room}->{Hucode};
           $room_type  = $_->{Room}->{RoomType};
           print "$hotel_code | $room_code | $room_type \n";
      }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


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


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

Muchas gracias,

Caribesoft 8)
caribesoft
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2006-05-09 22:01 @959
Ubicación: Cancun

Publicidad

Notapor explorer » 2007-10-16 12:02 @543

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.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Sí, eso es lo que está pasando

Notapor caribesoft » 2007-10-16 12:25 @559

Hola Explorer:

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

Código: Seleccionar todo
$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.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
####  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;
    }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


¿Cómo podré extraer los datos correctamente?

Saludos,
Caribesoft 8)
caribesoft
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2006-05-09 22:01 @959
Ubicación: Cancun

Notapor explorer » 2007-10-16 12:55 @580

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.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Así es

Notapor caribesoft » 2007-10-16 13:19 @597

Hola Explorer :

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


Gracias,

Caribesoft. 8)
caribesoft
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2006-05-09 22:01 @959
Ubicación: Cancun

Notapor explorer » 2007-10-16 20:12 @883

Pues con otro bucle, claro... :-D
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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";
    }
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Código: Seleccionar todo
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
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

¡¡¡ Perfectamente !!!

Notapor caribesoft » 2007-10-17 12:10 @548

Gracias Explorer:

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

Saludos,

Caribesoft
caribesoft
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2006-05-09 22:01 @959
Ubicación: Cancun

Otra pregunta del mismo tema

Notapor caribesoft » 2007-10-24 12:03 @544

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

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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";
    }
}
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


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 8)
caribesoft
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2006-05-09 22:01 @959
Ubicación: Cancun

Notapor explorer » 2007-10-24 14:47 @658

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.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Eres un sabio

Notapor caribesoft » 2007-10-24 17:16 @761

Hola Explorer :

La verdad eres un Sabio; sí me funcionó con el
Código: Seleccionar todo
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 8)
caribesoft
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2006-05-09 22:01 @959
Ubicación: Cancun


Volver a Intermedio

¿Quién está conectado?

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