【问题标题】:Perl XML::Simple parser decoding inconsistencyPerl XML::Simple 解析器解码不一致
【发布时间】:2014-10-11 01:23:10
【问题描述】:

我在解析 XML 时遇到了“不一致”(对我而言):

use 5.14.2;
use strict;
use warnings;

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

my $xml;
{local $/;
$xml = <DATA>;}

my $xmlParsed = XMLin($xml,
            KeyAttr => {phone => 'type', tankstelle => 'id'},
            ForceArray => [ 'phone' ],
                        ContentKey => '-content',
                       );
say Dumper($$xmlParsed{'tankstelle'});


__DATA__
<?xml version="1.0"?>
<tankstellen>
    <tankstelle>
        <id>63</id>
        <phone type="main">0911 731586</phone>
        <phone type="fax">0911 7592228</phone>
        <number/>
    </tankstelle>
    <tankstelle>
        <id>64</id>
        <phone type="main">0911 732011</phone>
        <phone type="fax"></phone>
        <number>64</number>
    </tankstelle>
    <tankstelle>
        <id>91</id>
        <phone type="main">0911 732926</phone>
        <phone type="fax">0911 732917</phone>
        <number/>
    </tankstelle>
    <tankstelle>
        <id>92</id>
        <phone type="main">0911 737577</phone>
        <phone type="fax"></phone>
        <number/>
    </tankstelle>
</tankstellen>

有时数字是散列,有时是字符串。如果 type="fax" 为空,则它主要包含内容。

我为解析器尝试了不同的选项来摆脱 main 和 number 中的哈希,但没有运气。

'64' => {
        'number' => '64',
        'phone' => {
                   'main' => {
                             'content' => '0911 732011'
                           },
                   'fax' => {}
                 }
      },
'91' => {
        'phone' => {
                   'fax' => '0911 732917',
                   'main' => '0911 732926'
                 },
        'number' => {}
      }

【问题讨论】:

    标签: perl xml-parsing


    【解决方案1】:

    遗憾的是,XML::Simple 可能是 CPAN 上最复杂的 XML 模块,但初学者选择它是为了轻松上手。它自己的文档现在这样说

    不鼓励在新代码中使用此模块。其他模块也可以提供更直接和一致的接口。特别是,强烈推荐使用 XML::LibXML。

    您已经亲眼目睹了要让它在除了最简单的 XML 之外的任何东西上都能正常运行是多么困难,而且它有一个巨大的缺点,就是它对待属性的方式与对待元素的方式相同。

    根据作者的建议,这个简短的程序生成了我认为您想要的数据结构,其优点是您可以修改它以从 XML 创建您喜欢的任何结构。

    use strict;
    use warnings;
    
    use XML::LibXML;
    use Data::Dump;
    
    my $xml = XML::LibXML->load_xml(IO => \*DATA);
    
    my %data;
    
    for my $ts ($xml->findnodes('/tankstellen/tankstelle')) {
    
      my $id = $ts->findvalue('id');
    
      $data{$id}{number} = $ts->findvalue('number');
    
      for my $phone ($ts->findnodes('phone')) {
        my $type = $phone->findvalue('@type');
        $data{$id}{phone}{$type} = $phone->findvalue('text()');
      }
    }
    
    dd \%data;
    
    
    __DATA__
    <?xml version="1.0"?>
    <tankstellen>
        <tankstelle>
            <id>63</id>
            <phone type="main">0911 731586</phone>
            <phone type="fax">0911 7592228</phone>
            <number/>
        </tankstelle>
        <tankstelle>
            <id>64</id>
            <phone type="main">0911 732011</phone>
            <phone type="fax"></phone>
            <number>64</number>
        </tankstelle>
        <tankstelle>
            <id>91</id>
            <phone type="main">0911 732926</phone>
            <phone type="fax">0911 732917</phone>
            <number/>
        </tankstelle>
        <tankstelle>
            <id>92</id>
            <phone type="main">0911 737577</phone>
            <phone type="fax"></phone>
            <number/>
        </tankstelle>
    </tankstellen>
    

    输出

    {
      63 => {
              number => "",
              phone  => { fax => "0911 7592228", main => "0911 731586" },
            },
      64 => {
              number => 64,
              phone => { fax => "", main => "0911 732011" }
            },
      91 => {
              number => "",
              phone  => { fax => "0911 732917", main => "0911 732926" },
            },
      92 => {
              number => "",
              phone => { fax => "", main => "0911 737577" }
            },
    }
    

    工具成功完成

    【讨论】:

    • 谢谢,我想我错过了文档中的这一重要信息...
    【解决方案2】:

    如前所述,强烈推荐使用 XML::LibXML。

    但是,如果(对于大型 XML 文档)内存效率比 CPU 速度更重要,则可以考虑另一种选择:XML::Reader::PP

    use strict;
    use warnings;
    
    use XML::Reader::PP;
    use Data::Dump;
    
    my $rdr = XML::Reader::PP->new(\*DATA, { mode => 'branches' },
      { root => '/tankstellen/tankstelle', branch => [ 
        'id',
        'phone[@type="main"]',
        'phone[@type="fax"]',
        'number',
      ]});
    
    my %data;
    
    while ($rdr->iterate) {
        my ($id, $ph_main, $ph_fax, $num) = $rdr->value;
        $_ //= '' for ($id, $ph_main, $ph_fax, $num);
    
        $data{$id}{'number'}        = $num;
        $data{$id}{'phone'}{'main'} = $ph_main;
        $data{$id}{'phone'}{'fax'}  = $ph_fax;
    }
    
    dd \%data;
    
    __DATA__
    <?xml version="1.0"?>
    <tankstellen>
        <tankstelle>
            <id>63</id>
            <phone type="main">0911 731586</phone>
            <phone type="fax">0911 7592228</phone>
            <number/>
        </tankstelle>
        <tankstelle>
            <id>64</id>
            <phone type="main">0911 732011</phone>
            <phone type="fax"></phone>
            <number>64</number>
        </tankstelle>
        <tankstelle>
            <id>91</id>
            <phone type="main">0911 732926</phone>
            <phone type="fax">0911 732917</phone>
            <number/>
        </tankstelle>
        <tankstelle>
            <id>92</id>
            <phone type="main">0911 737577</phone>
            <phone type="fax"></phone>
            <number/>
        </tankstelle>
    </tankstellen>
    

    输出:

    {
      63 => {
              number => "",
              phone  => { fax => "0911 7592228", main => "0911 731586" },
            },
      64 => { 
              number => 64,
              phone => { fax => "", main => "0911 732011" }
            },
      91 => {
              number => "",
              phone  => { fax => "0911 732917", main => "0911 732926" },
            },
      92 => { 
              number => "",
              phone => { fax => "", main => "0911 737577" }
            },
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 2012-02-11
      • 1970-01-01
      • 2013-07-24
      • 1970-01-01
      • 2015-10-09
      • 2011-02-24
      相关资源
      最近更新 更多