I use XML::Simple to parse the following small XML file:
<test>
<firstElem>
<anything id="1" value1="v11" value2="v12"/>
</firstElem>
<secondElem>
<anything id="2" value1="v21" value2="v22"/>
<anything id="3" value1="v31" value2="v32"/>
</secondElem>
</test>
Perl-Scipt:
use strict;
use warnings;
use Data::Dumper;
my $database = eval {XMLin("test.xml", keyattr => ['id'])};
if ($@) {
die ("Cannot parse test.xml: $@\n");
}
print Dumper ($database);
XML::Simple generates the following data structure:
$VAR1 = {
'firstElem' => {
'anything' => {
'value1' => 'v11',
'id' => '1',
'value2' => 'v12'
}
},
'secondElem' => {
'anything' => {
'3' => {
'value1' => 'v31',
'value2' => 'v32'
},
'2' => {
'value1' => 'v21',
'value2' => 'v22'
}
}
}
};
Now I wonder why XMLin the hash-structure differs between 'firstElem'
and 'secondElem'. This makes parsing the datastructure (in my opinion)
unnecessary complex.
How can I force XMLin to generate a hash for id = '1', so that the
result would look like:
$VAR1 = {
'firstElem' => {
'anything' => {
'1' => {
'value1' => 'v11',
'value2' => 'v12'
},
}
},
'secondElem' => {
'anything' => {
'3' => {
'value1' => 'v31',
'value2' => 'v32'
},
'2' => {
'value1' => 'v21',
'value2' => 'v22'
}
}
}
};
I wonder whether I am doing something fundamentally wrong, as I have
looked into lots of FAQs and into the documentation of XML::Simple, but
could not figure out any option to generate the output the way I need it.
Kind regards
Wolfgang
[snip]
What is XMLin?
This Perl script fails to run:
Cannot parse test.xml: Undefined subroutine &main::XMLin called at
newscript1.cgi line 6.
[snip]
> How can I force XMLin to generate a hash for id = '1'
[more snippage]
> I wonder whether I am doing something fundamentally wrong, as I have
> looked into lots of FAQs and into the documentation of XML::Simple, but
> could not figure out any option to generate the output the way I need it.
>
You want the 'ForceArray' option:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use XML::Simple;
my $xml = XMLin(
\*DATA,
ForceArray => ['anything'],
KeyAttr => ['id'],
);
print Dumper($xml);
__DATA__
<test>
<firstElem>
<anything id="1" value1="v11" value2="v12"/>
</firstElem>
<secondElem>
<anything id="2" value1="v21" value2="v22"/>
<anything id="3" value1="v31" value2="v32"/>
</secondElem>
</test>
> Kind regards
> Wolfgang
Greetings,
Andreas Pürzer
--
Have Fun,
and if you can't have fun,
have someone else's fun.
The Beautiful South
Sorry for the inconvenience
Wolfgang
This generates exactly the output, that I expected. Thank you!
But honestly, I do not understand why: From the description of this
option I would expect that this option creates arrays, which I do not
want. But used, as you proposed, the option does not create arrays, but
the hash I was missing.
KeyAttr controls how arrays are turned into hashes. But if there is no
array there, it won't be turned into a hash. So you have to force
single-element entries to be treated as an array of 1, so it can then be
detected and folded into a hash.
The docs are kind of written from the package creator's perspective rather
than the user's perspective. Unless you know that arrays are an
intermediate step between XML and final hash-based output, it is rather
confusing to have to think about arrays that are behind the scene which you
never see. (But on the other hand, the docs do tell you that you should
almost always have ForceArray on, and that having the default be for it to
be off was a mistake.)
Xho
--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
Xho, thanks for explaining the non-obvious aspects of the documentation.