XML::Hash::XS(3pm)
π XML::Hash::XS π
okay so bestie, lemme put you onto XML::Hash::XS β it's a Perl module that does hash β XML and XML β hash conversion, and it's written in C so it's fast fast. β¨ It's XML::Hash::XS(3pm) from the User Contributed Perl Documentation, and honestly? iconic. π
β¨ NAME β¨
XML::Hash::XS β Simple and fast hash to XML and XML to hash conversion written in C. no cap, that's literally the whole thing. π¦
πΈ SYNOPSIS πΈ
The functional way, bestie:
use XML::Hash::XS;
my $xmlstr = hash2xml \%hash;
hash2xml \%hash, output => $fh;
my $hash = xml2hash $xmlstr;
my $hash = xml2hash \$xmlstr;
my $hash = xml2hash 'test.xml', encoding => 'cp1251';
my $hash = xml2hash $fh;
my $hash = xml2hash *STDIN;
Or the OOP way, if that's more your vibe:
use XML::Hash::XS qw();
my $conv = XML::Hash::XS->new(utf8 => 0, encoding => 'utf-8')
my $xmlstr = $conv->hash2xml(\%hash, utf8 => 1);
my $hash = $conv->xml2hash($xmlstr, encoding => 'cp1251');
π DESCRIPTION π
This module implements simple hash to XML and XML to hash conversion written in C. π§
During conversion it uses the minimum of memory β the XML or the hash gets written directly, without building a DOM. it's giving efficiency, it's giving lewk. π
Some features are optional and only show up if you have the right libraries installed:
XML::LibXMLlibrary is required in order to build DOMICUoriconvlibrary is required in order to perform charset conversions
π₯ FUNCTIONS π₯
π hash2xml $hash, [ %options ]
$hash is a reference to a hash, babes.
hash2xml
{
node1 => 'value1',
node2 => [ 'value21', { node22 => 'value22' } ],
node3 => \'value3',
node4 => sub { return 'value4' },
node5 => sub { return { node51 => 'value51' } },
},
canonical => 1,
indent => 2,
;
will convert to:
<?xml version="1.0" encoding="utf-8"?>
<root>
<node1>value1</node1>
<node2>value21</node2>
<node2>
<node22>value22</node22>
</node2>
<node3>value3</node3>
<node4>value4</node4>
<node5>
<node51>value51</node51>
</node5>
</root>
and (with use_attr=1):
hash2xml
{
node1 => 'value1',
node2 => [ 'value21', { node22 => 'value22' } ],
node3 => \'value3',
node4 => sub { return 'value4' },
node5 => sub { return { node51 => 'value51' } },
},
use_attr => 1,
canonical => 1,
indent => 2,
;
will convert to:
<?xml version="1.0" encoding="utf-8"?>
<root node1="value1" node3="value3" node4="value4">
<node2>value21</node2>
<node2 node22="value22"/>
<node5 node51="value51"/>
</root>
π¦ xml2hash $xml, [ %options ]
$xml can be a string, a reference to a string, a file handle, or a tied file handle β she's flexible like that:
xml2hash '<root>text</root>';
# output: 'text'
xml2hash '<root a="1" b="2">text</root>';
# output: { a => '1', b => '2', content => 'text' }
open(my $fh, '<', 'test.xml');
xml2hash $fh;
xml2hash *STDIN;
π OPTIONS π
doc[ => 0 ]β # hash2xml. ifdocis'1', then the returned value is anXML::LibXML::Document. πroot[ = 'root' ]β # hash2xml. the root node name.version[ = '1.0' ]β # hash2xml. the XML document version.encoding[ = 'utf-8' ]β # hash2xml+xml2hash. the XML input/output encoding.indent[ = 0 ]β # hash2xml. ifindentis greater than"0", the XML output gets indented according to its hierarchic structure. This value determines the number of spaces. π
if indent is "0", the XML output will all be on one line. one line! efficient!
output[ = undef ]β # hash2xml. the XML output method.
if output is undefined, the XML document is dumped into a string.
if output is an FH, the XML document writes directly to a filehandle or a stream.
canonical[ = 0 ]β # hash2xml. ifcanonicalis"1", the converter will write hashes sorted by key. π€
if canonical is "0", the order of the elements will be pseudo-randomly.
use_attr[ = 0 ]β # hash2xml. ifuse_attris"1", the converter will use the attributes.
if use_attr is "0", the converter will use tags only.
content[ = undef ]β # hash2xml+xml2hash. if defined, that's the key name for the text content (used only ifuse_attr=1).force_array[ = undef ]β # xml2hash. this option is similar to"ForceArray"from theXML::Simplemodule:https://metacpan.org/pod/XML::Simple#ForceArray-=%3E-1-%23-in-important.force_content[ = 0 ]β # xml2hash. this option is similar to"ForceContent"from theXML::Simplemodule:https://metacpan.org/pod/XML::Simple#ForceContent-=%3E-1-%23-in-seldom-used.merge_text[ = 0 ]β # xml2hash. setting this option to"1"will cause adjacent text nodes to merge. π«Άxml_decl[ = 1 ]β # hash2xml. ifxml_declis"1", the output will start with the XML declaration'<?xml version="1.0" encoding="utf-8"?>'.
if xml_decl is "0", the XML declaration will not be output.
trim[ = 0 ]β # hash2xml+xml2hash. trim leading and trailing whitespace from text nodes. βοΈsuppress_empty[ = 0 ]β # xml2hash. this option is similar to"SuppressEmpty"from theXMl::Simplemodule:https://metacpan.org/pod/XML::Simple#SuppressEmpty-=%3E-1-%7C-''-%7C-undef-%23-in+out-handy.utf8[ = 1 ]β # hash2xml+xml2hash. turn on the utf8 flag for strings if enabled.max_depth[ = 1024 ]β # xml2hash. maximum recursion depth. don't go deeper than this, bestie, it's not that kind of party. πbuf_size[ = 4096 ]β # hash2xml+xml2hash. buffer size for reading and encoding data.keep_root[ = 1 ]β # hash2xml+xml2hash. keep root element.filter[ = undef ]β # xml2hash. filter nodes matched by pattern and return a reference to an array of nodes. π
Sample:
my $xml = <<'XML';
<root>
<item1>111</item1>
<item2>222</item2>
<item3>333</item3>
</root>
XML
my $nodes = xml2hash($xml, filter => '/root/item1');
# $nodes = [ 111 ]
my $nodes = xml2hash($xml, filter => ['/root/item1', '/root/item2']);
# $nodes = [ 111, 222 ]
my $nodes = xml2hash($xml, filter => qr[/root/item\d$]);
# $nodes = [ 111, 222, 333 ]
It may be used to parse large XML because it does not require a lot of memory. πΎ
cb[ = undef ]β # xml2hash. this option is used in conjunction with the"filter"option and defines a callback that will be called for each matched node.
Sample:
xml2hash($xml, filter => qr[/root/item\d$], cb => sub {
print $_[0], "\n";
});
# 111
# 222
# 333
method[ = 'NATIVE' ]β # hash2xml. experimental support for conversion methods from other libraries. π§ͺ
if method is 'LX' then the conversion result is the same as using the XML::Hash::LX library.
Note: for the 'LX' method the following additional options are available:
attr
cdata
text
comm
π§ OBJECT SERIALISATION(hash2xml) π§
- When object has a
"toString"method
In this case, the <toString> method of the object is invoked in scalar context. It must return a single scalar that can be directly encoded into XML.
Example:
use XML::LibXML;
local $XML::LibXML::skipXMLDeclaration = 1;
my $doc = XML::LibXML->new->parse_string('<foo bar="1"/>');
print hash2xml({ doc => $doc }, indent => 2, xml_decl => 0);
=>
<root>
<doc><foo bar="1"/></doc>
</root>
- When object has overloaded stringification
In this case, the stringification method of the object is invoked and the result is directly encoded into XML.
Example:
package Test {
use overload '""' => sub { shift->stringify }, fallback => 1;
sub new {
my ($class, $str) = @_;
bless { str => $str }, $class;
}
sub stringify {
shift->{str}
}
}
my $obj = Test->new('test string');
print hash2xml({ obj => $obj }, indent => 2, xml_decl => 0);
=>
<root>
<obj>test string</obj>
</root>
- When object has a
"iternext"method ("NATIVE"method only)
In this case, the <iternext> method will be invoked a few times until the return value is not undefined.
Example:
my $count = 0;
my $o = bless {}, 'Iterator';
*Iterator::iternext = sub { $count++ < 3 ? { count => $count } : undef };
print hash2xml({ item => $o }, use_attr => 1, indent => 2, xml_decl => 0);
=>
<root>
<item count="1"/>
<item count="2"/>
<item count="3"/>
</root>
This can be used to generate a large XML using minimum memory, example with DBI:
my $sth = $dbh->prepare('SELECT * FROM foo WHERE bar=?');
$sth->execute(...);
my $o = bless {}, 'Iterator';
*Iterator::iternext = sub { $sth->fetchrow_hashref() };
open(my $fh, '>', 'data.xml');
hash2xml({ row => $o }, use_attr => 1, indent => 2, xml_decl => 0, output => $fh);
=>
<root>
<row bar="..." ... />
<row bar="..." ... />
...
</root>
π BENCHMARK π
Performance benchmark in comparison with some popular modules (hash2xml):
Rate XML::Hash XML::Hash::LX XML::Simple XML::Hash::XS
XML::Hash 65.0/s -- -6% -37% -99%
XML::Hash::LX 68.8/s 6% -- -33% -99%
XML::Simple 103/s 58% 49% -- -98%
XML::Hash::XS 4879/s 7404% 6988% 4658% --
Benchmark was done on http://search.cpan.org/uploads.rdf
like... 4879/s vs 65.0/s?? she ATE and left no crumbs. π
π AUTHOR π
Yuriy Ustushenko, <yoreek@yahoo.com>
πΈ COPYRIGHT AND LICENSE πΈ
Copyright (C) 2012-2021 Yuriy Ustushenko
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
and that's the whole vibe check bestie, go forth and convert some XML π
mwah π β this was perl v5.40.0, dated 2025-01-02, aka the XML::Hash::XS(3pm) era. slay, periodt. β¨
π¦ where this page comes from
- debian trixie: libxml-hash-xs-perl 0.64-1 Β· MIT
- ubuntu resolute: libxml-hash-xs-perl 0.64-1 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms