Reputation: 2395
I have simple XML that I want to read in Perl and make hash containing all read keys.
Consider this code:
my $content = $xml->XMLin("filesmap.xml")->{Item};
my %files = map { $_->{Path} => 1 } @$content;
This snippet works great when XML file contains many Item
tags. Then $content
is a reference to array. But when there is only one Item
I get an error when dereferencing as array. My assumption is that $content
is a reference to the scalar, not array.
What is the practice to make sure I get array of values read from XML?
Upvotes: 1
Views: 71
Reputation: 53478
What you need is to not use XML::Simple
and then it's really trivial. My favourite for fairly straightforward XML samples is XML::Twig
use XML::Twig;
my $twig = XML::Twig -> new -> parsefile ( 'filesmap.xml' );
my @files = map { $_ -> trimmed_text } $twig -> get_xpath ( '//Path' );
With a more detailed XML sample (and desired result) I'll be able to give you a better answer.
Part of the problem with XML::Simple
is it tries to turn an XML data structure into perl data structures, and - because hashes are key-values and unordered but arrays are ordered, it has to guess. And sometimes it does it wrong, and other times it's inconsistent.
If you want it to be consistent, you can set:
my $xml = XMLin( "filesmap.xml", ForceArray => 1, KeyAttr => [], ForceContent => 1 );
But really - XML::Simple
is just a route to pain. Don't use it. If you don't like XML::Twig
, try XML::LibXML
instead.
Upvotes: 8
Reputation: 9296
You can do a check and force the return into an array reference if necessary:
my $content = $xml->XMLin("filesmap.xml")->{Item};
$content = ref $content eq 'ARRAY'
? $content
: [$content];
Upvotes: 1
Reputation: 29854
What I would say you need is a flatten-ing step.
my %files
= map { $_->{Path} => 1 }
# flatten...
map { ref() eq 'ARRAY' ? @$_ : $_ }
$xml->XMLin("filesmap.xml")->{Item}
;
Upvotes: 1