2009-11-21T15:29:04+01:00

simple (stupid?) other XML way arround

flickr-dullhunk-3948166814.jpg

There are 2625 XML modules atm on CPAN. (`zcat 02packages.details.txt.gz | grep -E '\bXML\b' | wc -l`) So why not create another one? There are number of modules that are trying to map XML structure to Perl data structures. This can never be perfect and sometimes needs custom hooks to adapt. What about the other easy (easier) way around? Serializing Perl data structures to XML? I've made an experiment - Data::asXML. And here is how it looks like:

"Some text"
<VALUE>Some text</VALUE>


[ 1, 22, 333, 4444 ] <ARRAY> <VALUE>1</VALUE> <VALUE>22</VALUE> <VALUE>333</VALUE> <VALUE>4444</VALUE> </ARRAY>
{ heh => 'and', so => [ 'what', '?' ] } <HASH> <KEY name="heh"><VALUE>and</VALUE></KEY> <KEY name='so'> <ARRAY> <VALUE>what</VALUE> <VALUE>?</VALUE> </ARRAY> </KEY> </HASH>

Quite verbose, isn't it? But it should be clear how the data gets serialized to and from XML. My main reason was to have an easy and clear way to pass data to XML::LibXSLT. That meant building a DOM tree with XML::LibXML. As you can see the element names are static - HASH, ARRAY, VALUE. All that is changing are the attributes. The result DOM structure can be easily matched via XPath which is important for XSLT. Here are some examples:

/HASH/KEY[@name="key"]/VALUE
/HASH/KEY[@name="key2"]/ARRAY/*[3]/VALUE
/ARRAY/*[1]/VALUE
/ARRAY/*[2]/HASH/KEY[@name="key3"]/VALUE

I got a it little bit further than just creating a DOM, as now Data::asXML can deal with double references and circular references. Just have a look at how this data is encoded:

my (%hash1, %hash2, %hash3, $scalar_ref3);
%hash1 = (
	'info' => '/me hash1',
	'next' => \%hash2,
	'prev' => \%hash3,
	'more' => \$scalar_ref3,
);
%hash2 = (
	'info' => '/me hash2',
	'next' => \%hash3,
	'prev' => \%hash1,
	'more' => \$scalar_ref3,
);
%hash3 = (
	'info' => '/me hash3',
	'next' => \%hash1,
	'prev' => \%hash2,
	'more' => \$scalar_ref3,
);

print Data::asXML->new->encode([\%hash1, \%hash2, \%hash3])->toString, "\n";
<ARRAY>
	<HASH>
		<KEY name="info">
			<VALUE>/me hash1</VALUE>
		</KEY>
		<KEY name="next">
			<HASH>
				<KEY name="info">
					<VALUE>/me hash2</VALUE>
				</KEY>
				<KEY name="next">
					<HASH>
						<KEY name="info">
							<VALUE>/me hash3</VALUE>
						</KEY>
						<KEY name="next">
							<HASH href="../../../../../../*[1]"/>
						</KEY>
						<KEY name="prev">
							<HASH href="../../../../*[1]"/>
						</KEY>
						<KEY name="more">
							<VALUE type="undef" subtype="ref"/>
						</KEY>
					</HASH>
				</KEY>
				<KEY name="prev">
					<HASH href="../../../../*[1]"/>
				</KEY>
				<KEY name="more">
					<VALUE href="../*[2]/*[1]/*[4]/*[1]"/>
				</KEY>
			</HASH>
		</KEY>
		<KEY name="prev">
			<HASH href="../*[2]/*[1]/*[2]/*[1]"/>
		</KEY>
		<KEY name="more">
			<VALUE href="../*[2]/*[1]/*[2]/*[1]/*[4]/*[1]"/>
		</KEY>
	</HASH>
	<HASH href="*[1]/*[2]/*[1]"/>
	<HASH href="*[1]/*[2]/*[1]/*[2]/*[1]"/>
</ARRAY>

The href attribute holds a relative XPATH to the element that should be referenced. If anyone will ever find it useful, I don't know as I made it so far just to try if its possible and to have some fun with XML and Perl data structures...