【问题标题】:How can I parse a diffgam.xml file with perl in a way to get array of hashes instead of a big hash-map?如何使用 perl 解析 diffgam.xml 文件以获取哈希数组而不是大哈希映射?
【发布时间】:2015-01-22 09:12:01
【问题描述】:

我从服务中获得以下 diffgram XML:

<?xml version="1.0"?>
<xvcs:diffgram xmlns:xvcs="http://www.xvcs.org/">
  <xvcs:update id="7" first-child-of="/opt/node/node[1]">
    <xvcs:attr-update name="location" old-value="???" new-value="testlocation"/>
  </xvcs:update>
  <xvcs:update id="35" follows="/opt/node/node[2]">
    <xvcs:attr-update name="URL" old-value="/" new-value="/testurl/"/>
  </xvcs:update>
  <xvcs:insert id="75" first-child-of="/opt">
    <node node_id="/1234" location="new location" URL="/newurl"></node>
  </xvcs:insert>
</xvcs:diffgram>

我是这样用 XML::Simple 解析的:

my $diffgram_hashref = XMLin($diffgram->toString(1),
                                KeepRoot    => 1,
                                ForceArray  => 1,
                        );

$logger->debug( dump($diffgram_hashref) );

并得到以下结果:

{
  "xvcs:diffgram" => [
    {
      "xmlns:xvcs"  => "http://www.xvcs.org/",
      "xvcs:insert" => {
                         75 => {
                                 "first-child-of" => "/opt",
                                 "node" => [
                                   {
                                     node_id    => "/1234",
                                     location   => "new location",
                                     URL        => "/newurl",
                                   },
                                 ],
                               },
                       },
      "xvcs:update" => {
                         7  => {
                                 "first-child-of"   => "/opt/node/node[1]",
                                 "xvcs:attr-update" => {
                                                         location => { "new-value" => "testlocation", "old-value" => "???" },
                                                       },
                               },
                         35 => {
                                 "follows" => "/opt/node/node[2]",
                                 "xvcs:attr-update" => {
                                        URL => { "new-value" => "/testurl/", "old-value" => "/" },
                                 },
                               },
                       },
    },
  ],
}

我尝试了几种 ForeArray / KeyAttr 组合,但我没有实现将 diffgram 语句(更新、插入)作为数组来以正确的顺序进行处理:

{
  "xvcs:diffgram" => [
    {
      "xvcs:update" => {
                         7  => {
                                 "first-child-of"   => "/opt/node/node[1]",
                                 "xvcs:attr-update" => {
                                                         location => { "new-value" => "testlocation", "old-value" => "???" },
                                                       },
                               }
                        }
    },
    {
      "xvcs:update" => {
                         35 => {
                                 "follows" => "/opt/node/node[2]",
                                 "xvcs:attr-update" => {
                                        URL => { "new-value" => "/testurl/", "old-value" => "/" },
                                 },
                               },
                        }
    },
    {
      "xvcs:insert" => {
                         75 => {
                                 "first-child-of" => "/opt",
                                 "node" => [
                                   {
                                     node_id    => "/1234",
                                     location   => "new location",
                                     URL        => "/newurl",
                                   },
                                 ],
                               },
                       },
    }
  ]
}

有人可以帮帮我吗?

【问题讨论】:

  • 当你说你尝试了几种组合时......你到底尝试了什么,你想要完成什么?我建议您尝试的方法不够简单,使用 XML:Twig 而不是 XML::Simple 是前进的方向。
  • 我尝试了 ForceArray 和 KeyAttr 的不同组合,例如 my $diffgram_hashref = XMLin($diffgram-&gt;toString(1), KeepRoot =&gt; 1, ForceArray =&gt; ['xvcs:insert', 'xvcs:update'], KeyAttr =&gt; undef);my $diffgram_hashref = XMLin($diffgram-&gt;toString(1), KeepRoot =&gt; 1, ForceArray =&gt; ['xvcs:diffgram'], KeyAttr =&gt; undef); 我会看看 XML::Twig,谢谢这个提示
  • 你实际上想要完成什么?您的脚本的预期输出是什么?您想按顺序处理每个元素吗?
  • 预期输出应该是按正确顺序排列的语句数组(更新、插入)。不幸的是 id 不是连续的,所以这不是要排序的标识符。
  • 如果您显示了您希望从该数据中获得的 “哈希数组”,我很乐意编写一个使用 XML::Twig 为您创建它的脚本。

标签: arrays xml perl hash


【解决方案1】:

该程序使用XML::Twig 模块完成您所要求的工作。我忽略了顶级哈希键xvcs:diffgram,因为该哈希只有一个元素。这同样适用于数组中的每个散列——我更愿意将元素标记视为辅助散列的元素之一的值,因为就目前而言,你有一个元素散列数组;但是我已经按照你的描述保留了这个结构。

我还将idnameURL 属性保留为简单的哈希元素,而不是像您的示例那样对它们进行特殊处理。

我使用Data::Dump 只是为了显示从数据构建的结构。

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->new;
$twig->parse(\*DATA);

my @data;

for my $node ( $twig->root->children ) {

  my $atts = $node->atts;

  for my $child ($node->children) {
    $atts->{$child->tag} = $child->atts;
  }

  push @data, { $node->tag => $atts };
}

use Data::Dump;
dd \@data;



__DATA__
<?xml version="1.0"?>
<xvcs:diffgram xmlns:xvcs="http://www.xvcs.org/">
  <xvcs:update id="7" first-child-of="/opt/node/node[1]">
    <xvcs:attr-update name="location" old-value="???" new-value="testlocation"/>
  </xvcs:update>
  <xvcs:update id="35" follows="/opt/node/node[2]">
    <xvcs:attr-update name="URL" old-value="/" new-value="/testurl/"/>
  </xvcs:update>
  <xvcs:insert id="75" first-child-of="/opt">
    <node node_id="/1234" location="new location" URL="/newurl"></node>
  </xvcs:insert>
</xvcs:diffgram>

输出

[
  {
    "xvcs:update" => {
      "first-child-of" => "/opt/node/node[1]",
      "id" => 7,
      "xvcs:attr-update" => {
        "name" => "location",
        "new-value" => "testlocation",
        "old-value" => "???",
      },
    },
  },
  {
    "xvcs:update" => {
      "follows" => "/opt/node/node[2]",
      "id" => 35,
      "xvcs:attr-update" => {
        "name" => "URL",
        "new-value" => "/testurl/",
        "old-value" => "/",
      },
    },
  },
  {
    "xvcs:insert" => {
      "first-child-of" => "/opt",
      "id" => 75,
      "node" => {
        location => "new location",
        node_id => "/1234",
        URL => "/newurl",
      },
    },
  },
]

【讨论】:

    【解决方案2】:

    到目前为止,这是一个基于 cmets 的不完整解决方案。希望它能说明为什么 Borodin 和我要求你实际上试图从你的解析中得到什么。

    use strict;
    use warnings;
    
    use XML::Twig;
    
    my $twig = XML::Twig->new()->parse( \*DATA );
    
    foreach my $thing ( $twig->root->children() ) {
        print $thing ->tag, "\n";
        foreach my $att ( keys %{ $thing->atts() } ) {
            print "\t", $att, "=", $thing->att($att), "\n";
        }
        my $op = $thing->first_child;
        print "\t\t", $op->name, "\n";
        foreach my $att ( keys %{ $op->atts } ) {
            print "\t\t\t", $att, "=", $op->att($att), "\n";
        }
    
    }
    
    __DATA__
    <?xml version="1.0"?>
    <xvcs:diffgram xmlns:xvcs="http://www.xvcs.org/">
      <xvcs:update id="7" first-child-of="/opt/node/node[1]">
         <xvcs:attr-update name="location" old-value="???" new-value="testlocation"/>
      </xvcs:update>
      <xvcs:update id="35" follows="/opt/node/node[2]">
        <xvcs:attr-update name="URL" old-value="/" new-value="/testurl/"/>
      </xvcs:update>
      <xvcs:insert id="75" first-child-of="/opt">
        <node node_id="/1234" location="new location" URL="/newurl"></node>
      </xvcs:insert>
    </xvcs:diffgram>
    

    这将打印:

    xvcs:update
        first-child-of=/opt/node/node[1]
        id=7
            xvcs:attr-update
                old-value=???
                new-value=testlocation
                name=location
    xvcs:update
        follows=/opt/node/node[2]
        id=35
            xvcs:attr-update
                old-value=/
                new-value=/testurl/
                name=URL
    xvcs:insert
        first-child-of=/opt
        id=75
            node
                URL=/newurl
                location=new location
                node_id=/1234
    

    他们的关键点是将您的 XML 转换为哈希数组 - 可能 - 一个 XY problem。你专注于尝试以一种方式做某事,答案是 - 可能 - 不要那样做。

    【讨论】:

    • 我不知道“XY问题”是这样称呼的。感谢此链接和您的帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 2011-08-11
    • 2018-01-05
    相关资源
    最近更新 更多