From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

=head1 NAME
XML::TinyXML - Little and efficient Perl module to manage xml data.
=head1 SYNOPSIS
use XML::TinyXML;
# first create an XML Context
$xml = XML::TinyXML->new();
$node = XML::TinyXML::Node->new("nodelabel", "somevalue");
# or maybe
$attrs = { attr1 => v1, attr2 => v2 };
$node = XML::TinyXML::Node->new("nodelabel", "somevalue", $attrs);
$xml->addRootNode($node);
# or you could want to create the XML Context
# specifying the root node directly at creation time
$xml = XML::TinyXML->new($node);
# or maybe
$xml = XML::TinyXML->new("rootnode", "somevalue", { attr1 => v1, attr2 => v2 });
# or we can just create an empty root node:
$xml = XML::TinyXML->new("rootnode");
# and then obtain a reference using the getNode() method
$node = $xml->getNode("/rootnode");
# the leading '/' is optional ... since all paths will be absolute and
# first element is assumed to be always a root node
$node = $xml->getNode("rootnode");
# see XML::TinyXML::Node documentation for further details on possible
# operations on a node reference
######## #########
########## hashref2xml and xml2hashref facilities ###########
######## #########
# An useful facility is loading/dumping of hashrefs from/to xml
# for ex:
$hashref = { some => 'thing', someother => 'thing' };
my $xml = XML::TinyXML->new($hashref, 'mystruct');
# or to load on an existing XML::TinyXML object
$xml->loadHash($hashref, 'mystruct');
# we can also create and dump to string all at once :
my $xmlstring = XML::TinyXML->new($hashref, 'mystruct')->dump;
# to reload the hashref back
my $hashref = $xml->toHash;
=head1 DESCRIPTION
Since in some environments it could be desirable to avoid installing
Expat, XmlParser and blahblahblah , needed by most XML-related perl modules,.
my main scope was to obtain a fast xml library usable from perl
(so with a powerful interface) but without the need to install
a lot of other modules (or even C libraries) to have it working.
Once I discovered XS I started porting a very little and efficent
xml library I wrote in C some years ago.
The interesting part of porting it in perl is that now it's really easy
to improve the interface and I was almost always pissed off of installing
more than 10 modules to have a simple xml implementation.
=over
=cut
package XML::TinyXML;
use 5.008008;
use strict;
use Carp;
require Exporter;
our @ISA = qw(Exporter);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
# This allows declaration use XML::TinyXML ':all';
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
# will save memory.
our %EXPORT_TAGS = ( 'all' => [ qw(
) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
XML_BADARGS
XML_GENERIC_ERR
XML_LINKLIST_ERR
XML_MEMORY_ERR
XML_NOERR
XML_OPEN_FILE_ERR
XML_PARSER_GENERIC_ERR
XML_NODETYPE_SIMPLE
XML_NODETYPE_COMMENT
XML_NODETYPE_CDATA
XXmlAddAttribute
XmlAddChildNode
XmlAddRootNode
XmlCountAttributes
XmlCountBranches
XmlCountChildren
XmlCreateContext
XmlCreateNode
XmlDestroyContext
XmlDestroyNode
XmlDump
XmlDumpBranch
XmlGetBranch
XmlGetChildNode
XmlGetChildNodeByName
XmlGetNode
XmlGetNodeValue
XmlParseBuffer
XmlParseFile
XmlRemoveBranch
XmlRemoveNode
XmlSave
XmlSetNodeValue
XmlSubstBranch
);
our $VERSION = '0.02';
sub AUTOLOAD {
# This AUTOLOAD is used to 'autoload' constants from the constant()
# XS function.
my $constname;
our $AUTOLOAD;
($constname = $AUTOLOAD) =~ s/.*:://;
croak "&XML::TinyXML::constant not defined" if $constname eq 'constant';
my ($error, $val) = constant($constname);
if ($error) { croak $error; }
{
no strict 'refs';
# Fixed between 5.005_53 and 5.005_61
#XXX if ($] >= 5.00561) {
#XXX *$AUTOLOAD = sub () { $val };
#XXX }
#XXX else {
*$AUTOLOAD = sub { $val };
#XXX }
}
goto &$AUTOLOAD;
}
require XSLoader;
XSLoader::load('XML::TinyXML', $VERSION);
# Preloaded methods go here.
=item * new ($arg, $param, $attrs, $doctype)
=cut
sub new {
my ($class, $arg, $param, $attrs, $doctype) = @_;
my $self = {} ;
bless($self, $class);
$self->{_ctx} = XmlCreateContext();
if($arg) {
if(UNIVERSAL::isa($arg, "XML::TinyXML::Node")) {
XmlAddRootNode($self->{_ctx}, $arg->{_node});
} elsif(UNIVERSAL::isa($arg, "XmlNodePtr")) {
XmlAddRootNode($self->{_ctx}, $arg);
} elsif(ref($arg) eq "HASH") {
$self->loadHash($arg, $param);
} elsif(defined($arg) && (!ref($arg) || ref($arg) eq "SCALAR")) {
$self->addRootNode($arg, $param, $attrs);
}
}
return $self;
}
=item * addNodeAttribute ($node, $key, $value)
=cut
sub addNodeAttribute {
my ($self, $node, $key, $value) = @_;
return undef unless($node && UNIVERSAL::isa("XML::TinyXML::Node", $node));
return $node->addAttributes($key => $value);
}
=item * removeNodeAttribute ($node, $index)
=cut
sub removeNodeAttribute {
# TODO
}
=item * addRootNode ($name, $val, $attrs)
=cut
sub addRootNode {
my ($self, $name, $val, $attrs) = @_;
$val = "" unless(defined($val));
my $node = XML::TinyXML::Node->new($name, $val);
return undef unless($node);
if($attrs && ref($attrs) eq "HASH") {
$node->addAttributes(%$attrs)
}
return XmlAddRootNode($self->{_ctx}, $node->{_node});
}
=item * dump ()
Returns a stringified version of the XML structure represented internally
=cut
sub dump {
my $self = shift;
return XmlDump($self->{_ctx});
}
=item * loadFile ($path)
Load the xml structure from a file
=cut
sub loadFile {
my ($self, $path) = @_;
return XmlParseFile($self->{_ctx}, $path);
}
=item * loadHash ($hash, $root)
Load the xml structure from an hashref (AKA: convert an hashref to an xml document)
=cut
sub loadHash {
my ($self, $hash, $root) = @_;
$root = "txml"
unless($root);
my $cur = undef;
if(ref($root) && UNIVERSAL::isa("XML::TinyXML::Node", $root)) {
XmlAddRootNode($self->{_ctx}, $root->{_node});
$cur = $root;
} else {
$self->addRootNode($root);
$cur = $self->getNode($root);
}
return $cur->loadHash($hash);
}
=item * toHAsh ()
Dump the xml structure represented internally in the form of an hashref
=cut
sub toHash {
my ($self) = shift;
# only first branch will be parsed ... This means that if multiple root
# nodes are present, only the first one will be parsed and translated
# into an hashred
my $node = $self->getRootNode(1);
return $node->toHash;
}
=item * loadBuffer ($buf)
Load the xml structure from a preloaded memory buffer
=cut
sub loadBuffer {
my ($self, $buf) = @_;
return XmlParseBuffer($self->{_ctx}, $buf);
}
=item * getNode ($path)
Get a node at a specific path.
$path must be of the form: '/rootnode/child1/child2/leafnod'
and the leading '/' is optional (since all paths will be interpreted
as absolute)
Returns an XML::TinyXML::Node object
=cut
sub getNode {
my ($self, $path) = @_;
return XML::TinyXML::Node->new(XmlGetNode($self->{_ctx}, $path));
}
=item * getChildNode ($node, $index)
Get the child of $node at index $index.
Returns an XML::TinyXML::Node object
=cut
sub getChildNode {
my ($self, $node, $index) = @_;
return XML::TinyXML::Node->new(XmlGetChildNode($node, $index));
}
=item * removeNode ($path)
Remove the node at specific $path , if present.
See getNode() documentation for some notes on the $path format.
Returns XML_NOERR (0) if success, error code otherwise.
See Exportable constants for a list of possible error codes
=cut
sub removeNode {
my ($self, $path) = @_;
return XmlRemoveNode($self->{_ctx}, $path);
}
=item * getBranch ($index)
alias for getRootNode
=cut
sub getBranch {
my ($self, $index) = @_;
return XML::TinyXML::Node->new(XmlGetBranch($self->{_ctx}, $index));
}
=item * getRootNode ($index)
Get the root node at $index.
Returns an XML::TinyXML::Node object if present, undef otherwise
=cut
sub getRootNode {
my ($self, $index) = @_;
return $self->getBranch($index);
}
=item * removeBranch ($index)
Remove the rootnode (and all his children) at $index.
=cut
sub removeBranch {
my ($self, $index) = @_;
return XmlRemoveBranch($self->{_ctx}, $index);
}
=item * getChildNodeByName ($node, $name)
Get the child of $node with name == $name.
Returns an XML::TinyXML::Node object if there is such a child, undef otherwise
=cut
sub getChildNodeByName {
my ($self, $node, $name) = @_;
if($node) {
return XML::TinyXML::Node->new(XmlGetChildNodeByName($node, $name));
} else {
my $count = XmlCountBranches($self->{_ctx});
for (my $i = 0 ; $i < $count; $i++ ){
my $res = XmlGetChildNodeByName(XmlGetBranch($self->{_ctx}, $i), $name);
return XML::TinyXML::Node->new($res) if($res)
}
}
return undef;
}
=item * save ($path)
Save the xml document represented internally into $path.
Returns XML_NOERR if success, a specific error code otherwise
=cut
sub save {
my ($self, $path) = @_;
return XmlSave($self->{_ctx}, $path);
}
sub DESTROY {
my $self = shift;
XmlDestroyContext($self->{_ctx})
if($self->{_ctx});
}
# Autoload methods go after =cut, and are processed by the autosplit program.
1;
__END__
=back
=head2 EXPORT
None by default.
=head2 Exportable constants
XML_BADARGS
XML_GENERIC_ERR
XML_LINKLIST_ERR
XML_MEMORY_ERR
XML_NOERR
XML_OPEN_FILE_ERR
XML_PARSER_GENERIC_ERR
XML_UPDATE_ERR
XML_NODETYPE_SIMPLE
XML_NODETYPE_COMMENT
XML_NODETYPE_CDATA
=head2 Exportable functions
TXml *XmlCreateContext()
void XmlDestroyContext(TXml *xml)
int XmlAddAttribute(XmlNode *node, char *name, char *val)
int XmlAddRootNode(TXml *xml, XmlNode *node)
unsigned long XmlCountBranches(TXml *xml)
XmlNode *XmlGetChildNode(XmlNode *node, unsigned long index)
XmlNode *XmlGetNode(TXml *xml, char *path)
int XmlParseBuffer(TXml *xml, char *buf)
int XmlRemoveBranch(TXml *xml, unsigned long index)
int XmlSave(TXml *xml, char *path)
char *XmlDump(TXml *xml)
=head1 SEE ALSO
XML::TinyXML::Node
You should also see libtinyxml documentation (mostly txml.h, redistributed with this module)
=head1 AUTHOR
xant, E<lt>xant@cpan.orgE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2008 by xant
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.
=cut