NAME

XML::LibXML::Enhanced - adds convenience methods to XML::LibXML and LibXSLT

SYNOPSIS

use XML::LibXML::Enhanced;

my $xml = XML::LibXML::Singleton->instance;
my $xsl = XML::LibXSLT::Singleton->instance;

my $doc = $xml->parse_xml_string("<root/>");

my $root = $doc->getDocumentElement;

$root->appendHash({ name => 'Michael', email => 'mjs@beebo.org' });

DESCRIPTION

ADDED FUNCTIONS

$xml = parse_xml_file($filename)
$xml = parse_xml_string($string)
$xml = parse_xml_chunk($string)

Parses a file or string, and returns an XML::LibXML::Document (parse_xml_file(), parse_xml_string()) or XML::LibXML::DocumentFragment (parse_xml_chunk()).

That is, the equivalent of XML::LibXML::Singleton->instance->parse_file($filename), etc.

$xsl = parse_xslt_file($filename)
$xsl = parse_xslt_string($string)

Parses a file or string, and returns an XML::LibXSLT::Stylesheet. (XML::LibXSLT.)

That is, the equivalent of XML::LibXSLT::Singleton->instance->parse_stylesheet(XML::LibXML::Singleton->instance->parse_file($filename)), etc.

ADDED CLASSES

XML::LibXML::Singleton

Singleton version of XML::LibXML; get an instance via XML::LibXML::SIngleton->instance.

Note that the methods load_ext_dtd(0) and validation(0) have been called on the returned object; see XML::LibXML for futher details.

XML::LibXSLT::Singleton

Singleton version of XML::LibXSLT; get an instance via XML::LibXSLT::SIngleton->instance.

ADDED METHODS

TO XML::LibXML::Node

$n->appendHash( $hash [, $values_are_text ])

Converts $hash to an XML element, and adds it to $n. (That is, the opposite of $hash = $n->toHash.)

If $values_are_text is 1, the values of the hash are treated as text, and are XML-encoded (& to &amp; and so forth) before being added to the node.

If $values_are_text is 0 or undefined, the values of the hash are treated as XML, and are parsed before being added to the node. In this case, the key values must be either be well-formed XML, or well-balanced XML chunks. (i.e. "<foo/><bar/>" is okay, but not "<foo>".) If neither is true, a comment will be inserted in the place of value--NOT BALANCED XML.

For example, if

$hash = {
  name => "Clive",
  email => "clive@example.com",
};

and

$node

is

<row>
</row>

then

$node->appendHash($hash);

results in the $node

<row>
    <name>Clive</name>
    <email>clive@example.com</email>
</row>

NOTE: attribute names (i.e. key values) are lowercased.

$n->appendAttributeHash( $hash )

Adds attributes to node $n.

$h = $n->toHash( [ $values_are_text ] )

Returns a simple hash reference representation of node $n. (That is, the opposite of $n->appendHash($h).)

If $values_are_text is 1, an XML decoding of the values is performed. (&amp; to &, etc.)

If $values_are_text is 0 or undefined, then no transformation of the values are performed.

For example, when toHash() is called on the row node

<row>
  <name>Michael</name>
  <email>mjs@beebo.org</email>
</row>

the return value will be

{
  name => 'Michael',
  email => 'mjs@beebo.org',
}

NOTE:

o

order is not necessarily preserved, and if two or more tags of the same name are present, only one will be present in the hash.

o

attributes are discarded.

$h = $n->toAttributeHash
$n->appendRow($hash [, $name ])

Similar to appendHash($hash) except that the appended hash is added as child of a $name element. That is, if $n is the node "<root/>", $n->appendRow({ name => 'Michael' }, "row") results in

<root>
  <row>
    <name>Michael</name>
  </row>
</root>

$name defaults to "row".

$s = $n->childrenToString

Like toString() except that only the node's children are stringified--the opening and closing tags of the node itself are omitted. (This may create a "balanced chunk.")

AUTHOR

Michael Stillwell <mjs@beebo.org>

# OLD CODE

sub toHash_can_recurse { my ($self, $recursive) = @_;

    $recursive = 0 unless defined $recursive;

    my @children = grep { $_->nodeType == XML_ELEMENT_NODE } 
                        $self->childNodes;
    
    if (@children) {

	# WE GET HERE IF: THERE'S AT LEAST ONE ELEMENT NODE.
	#
	# NOTE: THE FOLLOWING SECTIONS, BY PROCESSING ONLY @children,
	# PROCESS ONLY ELEMENT NODES--ANY TEXT NODES THAT MAY HAVE
	# BEEN CHILDREN OF $self (E.G. IN THE CASE OF MIXED CONTENT)
	# ARE IGNORED.

	if ($recursive) {
	    return {
		map { $_->nodeName, $_->toHash($recursive) }
	            @children
	    };
	}
	
	else {
	    return {
		map { $_->nodeName, $_->childrenToString }
	            @children
	    };
	}

    }
    
    else {

	# WE GET HERE IF: THERE'S EITHER NO CHILDREN, OR NO CHILDREN
	# THAT ARE ELEMENT NODES.  (WE ASSUME THAT IN THE LATTER
	# CASE, THERE'S ONE CHILD, AND IT'S A TEXT NODE.)

	return $self->hasChildNodes ? $self->firstChild->toString : '';
	    
    }

}

sub appendHash_old { my ($self, $hash, $values_are_xml) = @_;

    $values_are_xml = 1 unless defined $values_are_xml;

    my $doc = $self->getOwnerDocument;

    while (my ($k, $v) = each %$hash) {

	my $n = $doc->createElement(lc($k));
	
	if (defined $v) {

	    if (!ref($v)) {
		
		if ($values_are_xml) {

		    my $c = eval {
			XML::LibXML::Singleton->instance->parse_balanced_chunk(
			    $v
			);
		    };

		    if ($@) {
			
			# COULDN'T PARSE $v

			$n->appendChild($doc->createComment(
			    "VALUE NOT BALANCED XML"
			));
		    }
		    else {
			
			# COULD PARSE $v

			$n->appendChild($doc->adoptNode(
			    $c
			));
		    }
		}
		
		else {
		    $n->appendChild($doc->createTextNode($v));
		}
	    }

	    elsif (ref($v) eq "HASH") {
		$n->appendHash($v, $values_are_xml);
	    }

	    else {
		# SOME OTHER SORT OF REFERENCE, SKIP IT (SILENTLY)
	    }
	}
	    
	$self->appendChild($n);
    }
    
    $hash; # because $n->appendChild($c) returns $c
}