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

时间:2012-07-20 14:23:21

标签: xml perl

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

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

我想输出这个:

<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>

我看不到使用XML::Simple::XMLout执行此操作的方法。我错过了什么吗?

3 个答案:

答案 0 :(得分:6)

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

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

  

查看“ForceArray”,因为你几乎肯定想打开它

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

此代码可满足您的需求。 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);

<强>输出

<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>

<强>更新

您可能更喜欢使用XML::Smart的解决方案,它允许您指定哪些节点是元素,哪些节点是标记。这样您就可以保留原始数据@rooms不受影响。

此程序接受对XML::Simple解决方案的类似哈希引用,并循环遍历所有/rooms/room元素,使用{将所有namecapacity个子节点设置为元素{1}}。

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

如果您对XML中属性和元素的显示顺序不感兴趣,则可以省略对data的调用。

$smart->set_order

<强>输出

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);

答案 1 :(得分:2)

哈希值arrayrefs成为XML元素内容,简单哈希值成为XML属性值。

use strictures;
use XML::Simple qw(:strict);

print XMLout(
    {
        room => [
            {
                id       => 4,
                is_key   => 0,
                name     => ['B507'],
                capacity => [35],
            },
            {
                id       => 5,
                is_key   => 1,
                name     => ['B502'],
                capacity => [24],
            }
        ]
    },
    KeyAttr  => [],
    RootName => 'rooms'
);

<rooms>
  <room id="4" is_key="0">
    <capacity>35</capacity>
    <name>B507</name>
  </room>
  <room id="5" is_key="1">
    <capacity>24</capacity>
    <name>B502</name>
  </room>
</rooms>

答案 2 :(得分:0)

Daxim的回答已经是正确的。因为我输入了它,所以我会发布这个。这是一段代码,可以将您的数据结构转换为您需要的数据结构(Daxim已经指出过)。

my $stuff = { 
  'room' =>  [ 
    map { { 
      'id' => $_->{'id'}, 
      'is_key' => $_->{'is_key'}, 
      'name' => [ $_->{'name'} ], 
      'capacity' => [  $_->{'capacity'} ] 
    } } @rooms 
  ]
};

print XMLout($stuff, RootName=> 'rooms', );