我發現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