【问题标题】:Perl XML to Hash drop last xml node and force an arrayPerl XML to Hash 删除最后一个 xml 节点并强制一个数组
【发布时间】:2020-05-11 03:56:47
【问题描述】:

我有一个 XML,我需要将其转换为特定格式的哈希,该格式需要一些节点位于数组中。我试过 XML::Simple 但无法摆脱一个 xml 节点级别。

#!/usr/bin/perl
use Data::Dumper::Simple;
use XML::Simple;

use warnings;
use strict;

my $xml = <<'XML';
<?xml version="1.0"?>
<release id="9999" status="Accepted">
  <images>
    <image height="511" type="primary" uri="" uri150="" width="600"/>
    <image height="519" type="secondary" uri="" uri150="" width="600"/>
    <image height="521" type="secondary" uri="" uri150="" width="600"/>
    <image height="217" type="secondary" uri="" uri150="" width="500"/>
    <image height="597" type="secondary" uri="" uri150="" width="600"/>
    <image height="89" type="secondary" uri="" uri150="" width="600"/>
  </images>
  <artists>
    <artist>
      <id>45</id>
      <name>Aphex Twin</name>
      <anv/>
      <join/>
      <role/>
      <tracks/>
    </artist>
  </artists>
</release>
XML

my $xml_hash = XMLin($xml, ForceArray => qr{image}x );
print Dumper $xml_hash; 

期望的输出

       'images' => [
                     {
                       'type' => 'primary',
                       'width' => 600,
                       'resource_url' => '',
                       'uri150' => '',
                       'height' => 511,
                       'uri' => ''
                     },
                     {
                       'width' => 600,
                       'type' => 'secondary',
                       'resource_url' => '',
                       'uri150' => '',
                       'uri' => '',
                       'height' => 519
                     }, etc...

我的示例代码得到的是

$xml_hash = {
              'images' => [
                            {
                              'image' => [
                                           {
                                             'uri150' => '',
                                             'type' => 'primary',
                                             'uri' => '',
                                             'height' => '511',
                                             'width' => '600'
                                           },
                                           {
                                             'type' => 'secondary',
                                             'uri150' => '',
                                             'uri' => '',
                                             'height' => '519',
                                             'width' => '600'
                                           },
                                           {
                                             'uri' => '',
                                             'height' => '521',
                                             'width' => '600',
                                             'type' => 'secondary',
                                             'uri150' => ''
                                           },
                              etc...

如何摆脱

'图像' => [

并且拥有

'图片' => [

包含所有哈希?

谢谢;乔治

【问题讨论】:

标签: arrays xml perl hash


【解决方案1】:

任何将整个 XML 文档表示为 Perl 数据结构的尝试都会因这两种格式的性质而充满边缘情况和不方便的设计。有许多选项可以以适合格式的方式解析和遍历 XML,例如 XML::LibXMLXML::Twig。以下是我将如何使用 Mojo::DOM(它使用 CSS 选择器进行遍历)来解决这个问题:

use strict;
use warnings;
use Mojo::DOM;
use Mojo::Util 'dumper';

my $xml = <<'XML';
<?xml version="1.0"?>
<release id="9999" status="Accepted">
  <images>
    <image height="511" type="primary" uri="" uri150="" width="600"/>
    <image height="519" type="secondary" uri="" uri150="" width="600"/>
    <image height="521" type="secondary" uri="" uri150="" width="600"/>
    <image height="217" type="secondary" uri="" uri150="" width="500"/>
    <image height="597" type="secondary" uri="" uri150="" width="600"/>
    <image height="89" type="secondary" uri="" uri150="" width="600"/>
  </images>
  <artists>
    <artist>
      <id>45</id>
      <name>Aphex Twin</name>
      <anv/>
      <join/>
      <role/>
      <tracks/>
    </artist>
  </artists>
</release>
XML

my $dom = Mojo::DOM->new->xml(1)->parse($xml);
my @images = $dom->find('release#9999 > images > image')->map('attr')->each;
print dumper \@images;

输出:

[
  {
    "height" => 511,
    "type" => "primary",
    "uri" => "",
    "uri150" => "",
    "width" => 600
  },
  {
    "height" => 519,
    "type" => "secondary",
    "uri" => "",
    "uri150" => "",
    "width" => 600
  },
  {
    "height" => 521,
    "type" => "secondary",
    "uri" => "",
    "uri150" => "",
    "width" => 600
  },
  {
    "height" => 217,
    "type" => "secondary",
    "uri" => "",
    "uri150" => "",
    "width" => 500
  },
  {
    "height" => 597,
    "type" => "secondary",
    "uri" => "",
    "uri150" => "",
    "width" => 600
  },
  {
    "height" => 89,
    "type" => "secondary",
    "uri" => "",
    "uri150" => "",
    "width" => 600
  }
]

【讨论】:

  • 我希望有灵丹妙药,但我明白你的意思,我发布的只是一个 xml 示例,在很多情况下我需要使用 Mojo 将我需要的内容提取为特定的哈希格式,我已经有一堆代码期望来自网络服务的哈希值。尝试使用 xml 数据转储而不是 Web 服务。谢谢!
  • @George 将各种 XML 调整为您需要的结构需要努力,但最终它会更加一致、灵活和可维护。
  • hum,如果前缀用于属性,这将创建一个使用该前缀的哈希元素,即使该前缀在文档之外是无意义的。
【解决方案2】:

XML::Simple 不鼓励自己使用。

以下是使用XML::LibXML 获取哈希数组的方法:

use XML::LibXML;

my $dom = XML::LibXML->load_xml(string => $xml);

my @images = map +{
    map { $_->name => $_->value } $_->findnodes('@*')
}, $dom->findnodes('/release/images/image');

【讨论】:

  • 这会忽略属性的命名空间,因此可能会导致冲突。最好忽略非空命名空间中的属性,以便扩展——“XML”中的“X”——不会引起问题。但这可能并不重要。
  • @ikegami:是的,如果 XML 声明了根节点的命名空间,则结果数组将为空。
  • 应该如此。这就是我要说的。您将节点 {}release 和节点 {http://foo}release 视为不同的元素(这很好),但您将属性 {}height{http://foo}height 视为相同,随机选择一个作为高度(这很糟糕,但不太可能发生)。
猜你喜欢
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
  • 2013-07-17
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多