Reputation: 87
I am creating an xml to pass to an API and the API returns this (data dumped):
(
"Data::Dump",
{
SiteDevices => {
"device" => {
1102 => { address => "1.2.3.4", riskfactor => "1.0", riskscore => "0.0" },
1136 => { address => "1.2.3.5", riskfactor => "1.0", riskscore => "0.0" },
20491 => { address => "1.2.3.6", riskfactor => "1.0", riskscore => "0.0" },
129644 => { address => "1.2.3.7", riskfactor => "1.0", riskscore => "0.0" },
129645 => { address => "1.2.3.8", riskfactor => "1.0", riskscore => "0.0" },
130408 => { address => "1.2.3.9", riskfactor => "1.0", riskscore => "0.0" },
135975 => { address => "1.2.3.10", riskfactor => "1.0", riskscore => "0.0" },
137642 => { address => "1.2.3.11", riskfactor => "1.0", riskscore => "0.0" },
},
"site-id" => 27,
},
success => 1,
},
)
I want to loop through and print the devices and IPs associated with them and I for the life of me can’t come up with any code to do it. What the heck am I missing?! I tried to loop through a hash, a hash of hashes, etc. Can never get it to work. If any of you have a second and can provide an answer so I can shake my head in shame that’d be awesome.
I have tried:
foreach my $key (keys %{ $output->{‘SiteDevices’}->{‘device’} }) {
print $key
print $key->{‘address’}
}
and
foreach my $key (keys %{ $output{‘SiteDevices’}{‘device’} }) {
print $key
print $key{‘address’}
}
but neither works.
Upvotes: 2
Views: 349
Reputation: 53488
You mention this is parsed XML. It looks like you've parsed it with XML::Simple
and that's just not a good idea.
Why not instead:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
## get xml somehow here. parsefile if it's a file already.
my $twig = XML::Twig -> new -> parse ( $your_xml );
foreach my $device ( $twig -> get_xpath('//devices' ) ) {
print $device -> att('name'), " => ";
print $device -> att('address'),"\n";
}
The useful thing here is xpath
- it's not a regular expression, but it's sort of similar - and it applies to XML. In this case //device
says 'find a <device>
node anywhere in the tree. (And then we extract attributes).
That may work for your scenario, but you can be more specific by specifying a longer path:
./device
- directly below the current node. .//device
- anywhere below the current node./root/SiteDevices/device
- nodes specifically matching this 'tree'. You can also use xpath
to search on attributes:
.//device[@name="1136"]
will find something with the appropriate value and attribute. See XML Twig quick reference for some guides on how to do this.
Upvotes: 6
Reputation: 9296
I believe the following loop will do what you are trying to accomplish. It fetches each device from the tree, then extracts out its address, and prints both:
for my $device (keys %{ $output->{SiteDevices}{device} }){
print "$device: $output->{SiteDevices}{device}{$device}{address}\n";
}
In your tests, you're trying to use the key name as a hash/hash reference, which won't work. You need to put the extracted key back into the hash to perform further extractions.
Output, based on the single record I extracted out of your question:
129644: 1.2.3.7
129645: 1.2.3.8
130408: 1.2.3.9
137642: 1.2.3.11
1136: 1.2.3.5
135975: 1.2.3.10
1102: 1.2.3.4
20491: 1.2.3.6
Upvotes: 2