
two level XML
Consider the following simple XML that has two levels.
<acme>
 <name>Bugs Bunny</name>
</acme>
Data::Dumper can be used to see how XML::Simple is going to parse the XML file.
use XML::Simple;
use Data::Dumper;
my $xml= XMLin("cartoon.xml");
print Dumper $xml;
Which will produce the following. Notice Bugs Bunny is inside of { } characters. Data inside of { } is interepreted as a hash.
$VAR1 = {
'name' => {
'Bugs Bunny',
}
};
The following would work as expected, and print Bugs Bunny.
use XML::Simple;
my $xml= XMLin("cartoon.xml");
print $xml->{'name'};
Consider the following XML.
<acme>
 <name>Bugs Bunny</name>
 <name>Elmer Fudd</name>
<name>Yosemite Sam</name>
</acme>
Now, Bugs Bunny, Elmer Fudd, and Yosemite Sam are inside of [ ] characters. Data inside of [ ] is interpreted as an array.
$VAR1 = {
'name' => [
'Bugs Bunny',
'Elmer Fudd',
'Yosemite Sam'
]
};
Attempting to print each name like this . . .
use XML::Simple;
my $xml= XMLin("cartoon.xml");
print $xml->{'name'};
. . . would produce the following, because the 'name' values are inside of the [ ] characters, thus they are array items.
ARRAY(Ox12bf350)
You can print a particular cartoon character by specifying the array value (0 prints Bugs Bunny, 1 print Elmer Fudd, 2 prints Yosemite Sam).
print $xml->{'name'}->[0];
print $xml->{'name'}->[1];
print $xml->{'name'}->[2];
Or, you could print all of the values in the array. This will print Bugs Bunny Elmer Fudd Yosemite Sam. However, this will not work if there is only a single cartoon character.
print @{$xml->{'name'}};
The solution to this challenge is to use the ForceArray => 1 option.
$cartoon = XMLin("cartoon.xml", ForceArray => 1 );
Once the ForceArray => 1 option is used, you can then use the following to print all of the values of the array. This will work when there is only a single item in the array, or when there are two or more items in the array.
print @{$xml->{'name'}};
One caveot is that the following markup will fail to print a cartoon character once the ForceArray options is set.
print $cartoon->{'name'};
Instead, you would have to append the array value, like this.
print $cartoon->{'name'}->[0];
hash and array mixtures
Let's consider this XML.
<acme>
<characters>
 <name>Bugs Bunny</name>
 <name>Elmer Fudd</name>
<name>Yosemite Sam</name>
</characters>
</acme>
Dumper will produce the following. Notice 'characters' is inside of { } (hash data). Bugs Bunny, Elmer Fudd, and Yosemite Sam are inside of [ ] (array data).
$VAR1 = {
'characters' =>
{
'name' => [
'Bugs Bunny',
'Elmer Fudd',
'Yosemite Sam'
]
}
};
In this situation, you would loop through the first array (character) and then print the second array (name).
foreach my $key (keys %{$xml}) {
foreach my $character ( @{$xml->{$key}} ) {
print @{$character->{name}};
}
}
Did you find this article helpful?
If so, consider buying me a coffee over at