———————————————————=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
warnings;
use
Carp;
require
Exporter;
use
AutoLoader;
use
XML::TinyXML::Node;
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