Reputation: 145
I am trying to write a value to an XML file. I have a CSV input file Input.xsv
and an XML template file template.xml
which I need to update with the Name and IP Address values from the CSV file.
LAB-1,10.26.0.1
LAB-2,10.26.0.2
LAB-3,10.26.0.3
<?xml version="1.0" encoding="UTF-8"?>
<ns0:networkdevice
xmlns:ns0="network.ers.ise.cisco.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ns1="ers.ise.cisco.com"
xmlns:ers="ers.ise.cisco.com"
name="name1">
<authenticationSettings>
<enableKeyWrap>true</enableKeyWrap>
<keyEncryptionKey>1234567890123456</keyEncryptionKey>
<keyInputFormat>ASCII</keyInputFormat>
<networkProtocol>RADIUS</networkProtocol>
<radiusSharedSecret>aaa</radiusSharedSecret>
</authenticationSettings>
<coaPort>1700</coaPort>
<NetworkDeviceIPList>
<NetworkDeviceIP>
<ipaddress>1.1.1.1</ipaddress>
<mask>32</mask>
</NetworkDeviceIP>
</NetworkDeviceIPList>
</ns0:networkdevice>
I want to read names and IP addresses from the CSV file and to write them into my XML template file to create an HTTP POST request for each device in the CSV file.
I tried to save the values in my XML template, but I'm not sure if I'm doing it right.
#!/usr/bin/perl
use warnings;
use strict;
use Text::CSV;
use XML::TreeBuilder;
use Data::Dumper;
my $xmlbase = 'template.xml';
my $paramsfile = 'input.csv';
# The list of tags filled from the CSV file
my @taglist = qw( name ipaddress );
my $tree = XML::TreeBuilder->new();
$tree->parsefile($xmlbase);
my $csv = Text::CSV->new();
open my $fh, "<:encoding(utf8)", $paramsfile or die "$paramsfile: $!";
while ( my $row = $csv->getline($fh) ) {
my $contree = XML::TreeBuilder->new();
$contree->parsefile($xmlbase);
my $index = 0;
for my $tagname ( @taglist ) {
my $tag = $contree->look_down('_tag' => $tagname);
$tag->push_content($row->[$index++]);
}
}
print '<?xml version="1.0" encoding="UTF-8"?>'."\n";
print $tree->as_XML();
After I run my script I get this error:
Can't locate object method "push_content"in this line
This error refers to the statement $tag->push_content($row->[$index++]);
. I think it is because name
does not have its own tag.
This element I have here:
<ns0:networkdevice
xmlns:ns0="network.ers.ise.cisco.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ns1="ers.ise.cisco.com"
xmlns:ers="ers.ise.cisco.com"
name="name1">
in tag ns0:networkdevice
When I try with just ipaddress
it is printed, but with the original value from template.xml
. It does not take a value from Input.csv
, and if it was empty, it stays empty.
How should I do this?
Upvotes: 1
Views: 875
Reputation: 10244
An easy way to generate XML from Perl is to use XML::FromPerl.
The template is replaced by a Perl data structure embedded in your code:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use XML::FromPerl qw(xml_from_perl);
my $name = 'LAB-1';
my $ip = '10.26.0.1';
my $xml = xml_from_perl
[ 'ns0:networkdevice' => { 'xmlns:ns0' => 'network.ers.ise.cisco.com',
'xmlns:xs' => 'http://www.w3.org/2001/XMLSchema',
'xmlns:ns1' => 'ers.ise.cisco.com',
'xmlns:ers' => 'ers.ise.cisco.com',
name => $name },
[ authenticationSettings =>
[ enableKeyWrap => 'true' ],
[ keyEncryptionKey => '1234567890123456' ],
[ keyInputFormat => 'ASCII' ],
[ networkProtocol => 'RADIUS' ],
[ radiusSharedSecret => 'aaa' ] ],
[ coaPort => '1700' ],
[ NetworkDeviceIPList =>
[ NetworkDeviceIP =>
[ ipaddress => $ip ],
[ mask => 32 ] ] ] ];
say $xml->toString(1);
Upvotes: 1
Reputation: 53478
I'm not familiar enough with XML::Treebuilder
so will give an example in XML::Twig
. I will also avoid Text::CSV
because I think it's overkill for most CSV use cases (e.g. any time you're not worrying about quoting/multi-line).
But it would go something like this:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $xml = XML::Twig -> new -> parsefile ( 'template.xml' );
$xml ->set_pretty_print('indented_a');
open ( my $input, '<', 'input.csv' ) or die $!;
while ( <$input> ) {
chomp;
my ( $name, $ip ) = split /,/;
$xml -> root -> set_att('name', $name );
$xml -> get_xpath('//ipaddress',0) -> set_text($ip);
$xml -> print;
}
For the last line of your CSV, this will generate:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:networkdevice
name="LAB-3"
xmlns:ers="ers.ise.cisco.com"
xmlns:ns0="network.ers.ise.cisco.com"
xmlns:ns1="ers.ise.cisco.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<authenticationSettings>
<enableKeyWrap>true</enableKeyWrap>
<keyEncryptionKey>1234567890123456</keyEncryptionKey>
<keyInputFormat>ASCII</keyInputFormat>
<networkProtocol>RADIUS</networkProtocol>
<radiusSharedSecret>aaa</radiusSharedSecret>
</authenticationSettings>
<coaPort>1700</coaPort>
<NetworkDeviceIPList>
<NetworkDeviceIP>
<ipaddress>10.26.0.3</ipaddress>
<mask>32</mask>
</NetworkDeviceIP>
</NetworkDeviceIPList>
</ns0:networkdevice>
Which looks like what you're after?
You'd be wanting $xml -> sprint
if you're wanting to include it in a POST
or similar though.
Upvotes: 0