我发现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 中。
$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);
输出
<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>