Perl 解析和迭代XML结构,其中每个条目都有多个属性

Perl 解析和迭代XML结构,其中每个条目都有多个属性,perl,hash,foreach,xml-parsing,key,Perl,Hash,Foreach,Xml Parsing,Key,我试图处理一个XML项目列表(在本例中是图像),并对每个项目进行迭代。我并不真正理解Perl或Hash,但我找到了一些解释和示例(这里有很多),并编写了一些似乎有效的东西。XML是一个元素列表,每个元素都包含一个唯一的“id”属性 我使用XML::Simple中的XMLin来解析XML 当列表包含多个元素时,它通过“id”进行迭代。但是,当只有一个属性时,它会变得混乱,并将元素的每个属性都视为自己的值,这会导致运行时错误 在使用“严格引用”时,无法将字符串(“0”)用作哈希引用 我猜问题在于散列

我试图处理一个XML项目列表(在本例中是图像),并对每个项目进行迭代。我并不真正理解Perl或Hash,但我找到了一些解释和示例(这里有很多),并编写了一些似乎有效的东西。XML是一个元素列表,每个元素都包含一个唯一的“id”属性

我使用XML::Simple中的XMLin来解析XML

当列表包含多个元素时,它通过“id”进行迭代。但是,当只有一个属性时,它会变得混乱,并将元素的每个属性都视为自己的值,这会导致运行时错误

在使用“严格引用”时,无法将字符串(“0”)用作哈希引用

我猜问题在于散列键不知道“id”是唯一键,至少当只有一个条目时是这样。所以我添加了代码来转储密钥。我还添加了一行来打印
$image
foreach
循环中的内容。在中断的情况下,行
print“In-loop;image ID=$image\n”在循环中显示
;image ID=Serial
由于
Serial
是与
ID
处于同一级别的属性,我猜这就是问题所在(没有正确使用
ID
作为键)

这是我的密码:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use XML::Simple;

    my $album_data_file = $ARGV[0];
    my $album_file_list = $ARGV[1];
    my $do_dump_data    = $ARGV[2];

    my $album_data = XMLin ( $album_data_file );
    my $LIST_FILE;

    if ( defined $album_file_list && "$album_file_list" ne "" )
    {
        if ( open ( $LIST_FILE, ">", "$album_file_list" ) )
        {
            print "Opened file $album_file_list as $LIST_FILE\n";
        }
    }

    if ( defined $do_dump_data && $do_dump_data eq "true" )
    {
        use Data::Dumper;
        print "data:\n\n";
        print Dumper ( $album_data );
        print "\n\n\n\n";

        print "keys:\n\n";
        print Dumper ( keys %{$album_data->{Images}->{Image}} );
        print "\n\n\n\n";
    }

    foreach my $image ( keys %{$album_data->{Images}->{Image}} )
    {
        print "In loop; image ID=$image\n";

        my $ref = $album_data->{Images}->{Image}->{$image};

        #
        # Write to files list: file name, ID, key, size, MD5
        #
        print $LIST_FILE ( "$ref->{FileName}\t$image\t$ref->{Key}"
                 . "\t$ref->{Size}\t$ref->{MD5Sum}\n" );
    }

    close ( $LIST_FILE );
下面是一个破坏它的示例XML文件:

<?xml version="1.0" encoding="utf-8"?>
<rsp stat="ok">
  <method>images.get</method>
  <Images>
    <Image id="123" Key="xyz" Type="Album" Caption="Room 5083" FileName="MVI_2838.AVI" Format="MP4" Height="480" Keywords="China; Suite" LastUpdated="2014-04-19 11:49:45" Position="1" Serial="0" Size="116033" Width="640" Date="2014-04-19 11:46:24" Hidden="0" MD5Sum="6151e20053eeda87c688f8becae0d402" Watermark="0">
      <Album id="345" Key="zzy" />
    </Image>
  </Images>
</rsp>
下面是转储键%{$album_data->{Images}->{Image}}构造的结果:

$VAR1 = 'Serial';
$VAR2 = 'Format';
$VAR3 = 'Keywords';
$VAR5 = 'Type';
$VAR6 = 'Size';
$VAR7 = 'MD5Sum';
$VAR9 = 'id';
$VAR10 = 'Key';
$VAR11 = 'LastUpdated';
$VAR12 = 'Album';
$VAR14 = 'Position';
$VAR15 = 'Height';
$VAR16 = 'Date';
$VAR17 = 'Caption';
$VAR19 = 'FileName';
$VAR20 = 'Hidden';
$VAR23 = 'Width';
$VAR24 = 'Watermark';
$VAR27 = 'Duration';
根据:

不鼓励在新代码中使用此模块。还提供了其他模块,它们提供了更直观和一致的接口。特别是,强烈建议使用

该模块的主要问题是选项数量庞大,以及这些选项之间的交互方式随意,通常会产生意想不到的结果

带有bug修复和文档修复的补丁是受欢迎的,但不太可能添加新功能

XML::Simple
是一个有用的模块,如果您熟悉perl复杂的数据结构,可以快速解析XML。然而,每当xml变得太复杂时,模块就不再有用,因为它是根据许多配置变量解析某些结构的任意方法


我仍然很少使用
XML::Simple
,但是,我建议您查看前面提到的
XML::LibXML
中的任何一个,以避免类似的问题。

我感谢Miller的警告,不鼓励使用
XML::Simple
,他警告说,由于有太多的选项以难以定义和管理的方式交互,因此很难使用它。在研究他建议的替换模块时,我偶然发现了一些信息,这些信息是我在使用
XML::Simple
之前应该知道的。特别是,我的脚本在XML中有多个图像时工作,但在只有一个图像时失败,这一事实指出,如果使用的是
XML::Simple
,将
ForceArray
选项设置为始终应位于数组中的元素通常是至关重要的,即使一个特定的XML文件恰好只包含一个。否则,元素有时是数组,有时是标量,这导致了我所看到的运行时错误

因此,在我的例子中,设置
forcearray=>['Image']
可以使代码工作(通过将所有
元素强制放入一个数组,即使只有一个),而不是试图找出如何使用不同的XML解析模块(尽管我毫不怀疑这样做会在将来节省时间).

$VAR1 = 'Serial';
$VAR2 = 'Format';
$VAR3 = 'Keywords';
$VAR5 = 'Type';
$VAR6 = 'Size';
$VAR7 = 'MD5Sum';
$VAR9 = 'id';
$VAR10 = 'Key';
$VAR11 = 'LastUpdated';
$VAR12 = 'Album';
$VAR14 = 'Position';
$VAR15 = 'Height';
$VAR16 = 'Date';
$VAR17 = 'Caption';
$VAR19 = 'FileName';
$VAR20 = 'Hidden';
$VAR23 = 'Width';
$VAR24 = 'Watermark';
$VAR27 = 'Duration';