A very easy way to create XML
Back in 1999/2000 when I was first learning Perl, I read an article by a Perl advocate in which he said he believes Perl would become the best language to do XML with. Having been impressed by Perl’s power and ease-of-use (coming from C and Pascal) I imagined how great it would be if Perl’s strengths and ease of use were applied to XML-processing.
However years passed and I couldn’t find a module easy and intuitive enough for me for processing XML. So in 2006 I made my own pure-perl module for personal usage, called XML::MyXML.
It was so easy even I could use it. And I happily develop it until today.
Among other things (parse XML), it lets you treat XML as easily as JSON.
Here’s an example:
use XML::MyXML ':all';
print simple_to_xml(
{
a => {
a1 => 123,
a2 => 234,
a3 => [city => 'New York', city => 'Boston', city => 'Moscow'],
}
},
{tidy => 1},
);
Outputs:
<a>
<a1>123</a1>
<a2>234</a2>
<a3>
<city>New York</city>
<city>Boston</city>
<city>Moscow</city>
</a3>
</a>
Or this example, if you want to create attributes (eg color=”blue”) in your elements:
my @points = ({lat => 10, lng => 10, color => 'blue'}, {lat => 11, lng => 11, color => 'red'}, {lat => 12, lng => 12});
sub point_to_simple {
my $point = shift;
my $color = $point->{color};
return (
# set (2n+1)'th element to be a ref instead of string, to easily set up element's attributes, not just tag
[point => {color => $color}] => {
coords => "$point->{lat},$point->{lng}"
},
);
}
print simple_to_xml(
{
'Points title="my points document"' => [
map point_to_simple($_), @points
],
},
{tidy => 1},
);
This produces the following XML:
<Points title="my points document">
<point color="blue">
<coords>10,10</coords>
</point>
<point color="red">
<coords>11,11</coords>
</point>
<point>
<coords>12,12</coords>
</point>
</Points>
I often have to generate KML files for Google Earth, and this module makes it possible with very short scripts.
You can find more about this module here: XML::MyXML on metacpan
Please write in the comments below, I’d like to know your opinion: Is it module good? Are there other easier-to-use modules on CPAN for this job? Is it powerful enough for others to use? Would you recommend it? And what do you think is missing from it to make it worthy of use by a wider audience?
Thanks!
I think this is very useful, well done. This may duplicate other XML generators/parsers, but seems much simpler to me. Can you retrospectively add attributes or elements to an existing XML?
No, I wouldn't recommend this module. There's a big problem with it, and XML::Simple, and any other module that lets you "treat XML as easily as JSON": XML is not JSON. XML and JSON have entirely different content models.
and:
… are different things in XML. But if I give a module like this a structure
{ foo => { bar => "baz" } }
, it's pot luck which output I'll get. There may be some options I can tweak to get the output I want, but by the time I've figured it out, I might as well have used a DOM module like XML::LibXML, which properly supports XML's content model.Toby, thanks for you input. Just so you know,
[{foo => {bar => 'baz'}}]
and[{foo => {bar => baz}} => undef]
produce the first output, whereas{foo => {bar => baz}}
produces the second.The idea is that each set of sibling elements (regardless of whether they're 1 or more than 1, and regardless of whether they're root or someone's children) are represented as key-value pairs inside a hashref-or-arrayref (your choice), where the key represents the tag or tag+attrs, and the value represents the contents (which can be either undef for no-contents, a string for simple text, or another hashref-or-arrayref for a set of children elements).
Given the above, it should be now clearer that
{foo => {bar => 'baz'}}
represents the root element with tagfoo
and contents{bar => 'baz'}
(since as I said the root element must still be enclosed in a hashref or an arrayref), whereas this:represents the document
<foo bar="baz"/>
Now that you mentioned this, I'll go to write the above in my module's documentation to make things clearer to all. Thanks.
Saif, adding attributes in a particular element is easy by using the attr method once you create an XML::MyXML::Object object from your XML, as described in the xml_to_object function.
Adding elements, and in general, manipulation, is harder (you might be able to achieve it if you have to, with the inner_xml method)
Last year, also facing the problem of generating XML from Perl in a simple way I developed and released XML::FromPerl which is a very thin layer on top of XML::LibXML.
Some code using it to generate complex XML can be seen here!
I updated XML::MyXML with a tutorial that showcases the simple_to_xml function in every possible way.
You can see it here: https://metacpan.org/pod/release/KARJALA/XML-MyXML-1.02/lib/XML/MyXML.pm#simple_to_xml($simple_array_ref)