Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

how to update an xml file by read data from csv file

by Vijay81 (Acolyte)
on Nov 28, 2012 at 16:24 UTC ( #1006069=perlquestion: print w/ replies, xml ) Need Help??
Vijay81 has asked for the wisdom of the Perl Monks concerning the following question:

Hi All,

I am new to perl. am trying achive something wrt to xml file. I have input file that is an csv which has number of rows with data and have xml template file where in which i need to update the values read from csv file. am not sure where and how to update an xml file using csv file in perl. Can any one please help me out.

Input put file looks like : file name : abc.csv
protocol,host,port and commandline SSH,-P,22 103.243.543.233,erted SSH,-P,22 303.233.542.622,rrertd
Xml file looks like : Filename : std.xml
<!-- The following lines can be modified at your own risks. --> <configuration version="0.2.1.4" savepassword="True"> <root type="database" name="WSSS" expanded="True"> <container type="folder" name="CM" expanded="True"> <container type="folder" name="1-AD/M" expanded="True"> <connection type="PuTTY" name="WSSS"> <connection_info> <name>WSSSS</name> <protocol>SSH</protocol> <host>20.148.24.2</host> <port>22</port> <session>Default Settings</session> <commandline>EEREd</commandline> <description /> </connection_info> <login> <login /> <password /> <prompt /> </login> <timeout> <connectiontimeout>1000</connectiontimeout> <logintimeout>750</logintimeout> <passwordtimeout>750</passwordtimeout> <commandtimeout>750</commandtimeout> </timeout> <command> <command1 /> <command2 /> <command3 /> <command4 /> <command5 /> </command> <options> <loginmacro>False</loginmacro> <postcommands>False</postcommands> <endlinechar>10</endlinechar> </options> </connection> </root> </configuration>
In the above xml file, protocol,host,port and commandline tag values are updated from csv file. Output file which am looking for is :
<?xml version="1.0" encoding="utf-16"?> <!-- ****************************************************************- +-> <!-- * *- +-> <!-- * PuTTY Configuration Manager save file - All right reserved. *- +-> <!-- * *- +-> <!-- ****************************************************************- +-> <!-- The following lines can be modified at your own risks. --> <configuration version="0.2.1.4" savepassword="True"> <root type="database" name="WSSS" expanded="True"> <container type="folder" name="CM" expanded="True"> <container type="folder" name="1-AD/M" expanded="True"> <connection type="PuTTY" name="WSSS"> <connection_info> <name>WSSSS</name> <protocol>SSH</protocol> <host>103.243.543.233</host> <port>22</port> <session>Default Settings</session> <commandline>erted</commandline> <description /> </connection_info> <login> <login /> <password /> <prompt /> </login> <timeout> <connectiontimeout>1000</connectiontimeout> <logintimeout>750</logintimeout> <passwordtimeout>750</passwordtimeout> <commandtimeout>750</commandtimeout> </timeout> <command> <command1 /> <command2 /> <command3 /> <command4 /> <command5 /> </command> <options> <loginmacro>False</loginmacro> <postcommands>False</postcommands> <endlinechar>10</endlinechar> </options> </connection> <connection type="PuTTY" name="AWSA"> <connection_info> <name>AWSA</name> <protocol>SSH</protocol> <host>303.233.542.622</host> <port>22</port> <session>Default Settings</session> <commandline>rrertd</commandline> <description /> </connection_info> <login> <login /> <password /> <prompt /> </login> <timeout> <connectiontimeout>1000</connectiontimeout> <logintimeout>750</logintimeout> <passwordtimeout>750</passwordtimeout> <commandtimeout>750</commandtimeout> </timeout> <command> <command1 /> <command2 /> <command3 /> <command4 /> <command5 /> </command> <options> <loginmacro>False</loginmacro> <postcommands>False</postcommands> <endlinechar>10</endlinechar> </options> </connection> </root> </configuration>

Comment on how to update an xml file by read data from csv file
Select or Download Code
Re: how to update an xml file by read data from csv file
by bitingduck (Friar) on Nov 28, 2012 at 16:48 UTC

    Text::CSV makes reading and writing CSV files very easy. It has a simple example in the synopsis that will probably do what you need just by copying and changing the filename. That takes care of the first half of your problem.

    If you're always using exactly the same input XML file you can probably get away with using a regex (regex tutorial)) to search and replace the elements that you want to change-- simply read in the file as text, make the change, and write it out.

    If you start making a habit of modifying XML files, especially if they're variable and may be a little unpredictable, you'll probably want to look into XML::TreeBuilder or XML::LibXML

    Try putting something together yourself, and if you run into trouble, post back in this thread and show your code and describe what it's doing wrong

      Thanks bitingduck (Pilgrim) for you input. As you suggested i used Text::CSV module to read csv file.

      Main pl file :
      #!/usr/bin/perl use warnings; use strict; use warnings; use Text::CSV; my $file1 = 'C:\TR_Vijay\Automation\serverinput.csv'; my $csv = Text::CSV->new(); my @columns; open (CSV, "<", $file1) or die $!; while (<CSV>) { next if ($. == 0); if ($csv->parse($_)) { @columns = $csv->fields(); print "$columns[0] \n"; print "$columns[1] \n"; print "$columns[2] \n"; print "$columns[3] \n"; } else { my $err = $csv->error_input; print "Failed to parse line: $err"; } open my $file, '>>', 'result.xml' or die "Can't open file: $!"; print $file <<EOF <?xml version="1.0" encoding="UTF-8"?> <!-- <!*************************************************************** +*> --> <!-- <!* + *> --> <!-- <!* PuTTY Configuration Manager save file - All right reserved. +*> --> <!-- <!* +*> --> <!-- <!*************************************************************** +*> --> <!-- <!The following lines can be modified at your own risks.> --> <configuration version=$columns[0] savepassword="True"> <root type="database" name=$columns[1] expanded="True"> <container type="folder" name=$columns[2] expanded="True"> <container type="folder" name=$columns[3] expanded="True"> <connection type="PuTTY" name=$columns[4]> <connection_info> <name>$columns[4]</name> <protocol>SSH</protocol> <host>$columns[7]</host> <port>$columns[8]</port> <session>Default Settings</session> <commandline>$columns[10]</commandline> <description /> </connection_info> <login> </login> <timeout> <connectiontimeout>1000</connectiontimeout> <logintimeout>750</logintimeout> <passwordtimeout>750</passwordtimeout> <commandtimeout>750</commandtimeout> </timeout> <command> </command> <options> <loginmacro>False</loginmacro> <postcommands>False</postcommands> <endlinechar>10</endlinechar> </options> </connection> </root> </configuration> EOF ; } close CSV;
      I was able to achive almost expect for few things. Anyhelp would be much appreciated. Achieved so far : 1. able to read data from csv file 2. ouput the xml file with data read from csv file. Now Issues are : 1. Don't want to print first 7 lines of the xml format everytime. It should be printed only once at top of the file.
      <?xml version="1.0" encoding="UTF-8"?> <!-- <!*************************************************************** +*> --> <!-- <!* + *> --> <!-- <!* PuTTY Configuration Manager save file - All right reserved. +*> --> <!-- <!* +*> --> <!-- <!*************************************************************** +*> --> <!-- <!The following lines can be modified at your own risks.> -->
      2. Don't want to print last 2 line everytime. it just need to be printed only once at bottom of the file
      </root> </configuration>
      3. Not sure where i made mistake, but when ever i try to open the result.xml, it doesn't open. even program doesn't give any error thou.
        If you do not want to print the lines every time, move the corresponding print out of the loop.
        لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

        Here's a solution that uses XML::TreeBuilder (which uses XML::Element methods as well). It seemed easier than trying to build it up from print statements and regex replacements.

        One maybe major caveat: your example input file isn't valid XML-- the two "container" tags don't get closed. I took the liberty of assuming (maybe incorrectly) that they should get closed and that you want valid XML.

        Here's the code:
        #!/usr/bin/perl use warnings; use strict; use Text::CSV; use XML::TreeBuilder; use Data::Dumper; my $xmlbase='original.xml'; my $paramsfile = 'params.csv'; # the list of tags filled from the csv file my @taglist=qw(name protocol host commandline); # this is the part that repeats, so we break it out separately # the tags that get filled from the CSV file are left empty my $connection= <<END <connection type="PuTTY" name="WSSS"> <connection_info> <name></name> <protocol></protocol> <host></host> <port>22</port> <session>Default Settings</session> <commandline></commandline> <description /> </connection_info> <login> <login /> <password /> <prompt /> </login> <timeout> <connectiontimeout>1000</connectiontimeout> <logintimeout>750</logintimeout> <passwordtimeout>750</passwordtimeout> <commandtimeout>750</commandtimeout> </timeout> <command> <command1 /> <command2 /> <command3 /> <command4 /> <command5 /> </command> <options> <loginmacro>False</loginmacro> <postcommands>False</postcommands> <endlinechar>10</endlinechar> </options> </connection> END ; #this is the wrapper my $config= <<END <?xml version="1.0" encoding="UTF-8"?> <!-- The following lines can be modified at your own risks. --> <configuration version="0.2.1.4" savepassword="True"> <root type="database" name="WSSS" expanded="True"> <container type="folder" name="CM" expanded="True"> <container type="folder" name="1-AD/M" expanded="True"> </container> </container> </root> </configuration> END ; #start an xml structure with the outer wrapper my $tree=XML::TreeBuilder->new(); $tree->parse($config); # find the insert location my $container=$tree->look_down("_tag"=>"container", "name"=>"1-AD/M"); + my $csv=Text::CSV->new(); open my $fh, "<:encoding(utf8)", $paramsfile or die "$paramsfile: $!"; # loop through the lines of the CSV and copy the connection structure +into # the wrapper with the updated values while(my $row=$csv->getline($fh)){ my $contree=XML::TreeBuilder->new(); #make an xml structure of th +e connection $contree->parse($connection); $container->push_content($contree); #insert it into the wrapper $contree->attr('name',$row->[0]); #set the name attribute $container->push_content("\n "); #make it a little prettier my $index=0; for my $tagname(@taglist){ #loop through the columns 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();
        And here's the output:
        $ perl puttyconfig.pl <?xml version="1.0" encoding="UTF-8"?> <configuration savepassword="True" version="0.2.1.4"> <root expanded="True" name="WSSS" type="database"> <container expanded="True" name="CM" type="folder"> <container expanded="True" name="1-AD/M" type="folder"> <connection name="WSSSS" type="PuTTY"> <connection_info> <name>WSSSS</name> <protocol>SSH</protocol> <host>103.243.543.233</host> <port>22</port> <session>Default Settings</session> <commandline>erted</commandline> <description></description> </connection_info> <login> <login></login> <password></password> <prompt></prompt> </login> <timeout> <connectiontimeout>1000</connectiontimeout> <logintimeout>750</logintimeout> <passwordtimeout>750</passwordtimeout> <commandtimeout>750</commandtimeout> </timeout> <command> <command1></command1> <command2></command2> <command3></command3> <command4></command4> <command5></command5> </command> <options> <loginmacro>False</loginmacro> <postcommands>False</postcommands> <endlinechar>10</endlinechar> </options> </connection> <connection name="AWSA" type="PuTTY"> <connection_info> <name>AWSA</name> <protocol>SSH</protocol> <host>303.233.542.622</host> <port>22</port> <session>Default Settings</session> <commandline>rrertd</commandline> <description></description> </connection_info> <login> <login></login> <password></password> <prompt></prompt> </login> <timeout> <connectiontimeout>1000</connectiontimeout> <logintimeout>750</logintimeout> <passwordtimeout>750</passwordtimeout> <commandtimeout>750</commandtimeout> </timeout> <command> <command1></command1> <command2></command2> <command3></command3> <command4></command4> <command5></command5> </command> <options> <loginmacro>False</loginmacro> <postcommands>False</postcommands> <endlinechar>10</endlinechar> </options> </connection> </container> </container> </root> </configuration>

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1006069]
Approved by mbethke
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (15)
As of 2014-12-22 17:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (122 votes), past polls