XML::复杂散列的简单输出元素顺序

标签 xml perl sorting xml-simple

关于设置 XMLout 返回的 XML 元素的顺序,我已经在不同的地方看到了一些答案。但是,我无法使用这些答案/示例解决问题。

我有一个脚本需要输出一些 XML 数据,并且需要按特定顺序打印某些元素。哈希非常复杂,我无法通过覆盖 XML::Simple 对象中的 sorted_keys 来获得任何结果。嗯,我做到了,但不是我想要的方式。

下面是示例代码,问题的详细信息在代码下面。

#!/usr/bin/perl

use strict;
use warnings;
use XML::Simple;

package MyXMLSimple;
use base 'XML::Simple';

sub sorted_keys
{
 my ($self, $name, $hashref) = @_;
 # ... 
 return $self->SUPER::sorted_keys($name, $hashref);
}

package main;

my $xmlParser = MyXMLSimple->new;

my $items = {
 'status' => 'OK',
 'fields' => {
  'i1' => {
   'header' => 'Header 1',
   'max_size' => '3'
  },
  'i2' => {
   'header' => 'Header 2',
   'max_size' => '8'
  }
 },
 'item_list' => {
  'GGG' => {
   'index' => '3',
   'i' => 3,
   'points' => {
    'p5' => {
     'data' => '10',
    }
   },
  },
  'AAA' => {
   'index' => '1',
   'i' => 2,
   'points' => {
    'p7' => {
     'data' => '22',
    }
   },
  },
  'ZZZ' => {
   'index' => '2',
   'i' => 1,
   'points' => {
    'p6' => {
     'data' => '15',
    }
   },
  }
 }
};

my $xml = $xmlParser->XMLout($items);
print "$xml";

因此,此脚本的输出将是这样的:

<opt status="OK">
  <fields name="i1" header="Header 1" max_size="3" />
  <fields name="i2" header="Header 2" max_size="8" />
  <item_list name="AAA" i="2" index="1">
    <points name="p7" data="22" />
  </item_list>
  <item_list name="GGG" i="3" index="3">
    <points name="p5" data="10" />
  </item_list>
  <item_list name="ZZZ" i="1" index="2">
    <points name="p6" data="15" />
  </item_list>
</opt>

item_list 元素被打印出来,输出顺序按字母顺序排列,通过 name 属性排序。输出顺序为AAA、GGG、ZZZ。

但是,我需要的是在 i 元素上排序(从数字上,从最低到最高)时输出。因此输出将按顺序 ZZZ、AAA、GGG。

我无法控制散列中的顺序(如果不使用 Tie::... 模块),所以我不能那样做。如果我使用 NoSort => 1,输出将不会按任何特定的顺序排序,所以我最终会得到随机输出。

所以,我很确定一定有一种方法可以通过覆盖 sorted_keys 子例程来按照我想要的方式对其进行排序。但是,我无法获得想要的结果,因为 sorted_keys 会为 item_list 的每个实例调用。当为 opt 元素调用 sorted_keys 时,我可以简单地访问整个哈希引用,但如果不依赖 Tie::<,也无法保证输出顺序 模块。

现在,我已经设法让它按照我想要的方式工作,方法是使用 Tie::IxHash 模块,然后重写 sorted_keys 并(重新)创建一个子哈希item_list,通过将原始哈希中的值重新插入到新的(有序的)哈希中,然后删除原始哈希中的子哈希,并用新的有序哈希替换它。

像这样:

sub sorted_keys
{
 my ($self, $name, $hashref) = @_;
 if ($name eq "opt")
 {
  my $clist = { };
  tie %{$clist}, "Tie::IxHash";

  my @sorted_keys = sort { $hashref->{item_list}->{$a}->{i} <=> $hashref->{item_list}->{$b}->{i} } keys %{$hashref->{item_list}};
  foreach my $sorted_key (@sorted_keys)
  {
   $clist->{$sorted_key} = $hashref->{item_list}->{$sorted_key};
  }

  delete $hashref->{item_list};
  $hashref->{item_list} = $clist;
 }
 return $self->SUPER::sorted_keys($name, $hashref);
}

虽然这可行(并且到目前为止似乎可靠地工作),但我相信一定有一种方法可以在不使用 Tie::IxHash 模块并进行所有哈希重新排序/重新排序的情况下实现这一目标,并且只能通过某种方式从 sorted_keys 中排序/返回某些数据。

我只是想不通,我真的不明白 sorted_keys 应该如何工作(尤其是当您使用不同/复杂的输入数据集得到不同的结果时;),但我希望有人知道这一点。

我的意思是,我已经尝试修改 XML/Simple.pm 本身并在 sorted_keys 子例程的最后返回行中更改排序顺序,但我仍然按字母数字排序输出。恐怕我无法弄清楚如何修改它,使其不按 name 排序,而是按 i 排序。

最佳答案

我相信此时您已经超出了 XML::Simple 的范围。如果您关心元素中子元素的顺序,那么是时候使用更像 XML 的模块了。对于您想要的 XML 创建样式,可能是 XML::TreeBuilder ,看new_from_lol方法。或者 XML::LibXML、XML::Twig、XML::Writer...

我过去也曾尝试混合使用 Tie::IxHash 和 XML::Simple,但效果并不理想。你实际上已经走得很远了。但我相信这种方式是疯狂的

关于XML::复杂散列的简单输出元素顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4164491/

相关文章:

java - @XmlEnum 属性与 JAXB

c++ - 解析 XML 文件 : Root Nodes has no child nodes

perl - 如何使 Devel::REPL 输出人类可读的 Unicode?

perl - Perl是否具有等效于Python的多行字符串?

arrays - Scala:如何按元组的第二个元素对元组数组进行排序?

mysql - 为什么 ORDER BY DAYOFWEEK() 的返回不是从星期日开始的?

php - 使用 PHP 在网站上切换语言

java - setContentView 上的另一个 Resources$NotFoundException

Perl - Spreadsheet::WriteExcel 函数解释

angular - 如何使用ngx-datatable实现服务器端分页+服务器端排序