#
# lolxml
#
# Rev. 0.1 Jan. 31, 2010 by zhuo
# Rev. 0.2 Feb. 02, 2010 zhuo
#
# A module to generate an XML string (maybe long) from a list of
# lists organized in a specific manner.
#
# Usage:
# 1. Build a list of lists in a specific format (see the appendix
# for the format details) :
#
# $lol = [ ..... ];
#
# 2. Call the toxml function to generate a XML string.
#
# $xmlstring = lolxml::toxml( $lol, "", " " );
#
# Here, the second argument, "" in this example, specifies the
# default indentation prefix. This is inserted at the beginning of
# every line in the output.
# The third argument, " " in this example, specifies the extra
# indentation string appended to the default indentation prefix
# every time the nest level increases.
#
#
# Appendix: list-of-list format detail
#
# COMMENT:
# [ 'str' ] <->
#
# TREE CONSTRUCTION RULES:
#
# single value:
# [ 'key0', 'val0' ] <-> val0
#
# nest:
# [ 'key0', ['key1', 'val1'] ] <-> val1
#
# listing:
# [ 'key0', ['key1', 'val1'], ['key2','val2'],... ] <-> val1val2...
#
# ATTRIBUTES:
#
# 1) The attribute specifier for a single tag:
#
# 1-a) With a scalar value at the third element, a single value inside
# a nest is treated as an attribute:
# [ 'key0', ['key1', 'val1', ''] ] <->
# [ 'key0', ['key1', '', ''] ] <->
#
# 1-b) An empty key results in a hidden attribute-name field.
# [ 'key0', ['', 'val1', ''] ] <->
#
# 1-c) An empty key with an empty value results in an empty single tag.
# [ 'key0', ['', '', ''] ] <->
# Note that this list does not result in , as expected
# from the example ;
#
# 2) The attribute specifier for an open-close tag pair:
# To force a paired tag representation in stead of a single
# tag, put a non-attribute element or more in the listing:
# [ 'key0', ['key1', 'val1', ''], '' ] <->
# [ 'key0', ['key1', 'val1', ''], 'val0' ] <-> val0
# [ 'key0', ['key1', 'val1', ''], ['key2', 'val2'] ] <-> val2
package lolxml;
use Exporter;
@ISA = qw(Exporter);
@EXPORT = qw( toxml );
sub toxml {
my ( $pNode, $offset, $indent ) = @_;
if ( @$pNode == 1 ) { return sprintf( "%s\n", $offset, $pNode->[0] ); }
my ( $key, @args ) = @$pNode;
my $attr = '';
my $body = '';
foreach my $e ( @args ) {
if ( ref($e) ne 'ARRAY' ) { ## a single value
return sprintf( "%s<%s%s>%s%s>\n", $offset, $key, $attr, $e, $key );
}
if ( @$e == 3 && ref($e->[1]) eq '' ) { ## an attribute
$attr .= ' ';
if ( $e->[0] ne '' ) { $attr .= sprintf( '%s=', $e->[0] ); }
if ( $e->[0] ne '' || $e->[1] ne '' ) { $attr .= sprintf( '"%s"', $e->[1] ); }
} else { ## internal structure
$body .= toxml( $e, $offset . $indent, $indent );
}
}
if ( $body eq '' ) {
return sprintf( "%s<%s%s/>\n", $offset, $key, $attr );
}
return sprintf( "%s<%s%s>\n%s%s%s>\n", $offset, $key, $attr, $body, $offset, $key );
}
1;
__END__