我发现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);
输出
<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
元素,所有name
和capacity
子节点设置为使用set_tag
元件。
注意,XML是使用scalar $smart->data()
因为在列表上下文 调用时data
方法将返回的第二值输出:一个布尔标志指示XML是否是Unicode编码。这似乎没有记录在POD中。
如果您不关心属性和元素在XML中出现的顺序,您可以省略对$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);
输出
<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 Out过程,这似乎是最好的方法。谢谢! – hayesk 2012-07-20 17:40:13
@hayesk:我已经使用'XML :: Smart'添加了一个解决方案,它允许您明确区分XML属性和元素。这避免了对源数据的额外处理。 – Borodin 2012-07-21 11:31:16