Reputation: 11
I am new to Perl. I am trying to loop for each entry in xml file to perform a task but it's dying with "not an array reference at line 9".
My script is
#!/usr/bin/perl
# use module
use XML::Simple;
# create object
$xml = new XML::Simple;
# read XML file
$data = $xml->XMLin("data.xml");
# access XML data
foreach my $entry (@{$data->{entry}}){
print $entry->{'source-translation'}->{'static-ip'}-{'translated-address'};
}
My XML file data is
<?xml version="1.0"?>
<config version="6.0.0" urldb="paloaltonetworks">
<entry name="DROP NAT">
<source-translation>
<static-ip>
<bi-directional>yes</bi-directional>
<translated-address>192.91.75.129</translated-address>
</static-ip>
</source-translation>
<to>
<member>Outside</member>
</to>
<from>
<member>DROP</member>
</from>
<source>
<member>192.91.66.72</member>
</source>
<destination>
<member>any</member>
</destination>
<service>any</service>
<description>NAT for DROP FTP Server</description>
<to-interface>ethernet1/1</to-interface>
<nat-type>ipv4</nat-type>
</entry>
<entry name="SDROP NAT">
<source-translation>
<static-ip>
<bi-directional>yes</bi-directional>
<translated-address>192.91.75.154</translated-address>
</static-ip>
</source-translation>
<to>
<member>Outside</member>
</to>
<from>
<member>DROP</member>
</from>
<source>
<member>192.91.66.79</member>
</source>
<destination>
<member>any</member>
</destination>
<service>any</service>
<description>NAT for SFTP server SDROP</description>
<to-interface>ethernet1/1</to-interface>
<nat-type>ipv4</nat-type>
</entry>
</config>
I want to list translated-address in each entry. Assume there are lot of entries like this. Please help me.
Upvotes: 0
Views: 97
Reputation: 53478
Here is your problem:
use XML::Simple;
XML::Simple
misleads you. It isn't simple at all. Unless you have absolutely no choice (and you probably do - it isn't core) then using another parser gives less pain.
Like:
use XML::Twig;
print $_ -> trimmed_text,"\n" for XML::Twig -> new -> parsefile ( 'data.xml') -> get_xpath ( '//translated-address');
expanded out that's more like:
use strict ;
use warnings;
my $twig = XML::Twig -> new;
$twig -> parsefile ( 'data.xml');
foreach my $entry ( $twig -> findnodes ('//entry')) {
print $entry -> first_child('source-translation') -> first_child('static-ip') -> first_child_text('translated-address');
}
Upvotes: 0
Reputation: 385496
The default value for the KeyAttr
option is
KeyAttr => [qw( name key id )]
That means that XML::Simple will convert
[ { name => $name1, ... }, { name => $name2, ... }, ... ]
into
{ $name1 => { ... }, $name2 => { ... }, ... }
You could use the following option to the get the structure you expect.
KeyAttr => []
Don't forget to also provide the following option if you want your code to work when only one entry is present:
ForceArray => [qw( entry )]
The use of XML::Simple is discouraged, even by its own documentation.
XML::LibXML solution:
use XML::LibXML qw( );
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('data.xml');
for my $node ($doc->findnodes(
'/config/entry/source-translation/static-ip/translated-address'
)) {
print($node->textContent(), "\n");
}
Upvotes: 1
Reputation: 4285
As you stated $data->{entry}
is not an array reference in your data structure; it is a hash reference.
Check the script below, it accesses the data in the hash:
#!/usr/bin/perl
use v5.10; use strict; use warnings;
use XML::Simple;
my $xml = new XML::Simple;
my $data = $xml->XMLin("data.xml");
for my $entry (keys %{$data->{entry}}){
say $data->{entry}->{$entry}->{'source-translation'}->{'static-ip'}->{'translated-address'};
}
And as Сухой27 pointed out; if you'd use Data::Dumper you'd be able to see the data structure and you'd see the hash instead of your assumed array.
Upvotes: 0