【问题标题】:Convert XML to Perl Hash将 XML 转换为 Perl 哈希
【发布时间】:2021-07-13 08:33:30
【问题描述】:

对于下面的 XML 结构,我正在尝试获取一个对应的 Perl Hash 数组

<root>
  <ref name="abc_sia_%version1.ref%">
    <func envname = "test01" objectdir = "/home/pv66" base="default_771"/>
  </ref>
</root>

我可以使用以下方法将其转换为 perl 哈希:

my $xml = new XML::Simple;
my $data = $xml->XMLin("/home/pv66", ForceArray => 1, KeyAttr => { ref => "name"});
print Dumper ($data);

哈希结果是:

$VAR1 = {
           'ref' => {
                       'abc_sia_%version1.ref' => {
                                                      'func' => [
                                                                  {
                                                                   'envname' => 'test01',
                                                                   'objectdir' => '/home/pv66',
                                                                   'base' => 'default_771'
                                                                  }
                                                                ]       
                                                  }
                    }
         };

虽然我需要删除上层引用,但基本上我希望哈希看起来像:

$VAR1 = {
           'abc_sia_%version1.ref' => {
                                         'func' => [
                                                     {
                                                        'envname' => 'test01',
                                                        'objectdir' => '/home/pv66',
                                                        'base' => 'default_771'
                                                     }
                                                   ]       
                                       }
        };

有什么方法可以转换哈希吗??

【问题讨论】:

  • 建议使用XML::LibXML 而不是XML::Simple。
  • @vkk05 是的,我知道总是建议使用 LibXML,尽管我无法在 LibXML 中找到任何可以帮助我像上面那样转换它的特定属性/函数。如果您能对如何使用 LibXML 进行一些说明,我将不胜感激。
  • 您也没有找到使用 XML::Simple 的方法... XML 不能很好地映射到哈希/数组。你需要说如何做到这一点。 XML::Simple 不允许您这样做,因此模块自己的文档中的警告告诉您不要使用它。说真的,当模块本身告诉你不要使用模块时,你为什么要使用模块?!
  • @ikegami 这就是我发布这个问题的原因。我发现了一些非常相似的东西:stackoverflow.com/questions/27328986/… 虽然如果你看一下哈希,在 func 中有一个列表,它是通过 XML:Simple 中的 ForceArray 参数实现的,XMLLib 中是否有类似的东西?
  • 您只认为 XML::Simple 有效。一段时间后,它将无法满足您的需求。例如,您无法可靠地往返数据。文档告诉你这一点。但是,正如 ikegami 所指出的,您只是告诉我们您认为解决方案是什么,而没有就实际问题发表任何意见。

标签: xml perl


【解决方案1】:

XML::LibXML 的文档对于初学者来说可能有点简洁。我推荐Grant's tutorial。

XML::LibXML 没有单一的“从这个 XML 文档创建数据结构”方法。正如 XML::Simple 所示,这种方法太脆弱而无法使用。相反,您可以自己遍历 DOM 以将所需的任何数据提取到数据结构中。就个人而言,我非常喜欢使用 XPath 表达式来确定我想要什么。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Data::Dumper;
use XML::LibXML;

# Here, I've loaded the XML from the DATA filehandle
# (at the end of the source file). Other options are
# available.
my $dom = XML::LibXML->load_xml(IO => \*DATA);

my $data;

# Look for all '/root/ref' nodes...
for my $ref ($dom->findnodes('/root/ref')) {
  # Get the name of the ref node
  my $key = $ref->findvalue('./@name');
  my @funcs;
  # Look for all of the 'func' nodes below this ref node
  for my $func ($ref->findnodes('./func')) {
    my $func_data;
    # For each attribute we're interested in...
    for (qw[envname objectdir base]) {
      # Get the value of the attribute
      $func_data->{$_} = $func->findvalue("./\@$_");
    }
    push @funcs, $func_data;
  }
  $data->{$key}{func} = \@funcs;
}

say Dumper $data;

__DATA__
<root>
  <ref name="abc_sia_%version1.ref%">
    <func envname = "test01" objectdir = "/home/pv66" base="default_771"/>
  </ref>
</root>

【讨论】:

  • 谢谢戴夫!!这确实很有意义,并且确实对进行基本的搜索和散列很有帮助。
【解决方案2】:

原来我所要做的就是添加另一个级别的搜索并将其分配给一个变量。无论如何我都会发布解决方案:

my $xml = new XML::Simple;
my $data = $xml->XMLin("/home/pv66", ForceArray => 1, KeyAttr => { ref => "name"});
my data1 = $data->{'ref'};
print Dumper ($data1);

这会返回:


    $VAR1 = {
           'abc_sia_%version1.ref' => {
                                         'func' => [
                                                     {
                                                        'envname' => 'test01',
                                                        'objectdir' => '/home/pv66',
                                                        'base' => 'default_771'
                                                     }
                                                   ]       
                                       }
        };

这是我想要的结构。

【讨论】:

  • 请停止在代码中使用间接对象表示法。 new XML::Simple 大部分时间都可以工作,但如果不工作,您将浪费数天时间来追踪问题。使用XML::Simple-&gt;new() 好得多(但显然,完全不使用 XML::Simple 更好)。
  • 我注意到 XML::Simple 在其文档中曾经使用过间接对象表示法。但这已在 2016 年 10 月发布的 2.16 版中得到修复。这让我相信您使用的模块版本已超过 15 年。请帮自己一个忙,更新您的开发环境。
  • 是的,我知道这一点。实际上,我一直致力于对其中的一些进行现代化改造,为此我在理解 Perl 中的工作方式时遇到了一些问题。据我所知,我正在更改的脚本是在 2004 年编写的:D
猜你喜欢
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 2011-12-21
  • 1970-01-01
  • 2016-07-25
  • 2016-08-26
  • 2017-01-06
  • 1970-01-01
相关资源
最近更新 更多