我的perl数据如下所示:
$data = {
id => 1,
name => "A",
users => [ { id => 1, name => "u1" }, { id => 2, name => "u2" } ],
groups => [ { id => 1, name => "g1" } ]
};
我想将其转换为xml,如下所示:
<map>
<item id="1" name="A">
<users>
<user id="1" name="u1"/>
<user id="2" name="u2"/>
</users>
<groups>
<group id="1" name="g1"/>
</groups>
</item>
</map>
我可以明确地手动创建每一行。但是,我正在寻找任何CPAN模块基础解决方案。
我尝试过XML :: Twig,但没有去过任何地方。我过去曾经使用过XML :: Simple这样的东西,但这次想尝试其他的东西,因为XML :: Simple已经得到了不好的评论。
答案 0 :(得分:1)
你可以像Sobrique的方法那样做,但字符串硬编码较少,如下所示:
#!/usr/bin/env perl
use strict; use warnings;
use XML::Twig;
my $data = {
id => 1,
name => "A",
users => [ { id => 1, name => "u1" }, { id => 2, name => "u2" } ],
groups => [ { id => 1, name => "g1" } ]
};
sub array_to_elts {
my ( $root, $name, $arrayref ) = @_;
map { $root->insert_new_elt($name, $_) } @{ $arrayref };
}
my $twig = XML::Twig
->new()
->set_xml_version("1.0")
->set_encoding('utf-8');
my $map = XML::Twig::Elt->new('map');
$twig->set_root($map);
my $item = $map->insert_new_elt(
'item',
{ id => $data->{'id'}, name => $data->{'name'} },
);
my $lines = $item->insert_new_elt('groups');
my $links = $item->insert_new_elt('users' );
array_to_elts($lines, 'group', $data->{'groups'});
array_to_elts($links, 'user', $data->{'users' });
$twig->set_pretty_print('indented');
$twig->print;
你可以花费极长的时间来减少硬编码的val,并从原始数据中获得更多的东西,但它很快就会变得难以阅读..
答案 1 :(得分:1)
使用XML::LibXML的“通用”方式。您可能需要向“else”部分添加新代码以处理其他类型的结构。
#!/usr/bin/perl
use warnings;
use strict;
use XML::LibXML;
my $data = {
id => 1,
name => "A",
users => [ { id => 1, name => "u1" },
{ id => 2, name => "u2" } ],
groups => [ { id => 1, name => "g1" } ],
};
sub to_xml {
my ($data, $xml) = @_;
for my $entry (keys %$data) {
my $ref = ref $data->{$entry};
if (not $ref) {
$xml->setAttribute($entry, $data->{$entry});
} elsif ('ARRAY' eq $ref) {
(my $name = $entry) =~ s/s$// or die "Can't guess the element name.\n";
my $list = $xml->addNewChild(q(), $entry);
for my $inner (@{ $data->{$entry} }) {
to_xml($inner, $list->addNewChild(q(), $name));
}
} else {
die "Unhandled structure $ref.\n";
}
}
}
my $xml = 'XML::LibXML::Document'->createDocument;
my $root = $xml->createElement('map');
$xml->setDocumentElement($root);
for my $entry ($data) {
my $item = $root->addNewChild(q(), 'item');
to_xml($entry, $item);
}
print $xml;
答案 2 :(得分:0)
是的,明智的选择。 XML::Simple
......不是。它是 for 简单XML。
正如评论中所述 - 您的数据有点含糊不清 - 具体来说,您如何判断应该在&#39;组内调用哪些元素?或者&#39;用户&#39;。
这看起来你可能已经解析了一些JSON。 (实际上,你可以直接将其转回JSON:
print to_json ( $data, { pretty => 1 } );
核心问题是 - 在JSON支持数组的地方,XML没有。因此,您可以做的很少,直接将您的数据结构转换为XML。
但是,如果你不介意自己做一些工作:
以下是使用XML::Twig
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new( 'pretty_print' => 'indented' );
$twig->set_root(
XML::Twig::Elt->new(
'map',
)
);
my $item = $twig->root->insert_new_elt('item', { 'id' => 1, 'name' => 'A' } );
my $users = $item ->insert_new_elt( 'users' );
$users -> insert_new_elt ( 'user', { 'id' => 1, 'name' => 'u1' } );
$users -> insert_new_elt ( 'user', { 'id' => 2, 'name' => 'u2' } );
my $groups = $item -> insert_new_elt ('last_child', 'groups');
$groups -> insert_new_elt ( 'group', { 'id' => 1, 'name' => 'g1' } );
$twig->set_xml_version("1.0");
$twig->set_encoding('utf-8');
$twig->print;
打印哪些:
<?xml version="1.0" encoding="utf-8"?>
<map>
<item id="1" name="A">
<users>
<user id="2" name="u2"/>
<user id="1" name="u1"/>
</users>
<groups>
<group id="1" name="g1"/>
</groups>
</item>
</map>
迭代您的数据结构留给读者练习。
正如Borodin正确指出的那样 - 您无法从数据结构中推断map
item
group
或user
。后两个你可以或者推断基于复数,但是根据你的数据集,我能想出的最好的是这样的:
use strict;
use warnings;
use XML::Twig;
my $data = {
id => 1,
name => "A",
users => [ { id => 1, name => "u1" }, { id => 2, name => "u2" } ],
groups => [ { id => 1, name => "g1" } ]
};
my $twig = XML::Twig->new( 'pretty_print' => 'indented' );
$twig->set_root( XML::Twig::Elt->new( 'map', ) );
my $item = $twig->root->insert_new_elt('item');
foreach my $key ( keys %$data ) {
if ( not ref $data->{$key} ) {
$item->set_att( $key, $data->{$key} );
next;
}
if ( ref( $data->{$key} ) eq "ARRAY" ) {
my $fakearray = $item->insert_new_elt($key);
foreach my $element ( @{ $data->{$key} } ) {
my $name = $key;
$name =~ s/s$//g;
$fakearray->insert_new_elt( $name, $element );
}
next;
}
if ( ref ( $data -> {$key} ) eq "HASH" ) {
$item -> insert_new_elt( $key, $data -> {$key} );
next;
}
}
$twig->set_xml_version("1.0");
$twig->set_encoding('utf-8');
$twig->print;
这并不理想,因为 - map
是硬编码的,item
也是如此。我采用非常简单的方法来假设数组最后有s
,以便将其复数化。