使用XML :: Simple从哈希数组中构建XML,并将一些键作为属性

hay*_*esk 4 xml perl

我正在使用XML::Simple,我希望将此数据转换为XML:

@rooms = (
   {
      id => 4,
      is_key => 0,
      name => B507,
      capacity => 35
   },
   {
      id => 5,
      is_key => 1,
      name => B502,
      capacity => 24
   }
);
Run Code Online (Sandbox Code Playgroud)

我想输出这个:

<rooms>
   <room id=4 is_key=0>
      <name>B507</name>
      <capacity>35</capacity>
   </room>
   <room id=5 is_key=1>
      <name>B502</name>
      <capacity>24</capacity>
   </room>
</rooms>
Run Code Online (Sandbox Code Playgroud)

我没有看到这样做的方法XML::Simple::XMLout.我错过了什么吗?

Bor*_*din 6

我发现使用XML::Simple不直观且非常尴尬.很容易最终只是抛出随机选项来试图让它工作.

但是如果你坚持下去就有办法.首先,该ForceArray选项非常有用,正如文档所述,

看看"ForceArray",因为你几乎肯定想要打开它

因此,您需要调整数据,使其ForceArray在解析原始XML时看起来有效.这只涉及将所有数据放入一个匿名数组,这些数据应该是元素的内容而不是属性值.

此代码可满足您的需求.该KeepRoot选项只是告诉XMLout顶级哈希是根元素,它不必将整个事物包装在另一个元素中.

use strict;
use warnings;

use XML::Simple;

my @rooms = (
   {
      id => 4,
      is_key => 0,
      name => 'B507',
      capacity => 35
   },
   {
      id => 5,
      is_key => 1,
      name => 'B502',
      capacity => 24
   }
);

for my $room (@rooms) {
  for my $k (keys %$room) {
      $room->{$k} = [ $room->{$k} ] unless grep $k eq $_, qw/ is_key id /;
  }
}

my $xml = {rooms => {room => \@rooms} };

print XMLout($xml, KeepRoot => 1);
Run Code Online (Sandbox Code Playgroud)

产量

<rooms>
  <room id="4" is_key="0">
    <name>B507</name>
    <capacity>35</capacity>
  </room>
  <room id="5" is_key="1">
    <name>B502</name>
    <capacity>24</capacity>
  </room>
</rooms>
Run Code Online (Sandbox Code Playgroud)

更新

您可能更喜欢使用解决方案XML::Smart,它允许您指定哪些节点是元素,哪些节点是标记.这允许您@rooms保持原始数据不变.

该程序接受对XML::Simple解决方案的类似哈希引用,它们遍历所有/rooms/room元素,使用所有元素namecapacity子节点设置元素set_tag.

请注意,XML是使用输出的,scalar $smart->data()因为当在列表上下文中调用时,该data方法将返回第二个值:一个布尔标志,指示XML是否是Unicode编码的.这似乎没有记录在POD中.

$smart->set_order如果您不了解属性和元素在XML中出现的顺序,则可以省略调用.

use strict;
use warnings;

use XML::Smart;

my @rooms = (
   {
      id => 4,
      is_key => 0,
      name => 'B507',
      capacity => 35
   },
   {
      id => 5,
      is_key => 1,
      name => 'B502',
      capacity => 24
   }
);

my $smart = XML::Smart->new;
$smart->{rooms} = { room => \@rooms };

for my $room (@{$smart->{rooms}{room}}) {
  $room->set_order(qw/ id is_key name capacity /);
  $room->{name}->set_tag;
  $room->{capacity}->set_tag;
}

print scalar $smart->data(noheader => 1, nometagen => 1);
Run Code Online (Sandbox Code Playgroud)

产量

<rooms>
  <room id="4" is_key="0">
    <name>B507</name>
    <capacity>35</capacity>
  </room>
  <room id="5" is_key="1">
    <name>B502</name>
    <capacity>24</capacity>
  </room>
</rooms>
Run Code Online (Sandbox Code Playgroud)