Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Accessing attributes in XML::Simple

by sherab (Scribe)
on Dec 31, 2009 at 19:34 UTC ( #815113=perlquestion: print w/ replies, xml ) Need Help??
sherab has asked for the wisdom of the Perl Monks concerning the following question:

Hi folks, I am having an issue parsing XML using Perl's XML::Simple. The XML file I am parsing is below.... (It's called cars.xml)
<?xml version="1.0"?> <root> <unsold> <car> <model>Hyundai</model> <mileage>20000</mileage> </car> <car> <model>Jeep</model> <mileage>10000</mileage> </car> </unsold> <footnotes> <footnote id = "F1">F1 text</footnote> <footnote id = "F2">F2 text</footnote> </footnotes> </root>
Using Data::Dumper on this yields....
$VAR1 = { 'unsold' => { 'car' => [ { 'model' => 'Hyundai', 'mileage' => '20000' }, { 'model' => 'Jeep', 'mileage' => '10000' } ] }, 'footnotes' => { 'footnote' => { 'F2' => { 'content' => 'F2 text' }, 'F1' => { 'content' => 'F1 text' } } } };
The script I am using is below....
#!/usr/bin/perl use XML::Simple; use Data::Dumper; $xml = new XML::Simple; $data = $xml->XMLin("cars.xml", forcearray => ['footnote', 'car', 'id' +]) or die "Sorry no can do:$!"; #$data = $xml->XMLin("cars.xml") or die "Sorry no can do:$!"; print Dumper($data); exit; foreach $e (@{$data->{unsold}{car}}) { print "$e->{model}"; print "$e->{mileage}"; } foreach $e (@{$data->{footnotes}}) { print "$e->{footnote}{content}\n"; }
Running code yields this....
Hyundai
20000
Jeep
10000
Not an ARRAY reference at ./node_test2.pl line 15


What I like about the above is that referencing model and mileage info is easy using the foreach routine above. What I need to do is to equally access the attributes of "id" and "content" in an equally simple way. Of course I may just need to use something else besides XML::Simple too but I thought I'd see if the monks had any ideas.

Comment on Accessing attributes in XML::Simple
Select or Download Code
Re: Accessing attributes in XML::Simple
by toolic (Chancellor) on Dec 31, 2009 at 20:09 UTC
    Since you seem open to altenative modules, consider XML::Twig:
    use strict; use warnings; use XML::Twig; my $xfile = <<EOF; <?xml version="1.0"?> <root> <unsold> <car> <model>Hyundai</model> <mileage>20000</mileage> </car> <car> <model>Jeep</model> <mileage>10000</mileage> </car> </unsold> <footnotes> <footnote id = "F1">F1 text</footnote> <footnote id = "F2">F2 text</footnote> </footnotes> </root> EOF my $t= new XML::Twig(); $t->parse($xfile); for my $car ($t->root()->first_child('unsold')->children('car')) { print $car->first_child('model' )->text(), "\n"; print $car->first_child('mileage')->text(), "\n"; } for my $fnote ($t->root()->first_child('footnotes')->children('footnot +e')) { print $fnote->text(), "\n"; print $fnote->att('id'), "\n"; } __END__ Hyundai 20000 Jeep 10000 F1 text F1 F2 text F2
Re: Accessing attributes in XML::Simple
by ikegami (Pope) on Dec 31, 2009 at 20:32 UTC
    To use
    foreach $e (@{$data->{footnotes}}) { print "$e->{footnote}{content}\n"; }

    You'd need to specify KeyAttr => [].

    With the default KeyAttr => [qw( name key id )], the above should be

    my $footnotes = $data->{footnotes}{footnote}; foreach my $id (keys %$footnotes) { print "$footnotes->{$id}{content}\n"; }
    or
    my $footnotes = $data->{footnotes}{footnote}; foreach my $footnote (values %$footnotes) { print "$footnote->{content}\n"; }

    Don't forget ForceArray => [qw( car footnote )]. XML::Simple is the hardest XML parser to use :(

    By the way, if you used GroupTags => { footnotes => 'footnote' }, you could write ->{footnotes}{footnote} as just ->{footnotes}

      Considering the size of XML::Simple's docs (including all those options people tend to babble about as making XML::Simple complex) is about one tenth of the size of say XML::LibXML's (even if we ignore SAX and the fact that you have to learn XPath from some other document), I find your statement fairly ... interesting.

      XML::Simple is so simple that people tend to forget they have to set the options right. That's its only problem. Other than that for a reasonably designed data-centric XML of reasonable size, it's the easiest. If for no reason than because it doesn't force you to learn yet another set of method names to navigate what's basically just a tree data structure.

      Jenda
      Enoch was right!
      Enjoy the last years of Rome.

      Your example works GREAT for me ikegami. What I'm puzzled by now is how to refer to values of "F1", "F2", etc of the XML. The "id=" portion of the iteration. My apologies but I have been doing this for so long my brain is tapioca.

        In the first snippet, $e->{footnote}{id}

        In the second snippet, $id

        In the third snippet, you can't.

        Oh Jeeez,... I should probably stop for the night. The answer is "$id". Can't believe I asked the question. Sorry folks!
Re: Accessing attributes in XML::Simple
by gube (Parson) on Dec 31, 2009 at 20:33 UTC

    Hi,

    You can do in XML Simple itself by passing KeyAttr => 1. Hope using for loop you can take the value of id.

    #!/usr/bin/perl use strict; use warnings; use XML::Simple; use Data::Dumper; my $xml_simple = XML::Simple->new( KeepRoot => 1, KeyAttr => 1, For +ceArray => 1 ); my $response_hash = eval{ $xml_simple->XMLin( "cars.xml" ) }; print Dumper($response_hash); Output : $VAR1 = { 'root' => [ { 'unsold' => [ { 'car' => [ { 'model' => [ 'Hyundai' ], 'mileage' => [ '20000' ] }, { 'model' => [ 'Jeep' ], 'mileage' => [ '10000' ] } ] } ], 'footnotes' => [ { 'footnote' => [ { 'content' => 'F +1 text', 'id' => 'F1' }, { 'content' => 'F +2 text', 'id' => 'F2' } ] } ] } ] };

      KeyAttr => 1 is wrong. The value should be an array ref or a hash ref. In this case, you want KeyAttr => []

      ForceArray => 1 is overkill. ForceArray => [qw( car footnote )] would be more appropriate

        You are right ikegami. If array ref i totally agree to you.

        Thanks,

        Gubs

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://815113]
Approved by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2014-08-01 04:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (256 votes), past polls