Mar Oct 16, 2007 9:13 am
|
 |
caribesoft
Perlero Nuevo

|
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
|
|
| Extracción de datos de XML |
|
|
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  |
|
|
|

Mar Oct 16, 2007 11:02 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
|
|
|
|
|
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. |
|

Mar Oct 16, 2007 11:25 am
|
 |
caribesoft
Perlero Nuevo

|
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
|
|
| Sí, eso es lo que está pasando |
|
|
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  |
|

Mar Oct 16, 2007 11:55 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
|
|
|
|
|
| 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. |
|
Mar Oct 16, 2007 12:19 pm
|
 |
caribesoft
Perlero Nuevo

|
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
|
|
| Así es |
|
|
Hola Explorer :
Así es, hay un array de Rooms dentro del Array de Accommodation, eso no le sé manejar...
Gracias,
Caribesoft.  |
|

Mar Oct 16, 2007 7:12 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
|
|
|
|
|
Pues con otro bucle, claro...
| 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
|
|
|

Mie Oct 17, 2007 11:10 am
|
 |
caribesoft
Perlero Nuevo

|
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
|
|
| ¡¡¡ Perfectamente !!! |
|
|
Gracias Explorer:
Esa era la solución, y me funcionó muy bien, siempre tienes una buena idea...
Saludos,
Caribesoft |
|

Mie Oct 24, 2007 11:03 am
|
 |
caribesoft
Perlero Nuevo

|
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
|
|
| Otra pregunta del mismo tema |
|
|
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  |
|

Mie Oct 24, 2007 1:47 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4222
Ubicación: Valladolid, España
|
|
|
|
|
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. |
|

Mie Oct 24, 2007 4:16 pm
|
 |
caribesoft
Perlero Nuevo

|
Registrado: 09 May 2006
Mensajes: 73
Ubicación: Cancun
|
|
| Eres un sabio |
|
|
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  |
|
Powered by phpBB © 2001, 2005 phpBB Group
|