perl script- to read many values from xml file - perl

how to read the multiple values from XML file using perl script?
i have the xml file like:
<Provisioning>
<Appliance>
<ID>1</ID>
<SiteID></SiteID>
<IPAddress>10.52.32.230</IPAddress>
</Appliance>
<Appliance>
<ID>1</ID>
<SiteID></SiteID>
<IPAddress>10.52.32.530</IPAddress>
</Appliance>
<Appliance>
<ID>1</ID>
<SiteID></SiteID>
<IPAddress>10.52.32.730</IPAddress>
</Appliance>...
</Provisioning>
and i have written the code like:
use XML::Simple;
use Data::Dumper;
my $xml = new XML::Simple;
my $peermas = $xml->XMLin($masapplications);
print "file contents: $peermas \n";
print Dumper($peermas);
#masipaddr =+ $peermas->{Appliance}->{IPAddress}; #{Provisioning}->{Appliance}->{IPAddress};
print "The MAS ip: #masipaddr \n";
i am very new to perl script and my code can read only one IP address not the remaining 2.
so what should i do in this case?? please reply soon...
thanks in advance.

You already have all info you need in your $peermas. But if you need array of your IP addressed you may use:
my #massipaddr = map { $_->{IPAddress} } #{ $peermas->{Appliance} };
This map iterate on array of hashes $peermas->{Appliance} and push each IPAddress from it into #massipaddr.

Something like this perhaps:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Simple;
my $xml = join '', <DATA>;
my $peermas = XMLin($xml);
foreach (#{$peermas->{Appliance}}) {
print $_->{IPAddress}. "\n";
}
__DATA__
<Provisioning>
<Appliance>
<ID>1</ID>
<SiteID></SiteID>
<IPAddress>10.52.32.230</IPAddress>
</Appliance>
<Appliance>
<ID>1</ID>
<SiteID></SiteID>
<IPAddress>10.52.32.530</IPAddress>
</Appliance>
<Appliance>
<ID>1</ID>
<SiteID></SiteID>
<IPAddress>10.52.32.730</IPAddress>
</Appliance>...
</Provisioning>

Related

Which syntax is better XML::Simple or XML::Twig

I was running a Perl script and I encountered the following result, instead of the answer I expected.
input HASH(0x17268bb0)
input HASH(0x172b3300)
input HASH(0x172b32a0)
Can anyone say what this is and how to rectify it?
This is my XML file here
<Root>
<Top name="ri_32">
<Module name="ALU">
<input name="power_control_bus"/>
<bidirection name="address_bus"/>
</Module>
<Module name="Power_control">
<input name="cpu_control_bus"/>
<output name="power_control_bus"/>
<bidirection name="address_bus"/>
</Module>
<input name="address"/>
<input name="clock"/>
<input name="data_in"/>
<output name="data_out"/>
<bidirection name="control"/>
</Top>
</Root>
I'm writing a Perl script which can be converted into a specific requirement (.v, .sv file)
use strict;
use XML::Simple;
use Data::Dumper;
my $xml_root = XMLin( './simodule.xml' );
my $root_top = $xml_root->{Top};
my $mod = $root_top->{Module};
print "Top $root_top->{name}\n";
my $top_in = $root_top->{input};
foreach my $namein ( keys %$top_in ) {
print " input $top_in->{$namein}\n";
}
my $top_ou = $root_top->{output};
foreach my $nameou ( keys %$top_ou ) {
print " output $top_ou->{$nameou}\n";
}
my $top_bi = $root_top->{bidirection};
foreach my $namebi ( keys %$top_bi ) {
print " bidirection $top_bi->{$namebi}\n";
}
output:
Top risc_32
input HASH(0x172b3300)
input HASH(0x172b32a0)
input HASH(0x17268bb0)
output data_out
bidirection control
Expected output
input address
input clock
input data_in
output data_out
bidirection control
You've made your task more difficult for yourself by using one of the most deceitful modules on CPAN. XML::Simple isn't simple.
But it's docs also suggest not using it:
Why is XML::Simple "Discouraged"?
So - how about instead, XML::Twig:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
#$twig now contains our XML data structure.
my $twig = XML::Twig->new->parsefile('simodule.xml');
#fetch a value with an xpath expression - ./Top
#then extract the attribute 'name' from this node.
print "Top ", $twig->get_xpath( './Top', 0 )->att('name'), "\n";
#iterate all 'input' elements beneath "Top":
#note - single argument to "get_xpath" means all of them in a list.
foreach my $input ( $twig->get_xpath('./Top/input') ) {
#retrieve from each their name attribute (and print)
print "input ", $input->att('name'), "\n";
}
#locate the 'output' and 'bidirection' nodes within the tree, and fetch
#their name attribute.
print "output ", $twig -> get_xpath( './Top/output',0) -> att('name'),"\n";
print "bidirection ", $twig -> get_xpath( './Top/bidirection',0) -> att('name'),"\n";
We use XML::Twig which makes use of get_xpath to specify an XML path. We also use att to retrieve a named attribute. You could use iterators such as first_child and children if you prefer though:
#Top element is below the root - we create a reference to it $top
my $top = $twig->root->first_child('Top');
#From this reference, fetch the name attribute.
print "Top ", $top->att('name'), "\n";
#get children of Top matching 'input' and iterate
foreach my $input ( $top -> children('input') ) {
#print attribute called 'name'.
print "input ", $input->att('name'), "\n";
}
#Find a child below Top called 'output' and retrieve 'name' attribute.
print "output ", $top -> first_child('output') -> att('name'),"\n";
#as above.
print "bidirection ", $top -> first_child('bidirection') -> att('name'),"\n";
These are doing the same thing - personally I like xpath as a way of navigating XML but that's a matter of taste. (It lets you do all sorts of things like specify a path with embedded attributes, that kind of thing - moot point in this example though).
Given your input XML, both produce:
Top ri_32
input address
input clock
input data_in
output data_out
bidirection control
it skips the nested hashes for ALU and Power_Control because your original code appears to.
You still haven't been at all clear about exactly what output you want. But I use XML::LibXML for most of my XML processing requirements and I'd write something like this:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use XML::LibXML;
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('simodule.xml');
foreach my $type (qw[input output bidirection]) {
foreach ($doc->findnodes("/Root/Top/$type")) {
say $_->nodeName, ' ', $_->getAttribute('name');
}
}
The output is correct.
As we don't know what exactly you need,
I modify your code to following so maybe you can figure out why you see the HASH and how to de-reference it by yourself, it's pretty simple:
use strict;
use XML::Simple;
use Data::Dumper;
local $/;
my $xml_root = XMLin(<DATA>);
print Dumper $xml_root;
my $root_top=$xml_root->{Top};
my $mod=$root_top->{Module};
print "Top $root_top->{name}\n";
my $top_in=$root_top->{input};
foreach my $namein (keys %$top_in)
{
print " input" , Dumper $top_in->{$namein};
}
my $top_ou=$root_top->{output};
foreach my $nameou (keys %$top_ou)
{
print " output $top_ou->{$nameou}\n";
}
my $top_bi=$root_top->{bidirection};
foreach my $namebi (keys %$top_bi)
{
print " bidirection $top_bi->{$namebi}\n";
}
__DATA__
<Root>
<Top name="ri_32">
<Module name="ALU">
<input name="power_control_bus"/>
<bidirection name="address_bus"/>
</Module>
<Module name="Power_control">
<input name="cpu_control_bus"/>
<output name="power_control_bus"/>
<bidirection name="address_bus"/>
</Module>
<input name="address">X</input>
<input name="clock"/>
<input name="data_in"/>
<output name="data_out"/>
<bidirection name="control"/>
</Top>
</Root>

perl script to iterate over xml nodes using XML::LibXML

I am trying to come up with a perl script to iterate over some nodes and get values in xml file.
My XML File looks like below and is saved spec.xml
<?xml version="1.0" encoding="UTF-8"?>
<WO xmlns="http://www.example.com/yyyy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<WOSet>
<SR>
<FINISHTIME>2013-07-29T18:21:38-05:00</FINISHTIME>
<STARTTIME xsi:nil="true" />
<TYPE>SR</TYPE>
<DESCRIPTION>Create CUST</DESCRIPTION>
<EXTERNALSYSTEMID />
<REPORTEDBY>PCAUSR</REPORTEDBY>
<REPORTEDEMAIL />
<STATUS>RESOLVED</STATUS>
<SRID>1001</SRID>
<UID>1</UID>
<SPEC>
<AVALUE>IT</AVALUE>
<ATTRID>CUST_DEPT</ATTRID>
<NALUE xsi:nil="true" />
<TVALUE />
</SPEC>
<SPEC>
<AVALUE>001</AVALUE>
<ATTRID>DEPT_CODE</ATTRID>
<NVALUE xsi:nil="true" />
<TVALUE />
</SPEC>
</SR>
</WOSet>
</WO>
when I run the below script , I neither get the output nor any error to get clue on where to fix things...
I am not a perl expert , would love experts here to through some light...
#!/usr/bin/perl
use XML::LibXML;
use strict;
use warnings;
my $file = 'spec.xml';
my $parser = XML::LibXML->new();
my $tree = $parser->parse_file($file);
my $root = $tree->getDocumentElement;
foreach my $atrid ( $tree->findnodes('WO/WOSet/SR/SPEC') ) {
my $name = $atrid->findvalue('ATTRID');
my $value = $atrid->findvalue('AVALUE');
print $name
print " = ";
print $value;
print ";\n";
}
My expected output is
CUST_DEPT = IT
DEPT_CODE = 001
The XML doesn't contain any element named WO in the null namespace. You want to match the elements named WO in the http://www.example.com/yyyy namespace.
#!/usr/bin/perl
use strict;
use warnings;
use XML::LibXML qw( );
use XML::LibXML::XPathContext qw( );
my $file = 'spec.xml';
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file($file);
my $root = $doc->getDocumentElement;
my $xpc = XML::LibXML::XPathContext->new($doc);
$xpc->registerNs(y => 'http://www.example.com/yyyy');
for my $atrid ( $xpc->findnodes('y:WO/y:WOSet/y:SR/y:SPEC') ) {
my $name = $xpc->findvalue('y:ATTRID', $atrid);
my $value = $xpc->findvalue('y:AVALUE', $atrid);
print "$name = $value\n";
}

XML reading using Perl

I am new to the Perl language. I have an XML like,
<xml>
<date>
<date1>2012-10-22</date1>
<date2>2012-10-23</date2>
</date>
</xml>
I want to parse this XML file & store it in array. How to do this using perl script?
Use XML::Simple - Easy API to maintain XML (esp config files) or
see XML::Twig - A perl module for processing huge XML documents in tree mode.
Example like:
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
my $xml = q~<xml>
<date>
<date1>2012-10-22</date1>
<date2>2012-10-23</date2>
</date>
</xml>~;
print $xml,$/;
my $data = XMLin($xml);
print Dumper( $data );
my #dates;
foreach my $attributes (keys %{$data->{date}}){
push(#dates, $data->{date}{$attributes})
}
print Dumper(\#dates);
Output:
$VAR1 = [
'2012-10-23',
'2012-10-22'
];
Here's one way with XML::LibXML
#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;
my $doc = XML::LibXML->load_xml(location => 'data.xml');
my #nodes = $doc->findnodes('/xml/date/*');
my #dates = map { $_->textContent } #nodes;
Using XML::XSH2, a wrapper around XML::LibXML:
#!/usr/bin/perl
use warnings;
use strict;
use XML::XSH2;
xsh << '__XSH__';
open 2.xml ;
for $t in /xml/date/* {
my $s = string($t) ;
perl { push #l, $s }
}
__XSH__
no warnings qw(once);
print join(' ', #XML::XSH2::Map::l), ".\n";
If you can't/don't want to use any CPAN mod:
my #hits= $xml=~/<date\d+>(.+?)<\/date\d+>/
This should give you all the dates in the #hits array.
If the XML isn't as simple as your example, using a XML parser is recommended, the XML::Parser is one of them.

perl parsing using sax

I would like to write a xml parsing script in Perl that prints all the firstname values from the following xml file using XML::SAX module.
<employees>
<employee>
<firstname>John</firstname>
<lastname>Doe</lastname>
<age>gg</age>
<department>Operations</department>
<amount Ccy="EUR">100</amount>
</employee>
<employee>
<firstname>Larry</firstname>
<lastname>Page</lastname>
<age>45</age>
<department>Accounts</department>
<amount Ccy="EUR">200</amount>
</employee>
<employee>
<firstname>Harry</firstname>
<lastname>Potter</lastname>
<age>50</age>
<department>Human Resources</department>
<amount Ccy="EUR">300</amount>
</employee>
</employees>
Can anyone help me with sample script?
I am a new to Perl.
Here's an example using XML::SAX. I've used XML::SAX::PurePerl.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use XML::SAX::ParserFactory;
use XML::SAX::PurePerl;
my $characters;
my #firstnames;
my $factory = new XML::SAX::ParserFactory;
#Let's see which handlers we have available
#print Dumper $factory;
my $handler = new XML::SAX::PurePerl;
my $parser = $factory->parser(
Handler => $handler,
Methods => {
characters => sub {
$characters = shift->{Data};
},
end_element => sub {
push #firstnames, $characters if shift->{LocalName} eq 'firstname';
}
}
);
$parser->parse_uri("sample.xml");
print Dumper \#firstnames;
Output:
$VAR1 = [
'John',
'Larry',
'Harry'
];
I use $characters to hold character data, and push its contents onto #firstnames whenever I see a closing firstname tag.
Do you have any reason to stick with XML::Sax; If not then probably you can look for some other XML parsers in Perl (XML::Twig, XML::LibXML, XML::LibXMLReader, XML::Simple) and many more.
Here is a sample code to retrieve the firstname using XML::Twig.
use XML::Twig;
my $twig = XML::Twig->new ();
$twig->parsefile ('sample.xml');
my #firstname = map { $_->text } $twig->findnodes ('//firstname');

How can I use Perl's XML::LibXML to extract an attribute in a tag?

I have an XML file
<PARENT >
<TAG string1="asdf" string2="asdf" >
</TAG >
</PARENT>
I want to extract the string2 value here.. and also I want to set it to a new value..
How to do that?
Use XPath expressions
use strict;
use warnings;
use XML::LibXML;
use Data::Dumper;
my $doc = XML::LibXML->new->parse_string(q{
<PARENT>
<TAG string1="asdf" string2="asdfd">
</TAG>
</PARENT>
});
my $xpath = '/PARENT/TAG/#string2';
# getting value of attribute:
print Dumper $doc->findvalue($xpath);
my ($attr) = $doc->findnodes($xpath);
# setting new value:
$attr->setValue('dfdsa');
print Dumper $doc->findvalue($xpath);
# do following if you need to get string representation of your XML structure
print Dumper $doc->toString(1);
And read documentation, of course :)
You could use XML::Parser to get the value as well. For more information refer to the XML::Parser documentation:
#!/usr/local/bin/perl
use strict;
use warnings;
use XML::Parser;
use Data::Dumper;
my $attributes = {};
my $start_handler = sub
{
my ( $expat, $elem, %attr ) = #_;
if ($elem eq 'TAG')
{
$attributes->{$attr{'string1'}} = 'Found';
}
};
my $p1 = new XML::Parser(
Handlers => {
Start => $start_handler
}
);
$p1->parsefile('test.xml');
print Dumper($attributes);
I think you might be better off starting with XML::Simple and playing around a little first:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Simple;
my $xml = XMLin(\*DATA);
print $xml->{TAG}->{string2}, "\n";
$xml->{TAG}->{string2} = "asdf";
print XMLout( $xml, RootName => 'PARENT');
__DATA__
<PARENT>
<TAG string1="asdf" string2="value of string 2">
</TAG>
</PARENT>
Thanks for your responses. I found another answer in "Config file processing with LibXML2" which I found very useful.