The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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
}