1

Below is a XML file,

   <?xml version='1.0'?>
    <employee>
      <name>Pradeep</name>
      <age>23</age>
      <sex>M</sex>
      <department>Coder</department>
    </employee>

And the perl code is

 use XML::Simple;
 use Data::Dumper;
 @xml=new XML::Simple;
 $data=@xml->XMLin("data.xml");
 print Dumper($data);

Now how do you parse if the XML file is

   <?xml version='1.0'?>
      <employee="risc_31">
       <name>John Doe</name>
       <age>43</age>
       <sex>M</sex>
       <department>Analyst</department>
      </employee>
      <employee="risc_32">
       <name>Pradeep</name>
       <age>23</age>
       <sex>M</sex>
       <department>HR</department>
      </employee>

how can this be done using a foreach loop in perl

NOTE: XML::Simple is easier for me

Any help is appreciated!

Divox
  • 101
  • 6
  • 1
    You are wrong. `XML::Simple` isn't easier for anyone. [Why is XML::Simple discouraged](http://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged) – Sobrique Dec 30 '15 at 11:25
  • Thank you! I'll be using XML::Simple only for this task! Once done I'm for sure jumping to XML::Twig!@Sobrique – Divox Dec 30 '15 at 11:52

2 Answers2

2

Your xml is invalid, you can't have

<employee="risc_31">

You can have something like

<employee employeeId="risc_31">

Assuming your xml is

<?xml version='1.0'?>
<employee employeeId="risc_31">
  <name>John Doe</name>
  <age>43</age>
  <sex>M</sex>
  <department>Analyst</department>
</employee>
<employee employeeId="risc_32">
  <name>Pradeep</name>
  <age>23</age>
  <sex>M</sex>
  <department>HR</department>
</employee>

You can do the following with libXML (sorry, I don't know XML::Simple)

use strict;
use XML::LibXML;

my $filename = 'data.xml';
my $parser = XML::LibXML->new();
my $xmldoc = $parser -> parse_file( $filename );

foreach my $employee( $xmldoc -> findnodes( '/employee' ) ) {
  my $employeeId = $employee -> getAttribute( 'employeeId' );

  my $name = $employee -> findnodes( './name' );
  my $age = $employee -> findnodes( './age' );
  my $sex = $employee -> findnodes( './sex' );
  my $department = $employee -> findnodes( './department' );

}

exit 0;
user1817991
  • 93
  • 1
  • 1
  • 6
  • thats correct, My bad! Can we do it with XML::Simple ?! how can it be done? @user1817991 – Divox Dec 30 '15 at 09:58
  • Yes, I'm sure it can be done with XML::Simple, but I don't have that installed so I can't help, sorry. – user1817991 Dec 30 '15 at 10:25
  • 2
    Don't - life is too short to work with `XML::Simple` when there's better alternatives readily available. (`XML::LibXML` is the most exhaustive in terms of features, `XML::Twig` is probably easier to get started with). [Why is XML::Simple discouraged](http://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged) – Sobrique Dec 30 '15 at 11:26
0

Problems with XML and Perl. Have a look at xmllint on Mac and I'd assume linux...

Think of XML as having two types of data... "Data" and "Meta Data", everything between matched ">ME ME ME<" is real data, everything between matched <"me" "me" "me"> is meta data. Mixing them up means you get errors ie xmllint showed me this

data.xml:2: parser error : error parsing attribute name
<employee="risc_31">
     ^
data.xml:2: parser error : attributes construct error
<employee="risc_31">
     ^
data.xml:2: parser error : Couldn't find end of Start Tag employee line 2
<employee="risc_31">
     ^
data.xml:2: parser error : Extra content at the end of the document
<employee="risc_31">
     ^

Change your XML to look something more like. Note I've added a "wtf" entry to this record ie I've made the "risc_nn" data as a real part of the employee record, not meta data...

<?xml version="1.0"?>
<foo>
<employee>
  <wtf>risc_31</wtf>
  <name>John Doe</name>
  <age>43</age>
  <sex>M</sex>
  <department>Analyst</department>
</employee>
<employee>
  <wtf>risc_32</wtf>
  <name>Pradeep</name>
  <age>23</age>
  <sex>M</sex>
  <department>HR</department>
  </employee>
</foo>

The following Perl program will now work

use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
my @xml=new XML::Simple;
my $data=XMLin("data.xml");
print Dumper($data);

and provide the following result...

$VAR1 = { 
    'employee' => {
        'John Doe' => {
            'wtf' => 'risc_31',
            'sex' => 'M',
            'department' => 'Analyst',
            'age' => '43'
     },  
     'Pradeep' => {
            'age' => '23',
            'wtf' => 'risc_32',
            'sex' => 'M',
            'department' => 'HR'
     }   
  }   
};

If you want to loop over that it's a hash reference so use the following...

for my $key (%{$data}) {
  print $data->{$key} . "\n";
}

Or any myriad ways to do anything in Perl.

Harry
  • 11,298
  • 1
  • 29
  • 43
  • I'm aware of that method, but I'd like to try the way I posted my query! That's more fun ;) – Divox Dec 30 '15 at 07:34
  • GRD - The code above has a foreach loop. 'for' is the same as 'foreach'. There is no difference. – runrig Dec 30 '15 at 16:38