草庐IT

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

coder 2024-06-25 原文

关于设置 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/

有关XML::复杂散列的简单输出元素顺序的更多相关文章

  1. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  2. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  3. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  4. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  5. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  6. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  7. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  8. ruby - 按值降序排列散列,然后按升序键入 ruby - 2

    我有这样的哈希trial_hash={"key1"=>1000,"key2"=>34,"key3"=>500,"key4"=>500,"key5"=>500,"key6"=>500}我按值降序排列:my_hash=trial_hash.sort_by{|k,v|v}.reverse我现在是这样理解的:[["key1",1000],["key4",500],["key5",500],["key6",500],["key3",500],["key2",34]]但我希望当值相同时按键的升序排序。我该怎么做?例如:上面的散列将以这种方式排序:[["key1",1000],["key3",500

  9. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  10. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

随机推荐