Update: Significantly simplified toxml and made it more flexible (output is unchanged).
#!/usr/bin/env perl
use warnings;
use strict;
use open qw/:std :utf8/;
use XML::LibXML;
my $data = { employee => [ {
"************" => "M", age => { dob => "01-04-1993" },
department => { departmentname => "Operations",
title => "Manager" },
location => { town => { county => "Somewhere",
name => "Someplace" } },
name => { forename => "John", surname => "Doe" },
}, {
"************" => "M", age => { dob => "12-12-1979" },
department => { departmentname => "Internet",
title => "Developer" },
location => { town => { county => "Somewhere",
name => "Othertown" } },
name => { forename => "Jane", surname => "Doe" },
} ] };
my $doc = XML::LibXML::Document->createDocument('1.0', 'UTF-8');
toxml($doc, 'data', $data);
print $doc->toString(1);
sub toxml {
my ($parent, $name, $data) = @_;
my @args = $name=~/\A\w+\z/ ? ($name) : ('value', name=>$name);
if ( ref $data eq 'HASH' ) {
my $el = newel($parent, @args);
toxml($el, $_, $data->{$_}) for sort keys %$data;
}
elsif ( ref $data eq 'ARRAY' ) {
toxml(ref eq 'ARRAY' ? newel($parent, @args) : $parent,
$name, $_) for @$data;
}
elsif ( ref $data ) { die "Can't handle $data (yet)" }
else { newel($parent, @args)->appendText($data) }
}
sub newel {
my ($parent, $name, %attrs) = @_;
my $el = $parent->ownerDocument->createElement($name);
$el->setAttribute( $_ => $attrs{$_} ) for keys %attrs;
if ( $parent->nodeType==XML_DOCUMENT_NODE )
{ $parent->setDocumentElement($el) }
else { $parent->appendChild($el) }
return $el;
}
__END__
<?xml version="1.0" encoding="UTF-8"?>
<data>
<employee>
<value name="************">M</value>
<age>
<dob>01-04-1993</dob>
</age>
<department>
<departmentname>Operations</departmentname>
<title>Manager</title>
</department>
<location>
<town>
<county>Somewhere</county>
<name>Someplace</name>
</town>
</location>
<name>
<forename>John</forename>
<surname>Doe</surname>
</name>
</employee>
<employee>
<value name="************">M</value>
<age>
<dob>12-12-1979</dob>
</age>
<department>
<departmentname>Internet</departmentname>
<title>Developer</title>
</department>
<location>
<town>
<county>Somewhere</county>
<name>Othertown</name>
</town>
</location>
<name>
<forename>Jane</forename>
<surname>Doe</surname>
</name>
</employee>
</data>