将 XML 数据解析为不同的结构

Parsing XML data into a different structure

我有以下 XML 文件,我正在尝试解析它

<Books>
  <book name="first" feed="contentfeed" mode="modes" />
  <book name="first" feed="communityfeed" mode="modes" region="1"/>
  <book name="second" feed="contentfeed" mode="" />
  <book name="second" feed="communityfeed" mode="modes" />
  <book name="second" feed="articlefeed" mode="modes" /> 
</Books>

我正在使用 Perl 5.8 版和 XML::Simple。下面是我写的代码

    use XML::Simple;

    my $xs = new XML::Simple( KeyAttr => { book => 'name' } , ForceArray => [ 'book','name' ] );
    my $config = $xs->XMLin( <complete path to xml file> );

下面是结果(使用Data::Dumper显示)

'book' => {
    'first' => {
        'feed'   => 'communityfeed',
        'mode'   => 'modes',
        'region' => '1'
    },
    'second' => {
        'feed' => 'articlefeed',
        'mode' => 'modes'
    },
}

相反,我希望输出格式如下

'book' => {
    'first' => {
        'communityfeed' => { mode => 'modes', region => '1' },
        'contentfeed'   => { mode => 'modes' }
    },
    'second' => {
        'communityfeed' => { mode => 'modes' },
        'contentfeed'   => { mode => '' },
        'articlefeed'   => { mode => 'modes' }
    },
}

备注

  1. 无法更改 XML 文件格式,因为它是当前生产版本
  2. 首选 Perl 5.8 版,因为这是父脚本中使用的版本,解析逻辑应合并到该脚本中

您以前遇到过这种问题吗?如果是这样,那么如何解决这个问题?

XML::Simple 是一个使用起来笨拙且令人沮丧的模块,我非常怀疑您是否可以说服它构建您需要的数据结构。几乎任何其他 XML 解析器都会向前迈出一步

这是一个使用 XML::Twig 的解决方案。您可以查询已解析的 XML 数据并从中构建您喜欢的任何数据结构

我使用 Data::Dump 只是为了显示结果数据

use strict;
use warnings 'all';

use XML::Twig;

my $config;

{
    my $twig = XML::Twig->new;
    $twig->parsefile('books.xml');

    for my $book ( $twig->findnodes('/Books/book') ) {

        my $atts = $book->atts;
        my ( $name, $feed ) = delete @{$atts}{qw/ name feed /};

        $config->{book}{$name}{$feed} = $atts;
    }
}

use Data::Dump;
dd $config;

输出

{
  book => {
    first  => {
                communityfeed => { mode => "modes", region => 1 },
                contentfeed   => { mode => "modes" },
              },
    second => {
                articlefeed   => { mode => "modes" },
                communityfeed => { mode => "modes" },
                contentfeed   => { mode => "" },
              },
  },
}