1

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.

Input.csv (Name, IP Address)

LAB-1,10.26.0.1
LAB-2,10.26.0.2
LAB-3,10.26.0.3

template.xml

<?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?

1
  • Your program logic is wrong: You are creating object $tree outside the loop. Then you are creating, modifying and without doing anything useful discarding $contree. Finally you are printing the original unmodified $tree object as XML. Commented Jan 31, 2018 at 16:37

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

2 Comments

Cool! Thank's, But how I read values from csv in your example?
Using Text::CSV as you are already doing. You see $name and $ip are inserted into the XML, right? You only have to set their values to be equal to those read from the CSV file.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.