Re: Is there any XML reader like this?
by toolic (Bishop) on Jan 13, 2012 at 22:04 UTC
|
I'm not sure why you don't think you can use XML::Simple to parse your XML file, but here is one way to print all ip's for station17, for example:
use warnings;
use strict;
use XML::Simple;
my $str = '
<servers>
<station18>
<ip>10.0.0.101</ip>
<ip>10.0.1.101</ip>
<ip>10.0.0.102</ip>
<ip>10.0.0.103</ip>
<ip>10.0.1.103</ip>
</station18>
<station19>
<ip>10.0.0.111</ip>
<ip>10.0.1.111</ip>
<ip>10.0.0.112</ip>
<ip>10.0.0.113</ip>
<ip>10.0.1.113</ip>
</station19>
<station17>
<ip>10.0.0.121</ip>
<ip>10.0.1.121</ip>
<ip>10.0.0.122</ip>
<ip>10.0.0.123</ip>
<ip>10.0.1.123</ip>
</station17>
</servers>
';
my $xml = XMLin($str);
print "$_\n" for @{ $xml->{station17}{ip} };
__END__
10.0.0.121
10.0.1.121
10.0.0.122
10.0.0.123
10.0.1.123
See also:
| [reply] [d/l] |
|
toolic,
I have been using your code and which uses Simple::XML but now I am unable to retrieve the "ip" with the same code:
print "CMD:",@{ $xml->{$server}{ip} },"\n";
This is printing nothing.
And I have my XML file with server like:
<station19>
<ip>10.0.1.113</ip>
</station19>
Anything missing here?
Thanks,
Ashok | [reply] [d/l] [select] |
|
| [reply] |
Re: Is there any XML reader like this?
by BrowserUk (Pope) on Jan 13, 2012 at 22:10 UTC
|
C:\test>junk44
{
station17 => {
ip => [
"10.0.0.121",
"10.0.1.121",
"10.0.0.122",
"10.0.0.123",
"10.0.1.123",
],
},
station18 => {
ip => [
"10.0.0.101",
"10.0.1.101",
"10.0.0.102",
"10.0.0.103",
"10.0.1.103",
],
},
station19 => {
ip => [
"10.0.0.111",
"10.0.1.111",
"10.0.0.112",
"10.0.0.113",
"10.0.1.113",
],
},
}
The program that produced the above from your sample data in the __DATA__: #! perl -slw
use strict;
use Data::Dump qw[ pp ];
use XML::Simple;
my $xml = XMLin( \*DATA );
pp $xml;
__DATA__
...
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
| [reply] [d/l] [select] |
Re: Is there any XML reader like this?
by tobyink (Abbot) on Jan 13, 2012 at 22:32 UTC
|
As always, I strongly recommend against XML::Simple. XML::Simple might seem simple until you end up in a situation where one of your stations has only a single IP address, and you end up with:
{
servers => {
station19 => {ip=>['10.10.10.1','10.10.10.2']},
station20 => {ip=>['10.10.10.3','10.10.10.4']},
station21 => {ip=>'10.10.10.5'}, # D'oh!
}
}
Notice that $hash->{servers}{station21}{ip} is not an arrayref, whereas the IP list is an arrayref for every other station.
OK, so you can configure XML::Simple to force the IP addresses to always be arrayrefs, but by the time you've thought through every possible permutation of your data, XML::Simple becomes not so simple any more.
Better to use a more powerful XML module, like XML::LibXML, which might seem more complicated to begin with, but is at least consistent.
use XML::LibXML;
my $xml = XML::LibXML->new->parse_fh(\*DATA);
foreach my $station ($xml->findnodes('/servers/*'))
{
printf("Station: %s\n", $station->tagName);
foreach my $ip ($station->findnodes('./ip'))
{
printf("\tIP: %s\n", $ip->textContent);
}
}
__DATA__
<servers>
<station18>
<ip>10.0.0.101</ip>
<ip>10.0.1.101</ip>
<ip>10.0.0.102</ip>
<ip>10.0.0.103</ip>
<ip>10.0.1.103</ip>
</station18>
<station19>
<ip>10.0.0.111</ip>
<ip>10.0.1.111</ip>
<ip>10.0.0.112</ip>
<ip>10.0.0.113</ip>
<ip>10.0.1.113</ip>
</station19>
<station17>
<ip>10.0.0.121</ip>
<ip>10.0.1.121</ip>
<ip>10.0.0.122</ip>
<ip>10.0.0.123</ip>
<ip>10.0.1.123</ip>
</station17>
<station20>
<!-- no IP addresses -->
</station20>
<station21>
<!-- just one IP address -->
<ip>10.2.1.123</ip>
</station21>
</servers>
| [reply] [d/l] [select] |
|
C:\test>junk44
#! perl -slw
use strict;
use Data::Dump qw[ pp ];
use XML::Simple;
my $xml = XMLin( \*DATA, ForceArray => 1 );
pp $xml;
__DATA__
<servers>
<station18>
<ip>10.0.0.101</ip>
<ip>10.0.1.101</ip>
<ip>10.0.0.102</ip>
<ip>10.0.0.103</ip>
<ip>10.0.1.103</ip>
</station18>
<station19>
<ip>10.0.0.111</ip>
<ip>10.0.1.111</ip>
<ip>10.0.0.112</ip>
<ip>10.0.0.113</ip>
<ip>10.0.1.113</ip>
</station19>
<station17>
<ip>10.0.0.121</ip>
</station17>
</servers>
Produces: {
station17 => [{ ip => ["10.0.0.121"] }],
station18 => [
{
ip => [
"10.0.0.101",
"10.0.1.101",
"10.0.0.102",
"10.0.0.103",
"10.0.1.103",
],
},
],
station19 => [
{
ip => [
"10.0.0.111",
"10.0.1.111",
"10.0.0.112",
"10.0.0.113",
"10.0.1.113",
],
},
],
}
Which is still far simpler than wasting your time trying to figure out how use those complex monsters.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
| [reply] [d/l] [select] |
|
use XML::Simple qw( :strict XMLin );
local $XML::Simple::PREFERRED_PARSER = 'XML::Parser';
my $stations = XMLin( \*DATA, ForceArray => 1, KeyAttr => [] );
for my $station_name (keys %$stations) {
say $station_name;
my $station = $stations->{$station_name}[0];
for my $ip (@{ $station->{ips} // [] }) {
say " $ip";
}
}
use XML::LibXML qw( );
my $root = XML::LibXML->load_xml( IO => \*DATA )->documentElement;
for my $station ($root->findnodes('*')) {
say $station->getName;
for my $ip ($station->findnodes('ip')) {
say " ".$ip->textContent;
}
}
And that's not even mentioning the fact that XML::LibXML is 20x faster* and able to handle so much more stuff than XML::Simple (including every day stuff).
* — That assumes XML::Parser is used as XML::Simple's backend. XML::LibXML is 10,000x faster than XML::Simple's common default of XML::SAX::PurePerl (which handles encodings really badly).
Update: Fixed an error in XML::Simple code.
Update: Fixed an error in XML::LibXML code. ("IO" was mispelled, and the XPath was wrong.)
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
|
|
|
|
<ip assignment="temporary">10.0.0.101</ip>
And then all your code which assumes stations have IP addresses which are arrayrefs of strings breaks again. | [reply] |
|
|
|
|
|
|
|
|
Re: Is there any XML reader like this?
by choroba (Bishop) on Jan 16, 2012 at 02:36 UTC
|
I usually use XML::XSH2 for XML manipualtion: open 947833.xml ;
for /servers/* echo name() ; # list stations
for /servers/station18/ip echo text(); # list ip's for statio
+n18
$station = 'station17' ;
for /servers/*[name()=$station]/ip echo text(); # list ip's for a stat
+ion given by a string var
| [reply] [d/l] |