0

Perl script to read property.xml and create install.properties file

how to read multiple lines and split keyName and keyValue

#!/usr/bin/perl
use strict;
use warnings;

open my $fh, '<', "property.xml"  or die "property.xml: $!";
open(CTS,">install.properties") or die $!;

while ( my $line = <$fh> ) {

if ($line =~ m/\<entry.*\<\/entry\>$/i ){     # how to read multiple line
my ($keyName, $keyValue) = split(//, $line);     # how to split 
print CTS $keyName = $keyValue;
}
}

property.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <entry key="TYPE">
    Rel
    </entry>
    <!-- tst  -->
    <entry key="LOCATION">
    C:/Rel-LOCATION
    </entry>
    <entry key="HOST">
    localhost
    </entry>    
</properties>

install.properties

TYPE = Rel
LOCATION = C:/Rel-LOCATION
HOST = localhost
3
  • 3
    So what's the question..? Commented Aug 14, 2013 at 5:46
  • 2
    1. That isn't XML, it would have a root element otherwise. 2. Just use an XML parser like XML::LibXML and extract your information via XPath expressions. Come back if you have problems with that. Commented Aug 14, 2013 at 5:48
  • 3
    Re: your updated question. Your problem could be solved by using regexes, but this is really poor style and is difficult to do correctly. Please, use an XML parser. This is really not hard, and can be done in less lines than your current code! Commented Aug 14, 2013 at 6:15

3 Answers 3

2

I would write the code somewhat like this, using XML::LibXML.

use strict;
use warnings;
use feature 'say';
use XML::LibXML;

# Parse the XML
my $xml = XML::LibXML->load_xml(location => 'test.xml');

# Iterate the entries
for my $entry ($xml->findnodes('/properties/entry')) {

    my $key = $entry->findvalue('@key');

    # trim the value
    s/\A\s*//, s/\s*\z// for my $value = $entry->textContent;

    say "$key = $value";
}

The statement s/\A\s*//, s/\s*\z// for my $value = $entry->textContent is a shorthand for

my $value = $entry->textContent;
$value =~ s/\A\s*//;
$value =~ s/\s*\z//;

The substitutions do the trimming; \A anchores at the start of string, \z at the end (and are roughly equivalent to ^ and $ resp.).

The say feature is available since perl5 v10, and offers the say function which works like print, but appends a newline.

Simple XPath expressions work just like file paths, but @key selects an attribute.

The various DOM node methods I used here are:

  • findnodes – get a list of nodes that match the XPath expression.
  • findvalue – get a node that matches the XPath, and return the text value.
  • textContent – return the value of the text node.
Sign up to request clarification or add additional context in comments.

Comments

2

Here is how to do this using XML::Twig, with a few modern idioms thrown in:

#!/usr/bin/perl

use strict;
use warnings;

use autodie qw( open); # dies with error message when open fails

use XML::Twig;

my $IN= "properties.xml";
my $OUT= "install.properties";

open( my $cts, '>', $OUT); # avoid "bareword filehandles" (CTS), use 3 arg open

XML::Twig->new( twig_handlers => { entry => \&entry, },)
         ->parsefile( $IN);

sub entry
  { my( $t, $entry)= @_;
    print {$cts} $entry->att( 'key'), " = ", $entry->trimmed_text, "\n"; 
  } 

Comments

0

Try XML::Simple my all time favorite "XML parser" for simple XML processing. It loads your file into a ready to use perl hash/array of hash/array of ... :-

use XML::Simple;
use Data::Dumper;

my $ref = XMLin('test.xml'); # load the file
print STDERR Dumper($ref);   # see how it looks
foreach my $k (keys %{$ref->{entry}}) # output to conf
{
    $v = $ref->{entry}->{$k}->{content};
    print "$k=$v\n";
}

Works nicely :-

% perl test.pl

HOST=
    localhost

LOCATION=
    C:\Rel-LOCATION

TYPE=
    Rel

I have left the trimming etc for you :)

4 Comments

XML::Simple is deprecated in favour of XML::LibXML, according to its own docs. (While it is extremely DWIM in cases like this, it is extremely difficult to use for general problems).
I didn't know that. Nevertheless I'll let the answer stay to hopefully improve my rep :) and less importantly because that's what I'd do even today instead of using a full-fledged xml parser
its failing with msg junk after document element at line 3, column 0, byte 44 at C:/Perl64/lib/XML/Parser.pm line 187 in parser.pm 186 eval { 187 $result = $expat->parse($arg); 188 };
issue was with xml file format, its working fine. many thanks Himanshu

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.