Parsing complex XML in Perl

2019-06-08 19:57发布

I have an XML and I want to print all his nodes and I want to access the movie nodes fields.

I can access Name and City, but I can`t access Movie fields.

<OnlineCinema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Cinema.xsd">
<Cinema>
    <City>Cluj</City>
    <Name>Cinema2</Name>
    <MovieName>ScaryMovie</MovieName>
    <Movie>
        <Name>ScaryMovie</Name>
        <Genre>comedie</Genre>
        <Director>lala</Director>
        <Writer>asdf</Writer>
        <Cast>asdvvb</Cast>
        <Year>2010</Year>
        <Trailer>http://www.youtube.com/embed/RMDZ8M47j0I</Trailer>
        <NRLoc>400</NRLoc>
    </Movie>
</Cinema>

Code:

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

$xml = new XML::Simple (KeyAttr=>[]);
$data = $xml->XMLin("OnlineCinema.xml");
print "Content-type: text/html \n\n";

foreach $e (@{$data->{Cinema}}) {
    print "City: ", $e->{City}, "</br>\n";
    print "Name: ", $e->{Name}, "</br>\n"; 
    print "</br></br>\n";
}

标签: xml perl parsing
2条回答
倾城 Initia
2楼-- · 2019-06-08 20:08

XML::Simple is the hardest XML parser to use. I use XML::LibXML.

use strict;
use warnings;

use XML::LibXML qw( );

my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('OnlineCinema.xml');

for my $cinema ($doc->findnodes('/OnlineCinema/Cinema')) {
   my $cinema_name = $cinema->find('Name');
   my $cinema_city = $cinema->find('City');

   for my $movie ($cinema->findnodes('Movie')) {
      my $movie_name  = $movie->find('Name');
      my $movie_genre = $movie->find('Genre');

      print("$movie_name ($movie_genre) is playing at the $cinema_name in $cinema_city\n");
   }
}

(I assumed a Cinema can have more than one Movie, but given the presence of MovieName in Cinema, that might not be the case. It'll still work if it's not the case, but you might want to eliminate the inner for loop.)

查看更多
我想做一个坏孩纸
3楼-- · 2019-06-08 20:20

Try that:

use XML::Simple qw(:strict);
use Data::Dumper;

$xml = new XML::Simple (KeyAttr => [], ForceArray => [qw( Cinema )]);
$data = $xml->XMLin("OnlineCinema.xml");

print "Content-type: text/html \n\n";

foreach $e (@{$data->{Cinema}}) {
    print "City: ", $e->{City}, "<br/>\n";
    print "Name: ", $e->{Name}, "<br/>\n"; 
    print "<br/><br/>\n";
}

Basically, you are asking to go through the array of Cinema entries in your xml, but in this instance, since there's only one of them, it is built as a single scalar value. The ForceArray option tells the libray to consider that entry as a one element array, or more precisely, for any xml fed to the script, the Cinema tag(s) will always be made as an array of tags, whether there's one or more of them. That option may take:

  • an array of tag names which must be forced to arrays,
  • 1 to force it to all tags,
  • 0 to not use it (which is the default)

Oh, and add a closing OnlineCinema tag at the end of your xml to have it parsed correctly.

查看更多
登录 后发表回答