Commits

Anonymous committed d069086

memory fix merge
the mm_fix branch becomes obsolete

Modified Files:
Changes LibXML.pm LibXML.xs MANIFEST Makefile.PL dom.c dom.h
perl-libxml-mm.c perl-libxml-mm.h typemap xpath.c
example/article.xml example/article_bad.xml
example/article_internal.xml example/article_internal_bad.xml
example/bad.xml example/cb_example.pl example/dromeds.xml
example/dtd.xml example/libxml.xml example/ns.xml
example/test.xml example/test2.xml example/xml2pod.pl
lib/XML/LibXML/Boolean.pm lib/XML/LibXML/Literal.pm
lib/XML/LibXML/NodeList.pm lib/XML/LibXML/Number.pm
lib/XML/LibXML/SAX/Builder.pm lib/XML/LibXML/SAX/Generator.pm
lib/XML/LibXML/SAX/Parser.pm t/01basic.t t/08findnodes.t
t/10ns.t t/11memory.t t/12html.t t/13dtd.t t/14sax.t
t/15nodelist.t t/16docnodes.t t/17callbacks.t t/18docfree.t
t/19encoding.t

Added Files:
tester.sh t/02parse.t t/03doc.t t/04node.t t/05text.t
t/06elements.t t/07dtd.t t/09xpath.t t/20extras.t

Removed Files:
t/02parsestring.t t/03parsefile.t t/04parsefh.t
t/06nodetypes.t t/07nodelist.t t/09append.t

Comments (0)

Files changed (34)

 Revision history for Perl extension XML::LibXML
 
+1.49
+   - memory management has been completely rewritten.
+        now the module should not cause that many memory leaks 
+   - ownerDocument fixed
+   - parser validation bug fixed (reported by Erik Ray)
+   - made parse_xml_chunk() reporting errors
+   - DOM API is more Level 3 conform
+   - fixed the PI interface
+   - xpath.pl example 
+   - namespace fixes
+
 1.40
    - new parsefunction: $parser->parse_xml_chunk($string);
    - appendChild( $doc_fragment ) bug fixed
 use XML::LibXML::NodeList;
 use IO::Handle; # for FH reads called as methods
 
-$VERSION = "1.40";
+$VERSION = "1.49";
 require Exporter;
 require DynaLoader;
 
 @ISA = qw(DynaLoader Exporter);
 
+$XML::LibXML::skipDTD            = 0;
+$XML::LibXML::skipXMLDeclaration = 0;
+$XML::LibXML::setTagCompression  = 0;
+
 bootstrap XML::LibXML $VERSION;
 
 @EXPORT = qw( XML_ELEMENT_NODE
                                )],
                );
 
-
 sub new {
     my $class = shift;
     my %options = @_;
     my $self = bless \%options, $class;
-
     return $self;
 }
 
     return $self->{XML_LIBXML_EXPAND_XINCLUDE};
 }
 
+sub base_uri {
+    my $self = shift;
+    $self->{XML_LIBXML_BASE_URI} = shift if scalar @_;
+    return $self->{XML_LIBXML_BASE_URI};
+}
+
 sub parse_string {
     my $self = shift;
     croak("parse already in progress") if $self->{_State_};
+
+    unless ( defined $_[0] and length $_[0] ) {
+        croak("Empty String");
+    }
+
     $self->{_State_} = 1;
     my $result;
+
     eval {
         $result = $self->_parse_string( @_ );
     };
+
     my $err = $@;
     $self->{_State_} = 0;
     if ($err) {
         croak $err;
     }
+
+    my $uri = $self->{XML_LIBXML_BASE_URI};
+    $result->setBaseURI( $uri ) if defined $uri;
+
+    if ( defined $self->{XML_LIBXML_EXPAND_XINCLUDE}
+         and  $self->{XML_LIBXML_EXPAND_XINCLUDE} == 1 ) {
+         $self->{_State_} = 1;
+         eval { $self->processXIncludes($result); };
+         my $err = $@;
+         $self->{_State_} = 0;
+         if ($err) {
+             $result = undef;
+             croak $err;
+         }
+     }
+
     return $result;
 }
 
     if ($err) {
         croak $err;
     }
+
+    my $uri = $self->{XML_LIBXML_BASE_URI} ;
+    $result->setBaseURI( $uri ) if defined $uri;
+
+    if ( defined $self->{XML_LIBXML_EXPAND_XINCLUDE}
+         and  $self->{XML_LIBXML_EXPAND_XINCLUDE} == 1 ) {
+         $self->{_State_} = 1;
+         eval { $self->processXIncludes($result); };
+         my $err = $@;
+         $self->{_State_} = 0;
+         if ($err) {
+            $result = undef;
+            croak $err;
+         }
+     }
+
     return $result;
 }
 
     if ($err) {
         croak $err;
     }
+
+    # files will not get a base dir, since they are based by their
+    # filename.
+
+    if ( defined $self->{XML_LIBXML_EXPAND_XINCLUDE}
+         and  $self->{XML_LIBXML_EXPAND_XINCLUDE} == 1 ) {
+
+         $self->{_State_} = 1;
+         eval { $self->processXIncludes($result); };
+         my $err = $@;
+         $self->{_State_} = 0;
+         if ($err) {
+             $result = undef;
+             croak $err;
+         }
+     }
+
     return $result;
 }
 
     # max 2 parameter:
     # 1: the chunk
     # 2: the encoding of the string
-    croak("parse already in progress") if $self->{_State_};
+    croak("parse already in progress") if $self->{_State_};    my $result;
+
+    unless ( defined $_[0] and length $_[0] ) {
+        croak("Empty String");
+    }
+
     $self->{_State_} = 1;
-    my $result;
+
     eval {
         $result = $self->_parse_xml_chunk( @_ );
     };
     if ($err) {
         croak $err;
     }
+
     return $result;
 }
 
+sub processXIncludes {
+    my $self = shift;
+    my $doc = shift;
+    return $self->_processXIncludes($doc || " ");
+}
+
 sub __read {
     read($_[0], $_[1], $_[2]);
 }
 
-@XML::LibXML::Document::ISA         = 'XML::LibXML::Node';
-@XML::LibXML::DocumentFragment::ISA = 'XML::LibXML::Node';
-@XML::LibXML::Element::ISA          = 'XML::LibXML::Node';
-@XML::LibXML::Text::ISA             = 'XML::LibXML::Node';
-@XML::LibXML::Comment::ISA          = 'XML::LibXML::Text';
-@XML::LibXML::CDATASection::ISA     = 'XML::LibXML::Text';
-@XML::LibXML::Attr::ISA             = 'XML::LibXML::Node';
-@XML::LibXML::DocumentFragment::ISA = 'XML::LibXML::Node';
-@XML::LibXML::Dtd::ISA              = 'XML::LibXML::Node';
-@XML::LibXML::PI::ISA               = 'XML::LibXML::Node';
+sub __write {
+    if ( ref( $_[0] ) ) {
+        $_[0]->write( $_[1], $_[2] );
+    }
+    else {
+        $_[0]->write( $_[1] );
+    }
+}
 
 
-sub XML::LibXML::Node::iterator {
+1;
+
+package XML::LibXML::Node;
+
+sub isSupported {
+    my $self    = shift;
+    my $feature = shift;
+    return $self->can($feature) ? 1 : 0;
+}
+
+sub childNodes {
+    my $self = shift;
+    my @children = $self->_childNodes();
+    return wantarray ? @children : XML::LibXML::NodeList->new( @children );
+}
+
+sub attributes {
+    my $self = shift;
+    my @attr = $self->_attributes();
+    return wantarray ? @attr : XML::LibXML::NamedNodeMap->new( @attr );
+}
+
+sub iterator {
     my $self = shift;
     my $funcref = shift;
     my $child = undef;
     return $rv;
 }
 
-sub XML::LibXML::Node::findnodes {
+sub findnodes {
     my ($node, $xpath) = @_;
     my @nodes = $node->_findnodes($xpath);
     if (wantarray) {
     }
 }
 
-sub XML::LibXML::Node::findvalue {
+sub findvalue {
     my ($node, $xpath) = @_;
     return $node->find($xpath)->to_literal->value;
 }
 
-sub XML::LibXML::Node::find {
+sub find {
     my ($node, $xpath) = @_;
     my ($type, @params) = $node->_find($xpath);
     if ($type) {
     return undef;
 }
 
-sub XML::LibXML::Element::getElementsByTagName {
+1;
+
+package XML::LibXML::Document;
+
+use vars qw(@ISA);
+@ISA = 'XML::LibXML::Node';
+
+sub setDocumentElement {
+    my $doc = shift;
+    my $element = shift;
+
+    my $oldelem = $doc->documentElement;
+    if ( defined $oldelem ) {
+        $doc->removeChild($oldelem);
+    }
+
+    $doc->_setDocumentElement($element);
+}
+
+sub toString {
+    my $self = shift;
+    my $flag = shift;
+
+    my $retval = "";
+
+    if ( defined $XML::LibXML::skipXMLDeclaration
+         and $XML::LibXML::skipXMLDeclaration == 1 ) {
+        foreach ( $self->childNodes ){
+            next if $_->nodeType == XML::LibXML::XML_DTD_NODE()
+                    and $XML::LibXML::skipDTD;
+            $retval .= $_->toString;
+        }
+    }
+    else {
+        $retval =  $self->_toString($flag||0);
+    }
+
+    return $retval;
+}
+
+1;
+
+package XML::LibXML::DocumentFragment;
+
+use vars qw(@ISA);
+@ISA = ('XML::LibXML::Node');
+
+sub toString {
+    my $self = shift;
+    my $enc  = shift;
+    my $retval = "";
+    if ( $self->hasChildNodes() ) {
+        foreach my $n ( $self->childNodes() ) {
+            $retval .= $n->toString($enc);
+        }
+    }
+    return $retval;
+}
+
+1;
+
+package XML::LibXML::Element;
+
+use vars qw(@ISA);
+@ISA = ('XML::LibXML::Node');
+
+sub setNamespace {
+    my $self = shift;
+    my $n = $self->nodeName;
+    if ( $self->_setNamespace(@_) ){
+        if ( scalar @_ < 3 || $_[2] == 1 ){
+            $self->setNodeName( $n );
+        }
+        return 1;
+    }
+    return 0;
+}
+
+sub setAttribute {
+    my ( $self, $name, $value ) = @_;
+    if ( $name =~ /^xmlns/ ) {
+        # user wants to set a namespace ...
+
+        (my $lname = $name )=~s/^xmlns://;
+        my $nn = $self->nodeName;
+        if ( $nn =~ /^$lname\:/ ) {
+            $self->setNamespace($value, $lname);
+        }
+        else {
+            # use a ($active = 0) namespace
+            $self->setNamespace($value, $lname, 0);
+        }
+    }
+    else {
+        $self->_setAttribute($name, $value);
+    }
+}
+
+sub getElementsByTagName {
     my ( $node , $name ) = @_;
     my $xpath = "descendant::$name";
     my @nodes = $node->_findnodes($xpath);
-    if (wantarray) {
-        return @nodes;
-    }
-    else {
-        return XML::LibXML::NodeList->new(@nodes);
-    }
+    return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
-sub XML::LibXML::Element::getElementsByTagNameNS {
+sub  getElementsByTagNameNS {
     my ( $node, $nsURI, $name ) = @_;
     my $xpath = "descendant::*[local-name()='$name' and namespace-uri()='$nsURI']";
-        my @nodes = $node->_findnodes($xpath);
-    if (wantarray) {
-        return @nodes;
-    }
-    else {
-        return XML::LibXML::NodeList->new(@nodes);
-    }
+    my @nodes = $node->_findnodes($xpath);
+    return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
-sub XML::LibXML::Element::getElementsByLocalName {
+sub getElementsByLocalName {
     my ( $node,$name ) = @_;
     my $xpath = "descendant::*[local-name()='$name']";
         my @nodes = $node->_findnodes($xpath);
-    if (wantarray) {
-        return @nodes;
+    return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
+}
+
+sub getChildrenByTagName {
+    my ( $node, $name ) = @_;
+    my @nodes = grep { $_->nodeName eq $name } $node->childNodes();
+    return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
+}
+
+sub appendWellBalancedChunk {
+    my ( $self, $chunk ) = @_;
+
+    my $local_parser = XML::LibXML->new();
+    my $frag = $local_parser->parse_xml_chunk( $chunk );
+
+    $self->appendChild( $frag );
+}
+
+1;
+
+package XML::LibXML::Text;
+
+use vars qw(@ISA);
+@ISA = ('XML::LibXML::Node');
+
+sub attributes { return undef; }
+
+sub deleteDataString {
+    my $node = shift;
+    my $string = shift;
+    my $all    = shift;
+    my $data = $node->nodeValue();
+    $string =~ s/([\\\*\+\^\{\}\&\?\[\]\(\)\$\%\@])/\\$1/g;
+    if ( $all ) {
+        $data =~ s/$string//g;
     }
     else {
-        return XML::LibXML::NodeList->new(@nodes);
+        $data =~ s/$string//;
     }
+    $node->setData( $data );
 }
 
+sub replaceDataString {
+    my ( $node, $left, $right,$all ) = @_;
 
-sub XML::LibXML::PI::setData {
+    #ashure we exchange the strings and not expressions!
+    $left  =~ s/([\\\*\+\^\{\}\&\?\[\]\(\)\$\%\@])/\\$1/g;
+    my $datastr = $node->nodeValue();
+    if ( $all ) {
+        $datastr =~ s/$left/$right/g;
+    }
+    else{
+        $datastr =~ s/$left/$right/;
+    }
+    $node->setData( $datastr );
+}
+
+sub replaceDataRegEx {
+    my ( $node, $leftre, $rightre, $flags ) = @_;
+    return unless defined $leftre;
+    $rightre ||= "";
+
+    my $datastr = $node->nodeValue();
+    my $restr   = "s/" . $leftre . "/" . $rightre . "/";
+    $restr .= $flags if defined $flags;
+
+    eval '$datastr =~ '. $restr;
+
+    $node->setData( $datastr );
+}
+
+1;
+
+package XML::LibXML::Comment;
+
+use vars qw(@ISA);
+@ISA = ('XML::LibXML::Text');
+
+1;
+
+package XML::LibXML::CDATASection;
+
+use vars qw(@ISA);
+@ISA     = ('XML::LibXML::Text');
+
+1;
+
+package XML::LibXML::Attr;
+use vars qw( @ISA ) ;
+@ISA = ('XML::LibXML::Node') ;
+
+sub setNamespace {
+    my ($self,$href,$prefix) = @_;
+    my $n = $self->nodeName;
+    if ( $self->_setNamespace($href,$prefix) ) {
+        $self->setNodeName($n);
+        return 1;
+    }
+
+    return 0;
+}
+
+1;
+
+package XML::LibXML::Dtd;
+use vars qw( @ISA );
+@ISA = ('XML::LibXML::Node');
+
+1;
+
+package XML::LibXML::PI;
+use vars qw( @ISA );
+@ISA = ('XML::LibXML::Node');
+
+sub setData {
     my $pi = shift;
 
     my $string = "";
     $pi->_setData( $string ) unless  $string =~ /\?>/;
 }
 
-sub XML::LibXML::Text::deleteDataString {
-    my $node = shift;
-    my $string = shift;
-    my $all    = shift;
-    my $data = $node->getData();
-    $string =~ s/([\\\*\+\^\{\}\&\?\[\]\(\)\$\%\@])/\$1/g;
-    if ( $all ) {
-        $data =~ s/$string//g;
-    }
-    else {
-        $data =~ s/$string//;
-    }
-    $node->setData( $data );
-}
-sub XML::LibXML::Text::replaceDataString {
-    my ( $node, $left, $right,$all ) = @_;
+1;
 
-    #ashure we exchange the strings and not expressions!
-    $left  =~ s/([\\\*\+\^\{\}\&\?\[\]\(\)\$\%\@])/\$1/g;
-    $right =~ s/([\\\*\+\^\{\}\&\?\[\]\(\)\$\%\@])/\$1/g;
-    my $datastr = $node->getData();
-    if ( $all ) {
-        $datastr =~ s/$left/$right/g;
-    }
-    else{
-        $datastr =~ s/$left/$right/;
-    }
-    $node->setData( $datastr );
+package XML::LibXML::Namespace;
+
+# this is infact not a node!
+sub prefix { return "xmlns"; }
+
+sub nodeName {
+    my $self = shift;
+    my $nsP  = $self->name;
+    return length($nsP) ? "xmlns:$nsP" : "xmlns";
 }
 
-sub XML::LibXML::Text::replaceDataRegEx {
-    my ( $node, $leftre, $rightre, $flags ) = @_;
-    return unless defined $leftre;
-    $rightre ||= "";
-
-    my $datastr = $node->getData();
-    my $restr   = "s/" . $leftre . "/" . $rightre . "/";
-    $restr .= $flags if defined $flags;
-
-    eval '$datastr =~ '. $restr;
-
-    $node->setData( $datastr );
+sub isEqualNode {
+    my ( $self, $ref ) = @_;
+    if ( ref($ref) eq "XML::LibXML::Namespace" ) {
+        return $self->_isEqual($ref);
+    }
+    return 0;
 }
 
-sub XML::LibXML::DocumentFragment::toString {
-    my $self = shift;
-    my $enc  = shift;
-    if ( $self->hasChildNodes() ) {
-        return join( "", grep {defined $_} map( {$_->toString($enc)}  $self->childNodes() ) );
+sub isSameNode {
+    my ( $self, $ref ) = @_;
+    if ( $$self == $$ref ){
+        return 1;
     }
-    return "";
+    return 0;
 }
 
 1;
+
+package XML::LibXML::NamedNodeMap;
+
+sub new {
+    my $class = shift;
+    my $self = bless { Nodes => [@_] }, $class;
+    $self->{NodeMap} = { map { $_->nodeName => $_ } @_ };
+    return $self;
+}
+
+sub length     { return scalar( @{$_[0]->{Nodes}} ); }
+sub nodes      { return $_[0]->{Nodes}; }
+sub item       { $_[0]->{Nodes}->[$_[1]]; }
+
+sub getNamedItem {
+    my $self = shift;
+    my $name = shift;
+
+    return $self->{NodeMap}->{$name};
+}
+
+sub setNamedItem {
+    my $self = shift;
+    my $node = shift;
+
+    my $retval;
+    if ( defined $node ) {
+        if ( scalar @{$self->{Nodes}} ) {
+            my $name = $node->nodeName();
+            if ( $name =~ /^xmlns/ ) {
+                warn "not done yet\n";
+            }
+            elsif ( exists $self->{NodeMap}->{$name} ) {
+                $retval = $self->{NodeMap}->{$name}->replaceNode( $node );
+            }
+            else {
+                $self->{Nodes}->[0]->addSibling($node);
+            }
+            $self->{NodeMap}->{$name} = $node;
+            push @{$self->{Nodes}}, $node;
+        }
+        else {
+            # not done yet
+            # can this be properly be done???
+        }
+    }
+    return $retval;
+}
+
+sub removeNamedItem {
+    my $self = shift;
+    my $name = shift;
+    my $retval;
+    if ( $name =~ /^xmlns/ ) {
+        warn "not done yet\n";
+    }
+    elsif ( exists $self->{NodeMap}->{$name} ) {
+        $retval = $self->{NodeMap}->{$name};
+        $retval->unbindNode;
+        delete $self->{NodeMap}->{$name};
+        $self->{Nodes} = [grep {not($retval->isSameNode($_))} @{$self->{Nodes}}];
+    }
+
+    return $retval;
+}
+
+sub getNamedItemNS {
+    my $self = shift;
+    my $nsURI = shift;
+    my $name = shift;
+    return undef;
+}
+
+sub setNamedItemNS {
+    my $self = shift;
+    my $nsURI = shift;
+    my $node = shift;
+    return undef;
+}
+
+sub removeNamedItemNS {
+    my $self = shift;
+    my $nsURI = shift;
+    my $name = shift;
+    return undef;
+}
+
+1;
+
 __END__
 
 =head1 NAME
 If expand_xincludes is set to 1, the method is only required to process
 XIncludes appended to the DOM after its original parsing.
 
+=head1 SERIALIZATION
+
+The oposite of parsing is serialization. In XML::LibXML this can be
+done by using the functions toString(), toFile() and toFH(). All
+serialization functions understand the flag setTagCompression. if this
+Flag is set to 1 empty tags are displayed as <foo></foo>
+rather than <foo/>.
+
+toString() additionally checks two other flags:
+
+skipDTD and skipXMLDeclaration
+
+If skipDTD is specified and any DTD node is found in the document this
+will not be serialized.
+
+If skipXMLDeclaration is set to 1 the documents xml declaration is not
+serialized. This flag will cause the document to be serialized as UTF8
+even if the document has an other encoding specified.
+
+XML::LibXML does not define these flags itself, therefore they have to
+specify them manually by the caller:
+
+ local $XML::LibXML::skipXMLDeclaration = 1;
+ local $XML::LibXML::skipDTD = 1;
+ local $XML::LibXML::setTagCompression = 1;
+
+will cause the serializer to avoid the XML declaration for a document,
+skip the DTD if found, and expand empty tags.
+
+*NOTE* $XML::LibXML::skipXMLDeclaration and $XML::LibXML::skipDTD are
+only recognized by the Documents toString() function.
+
+Additionally it is possible to serialize single nodes by using
+toString() for the node. Since a node has no DTD and no XML
+Declaration the related flags will take no effect. Nevertheless
+setTagCompression is supported.
+
 =head1 XML::LibXML::Document
 
 The objects returned above have a few methods available to them:
 Process any xinclude tags in the file. (currently using B<only> libxml2's
 default callbacks)
 
+
 =head1 XML::LibXML::Dtd
 
 This module allows you to parse and return a DTD object. It has one method
 
 =head1 SEE ALSO
 
-L<XML::LibXSLT>, L<XML::LibXML::Document>,
+L<XML::LibXSLT>, L<XML::LibXML::DOM>, L<XML::LibXML::Document>,
 L<XML::LibXML::Element>, L<XML::LibXML::Node>,
 L<XML::LibXML::Text>, L<XML::LibXML::Comment>,
 L<XML::LibXML::CDATASection>, L<XML::LibXML::Attribute>
 #include "perl.h"
 #include "XSUB.h"
 
+#include <fcntl.h>
+#include <unistd.h>
+
 /* libxml2 stuff */
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
 #include <libxml/HTMLtree.h>
 #include <libxml/tree.h>
 #include <libxml/xpath.h>
-#include <libxml/xmlIO.h>
+#include <libxml2/libxml/xmlIO.h>
 /* #include <libxml/debugXML.h> */
 #include <libxml/xmlerror.h>
 #include <libxml/xinclude.h>
 extern int xmlLoadExtDtdDefaultValue;
 extern int xmlPedanticParserDefaultValue;
 
-#define SET_CB(cb, fld) \
-    RETVAL = cb ? newSVsv(cb) : &PL_sv_undef;\
-    if (SvOK(fld)) {\
-        if (cb) {\
-            if (cb != fld) {\
-                sv_setsv(cb, fld);\
-            }\
-        }\
-        else {\
-            cb = newSVsv(fld);\
-        }\
-    }\
-    else {\
-        if (cb) {\
-            SvREFCNT_dec(cb);\
-            cb = NULL;\
-        }\
-    }
-
 #define TEST_PERL_FLAG(flag) \
     SvTRUE(perl_get_sv(flag, FALSE)) ? 1 : 0
 
-
 static SV * LibXML_match_cb = NULL;
-static SV * LibXML_read_cb = NULL;
-static SV * LibXML_open_cb = NULL;
+static SV * LibXML_read_cb  = NULL;
+static SV * LibXML_open_cb  = NULL;
 static SV * LibXML_close_cb = NULL;
-static SV * LibXML_error = NULL;
+
+static SV * LibXML_error    = NULL;
 
 /* this should keep the default */
 static xmlExternalEntityLoader LibXML_old_ext_ent_loader = NULL;
 
+/* ****************************************************************
+ * Error handler
+ * **************************************************************** */
+
+/* stores libxml errors into $@ */
+void
+LibXML_error_handler(void * ctxt, const char * msg, ...)
+{
+    va_list args;
+    SV * sv;
+
+    sv = NEWSV(0,512);
+
+    va_start(args, msg);
+    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
+    va_end(args);
+
+    if (LibXML_error != NULL) {
+        sv_catsv(LibXML_error, sv); /* remember the last error */
+    }
+    else {
+        croak(SvPV(sv, PL_na));
+    }
+    SvREFCNT_dec(sv);
+}
+
+void
+LibXML_validity_error(void * ctxt, const char * msg, ...)
+{
+    va_list args;
+    SV * sv;
+    
+    sv = NEWSV(0,512);
+    
+    va_start(args, msg);
+    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
+    va_end(args);
+    
+    if (LibXML_error != NULL) {
+        sv_catsv(LibXML_error, sv); /* remember the last error */
+    }
+    else {
+        croak(SvPV(sv, PL_na));
+    }
+    SvREFCNT_dec(sv);
+}
+
+void
+LibXML_validity_warning(void * ctxt, const char * msg, ...)
+{
+    va_list args;
+    STRLEN len;
+    SV * sv;
+    
+    sv = NEWSV(0,512);
+    
+    va_start(args, msg);
+    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
+    va_end(args);
+    
+    warn(SvPV(sv, len));
+    SvREFCNT_dec(sv);
+}
+
+/* ****************************************************************
+ * IO callbacks 
+ * **************************************************************** */
+
+int
+LibXML_read_perl (SV * ioref, char * buffer, int len)
+{   
+    dSP;
+    
+    int cnt;
+    SV * read_results;
+    STRLEN read_length;
+    char * chars;
+    SV * tbuff = NEWSV(0,len);
+    SV * tsize = newSViv(len);
+    
+    ENTER;
+    SAVETMPS;
+    
+    PUSHMARK(SP);
+    EXTEND(SP, 3);
+    PUSHs(ioref);
+    PUSHs(sv_2mortal(tbuff));
+    PUSHs(sv_2mortal(tsize));
+    PUTBACK;
+
+    if (sv_isobject(ioref)) {
+        cnt = perl_call_method("read", G_SCALAR);
+    }
+    else {
+        cnt = perl_call_pv("__read", G_SCALAR);
+    }
+
+    SPAGAIN;
+
+    if (cnt != 1) {
+        croak("read method call failed");
+    }
+
+    read_results = POPs;
+
+    if (!SvOK(read_results)) {
+        croak("read error");
+    }
+
+    read_length = SvIV(read_results);
+
+    chars = SvPV(tbuff, read_length);
+    strncpy(buffer, chars, read_length);
+
+    FREETMPS;
+    LEAVE;
+
+    return read_length;
+}
+
+int 
+LibXML_input_match(char const * filename)
+{
+    int results = 0;
+    SV * global_cb;
+    SV * callback = NULL;
+
+    if (LibXML_match_cb && SvTRUE(LibXML_match_cb)) {
+        callback = LibXML_match_cb;
+    }
+    else if ((global_cb = perl_get_sv("XML::LibXML::match_cb", FALSE))
+             && SvTRUE(global_cb)) {
+        callback = global_cb;
+    }
+
+    if (callback) {
+        int count;
+        SV * res;
+
+        dSP;
+
+        ENTER;
+        SAVETMPS;
+
+        PUSHMARK(SP);
+        EXTEND(SP, 1);
+        PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
+        PUTBACK;
+
+        count = perl_call_sv(callback, G_SCALAR);
+
+        SPAGAIN;
+        
+        if (count != 1) {
+            croak("match callback must return a single value");
+        }
+        
+        res = POPs;
+
+        if (SvTRUE(res)) {
+            results = 1;
+        }
+        
+        PUTBACK;
+        FREETMPS;
+        LEAVE;
+    }
+    
+    return results;
+}
+
+void * 
+LibXML_input_open(char const * filename)
+{
+    SV * results;
+    SV * global_cb;
+    SV * callback = NULL;
+
+    if (LibXML_open_cb && SvTRUE(LibXML_open_cb)) {
+        callback = LibXML_open_cb;
+    }
+    else if ((global_cb = perl_get_sv("XML::LibXML::open_cb", FALSE))
+            && SvTRUE(global_cb)) {
+        callback = global_cb;
+    }
+
+    if (callback) {
+        int count;
+
+        dSP;
+
+        ENTER;
+        SAVETMPS;
+
+        PUSHMARK(SP);
+        EXTEND(SP, 1);
+        PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
+        PUTBACK;
+
+        count = perl_call_sv(callback, G_SCALAR);
+
+        SPAGAIN;
+        
+        if (count != 1) {
+            croak("open callback must return a single value");
+        }
+
+        results = POPs;
+
+        SvREFCNT_inc(results);
+
+        PUTBACK;
+        FREETMPS;
+        LEAVE;
+    }
+    
+    return (void *)results;
+}
+
+int 
+LibXML_input_read(void * context, char * buffer, int len)
+{
+    SV * results = NULL;
+    STRLEN res_len = 0;
+    const char * output;
+    SV * global_cb;
+    SV * callback = NULL;
+    SV * ctxt = (SV *)context;
+
+    if (LibXML_read_cb && SvTRUE(LibXML_read_cb)) {
+        callback = LibXML_read_cb;
+    }
+    else if ((global_cb = perl_get_sv("XML::LibXML::read_cb", FALSE))
+            && SvTRUE(global_cb)) {
+        callback = global_cb;
+    }
+    
+    if (callback) {
+        int count;
+
+        dSP;
+
+        ENTER;
+        SAVETMPS;
+
+        PUSHMARK(SP);
+        EXTEND(SP, 2);
+        PUSHs(ctxt);
+        PUSHs(sv_2mortal(newSViv(len)));
+        PUTBACK;
+
+        count = perl_call_sv(callback, G_SCALAR);
+
+        SPAGAIN;
+        
+        if (count != 1) {
+            croak("read callback must return a single value");
+        }
+
+        output = POPp;
+        if (output != NULL) {
+            res_len = strlen(output);
+            if (res_len) {
+                strncpy(buffer, output, res_len);
+            }
+            else {
+                buffer[0] = 0;
+            }
+        }
+        
+        FREETMPS;
+        LEAVE;
+    }
+    
+    /* warn("read, asked for: %d, returning: [%d] %s\n", len, res_len, buffer); */
+    return res_len;
+}
+
+void 
+LibXML_input_close(void * context)
+{
+    SV * global_cb;
+    SV * callback = NULL;
+    SV * ctxt = (SV *)context;
+
+    if (LibXML_close_cb && SvTRUE(LibXML_close_cb)) {
+        callback = LibXML_close_cb;
+    }
+    else if ((global_cb = perl_get_sv("XML::LibXML::close_cb", FALSE))
+            && SvTRUE(global_cb)) {
+        callback = global_cb;
+    }
+
+    if (callback) {
+        int count;
+
+        dSP;
+
+        ENTER;
+        SAVETMPS;
+
+        PUSHMARK(SP);
+        EXTEND(SP, 1);
+        PUSHs(ctxt);
+        PUTBACK;
+
+        count = perl_call_sv(callback, G_SCALAR);
+
+        SPAGAIN;
+
+        SvREFCNT_dec(ctxt);
+        
+        if (!count) {
+            croak("close callback failed");
+        }
+
+        PUTBACK;
+        FREETMPS;
+        LEAVE;
+    }
+}
+
+int
+LibXML_output_write_handler(void * ioref, char * buffer, int len)
+{   
+    if ( buffer != NULL && len > 0) {
+        dSP;
+
+        int cnt; 
+        SV * read_results;
+        STRLEN read_length;
+        char * chars;
+        SV * tbuff = newSVpv(buffer,len);
+        SV * tsize = newSViv(len);
+
+
+        ENTER;
+        SAVETMPS;
+    
+        PUSHMARK(SP);
+        EXTEND(SP, 3);
+        PUSHs((SV*)ioref);
+        PUSHs(sv_2mortal(tbuff));
+        PUSHs(sv_2mortal(tsize));
+        PUTBACK;
+
+        cnt = perl_call_pv("XML::LibXML::__write", G_SCALAR);
+
+        SPAGAIN;
+
+        if (cnt != 1) {
+            croak("write method call failed");
+        }
+
+        FREETMPS;
+        LEAVE;
+    }
+    return len;
+}
+
+int 
+LibXML_output_close_handler( void * handler )
+{
+    return 1;
+} 
+
 xmlParserInputPtr
 LibXML_load_external_entity(
         const char * URL, 
             return NULL;
         }
         return xmlNewInputFromFile(ctxt, URL);
+    }    
+}
+
+/* ****************************************************************
+ * Helper functions
+ * **************************************************************** */
+
+void
+LibXML_init_parser( SV * self ) {
+    /* we fetch all switches and callbacks from the hash */
+
+    xmlSetGenericErrorFunc(PerlIO_stderr(), 
+                           (xmlGenericErrorFunc)LibXML_error_handler);
+
+    if ( self != NULL ) {
+        /* first fetch the values from the hash */
+        HV* real_obj = (HV *)SvRV(self);
+        SV** item    = NULL;
+        SV * RETVAL  = NULL; /* dummy for the stupid macro */
+
+        item = hv_fetch( real_obj, "XML_LIBXML_VALIDATION", 21, 0 );
+        xmlDoValidityCheckingDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
+
+        item = hv_fetch( real_obj, "XML_LIBXML_EXPAND_ENTITIES", 26, 0 );
+        xmlSubstituteEntitiesDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
+
+        item = hv_fetch( real_obj, "XML_LIBXML_KEEP_BLANKS", 22, 0 );
+        xmlKeepBlanksDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
+        item = hv_fetch( real_obj, "XML_LIBXML_PEDANTIC", 19, 0 );
+        xmlPedanticParserDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
+
+        item = hv_fetch( real_obj, "XML_LIBXML_EXT_DTD", 18, 0 );
+        if ( item != NULL && SvTRUE(*item) )
+            xmlLoadExtDtdDefaultValue |= 1;
+        else
+            xmlLoadExtDtdDefaultValue ^= 1;
+
+        item = hv_fetch( real_obj, "XML_LIBXML_COMPLETE_ATTR", 24, 0 );
+        if (item != NULL && SvTRUE(*item))
+            xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
+        else
+            xmlLoadExtDtdDefaultValue ^= XML_COMPLETE_ATTRS;
+        /* now fetch the callbacks */
+
+        item = hv_fetch( real_obj, "XML_LIBXML_READ_CB", 18, 0 );
+        if ( item != NULL && SvTRUE(*item))
+            LibXML_read_cb= *item;
+
+        item = hv_fetch( real_obj, "XML_LIBXML_MATCH_CB", 19, 0 );
+        if ( item != NULL  && SvTRUE(*item)) 
+            LibXML_match_cb= *item;
+
+        item = hv_fetch( real_obj, "XML_LIBXML_OPEN_CB", 18, 0 );
+        if ( item != NULL  && SvTRUE(*item)) 
+            LibXML_open_cb = *item;
+
+        item = hv_fetch( real_obj, "XML_LIBXML_CLOSE_CB", 19, 0 );
+        if ( item != NULL  && SvTRUE(*item)) 
+            LibXML_close_cb = *item;
+
     }
+
+    return;
+/*    LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader(); */
+/*    warn("      init parser callbacks!\n"); */
+
+    xmlRegisterInputCallbacks((xmlInputMatchCallback) LibXML_input_match,
+                              (xmlInputOpenCallback) LibXML_input_open,
+                              (xmlInputReadCallback) LibXML_input_read,
+                              (xmlInputCloseCallback) LibXML_input_close);
+
+    xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_load_external_entity );
+
+}
+
+void
+LibXML_cleanup_parser() {
+    xmlSubstituteEntitiesDefaultValue = 1;
+    xmlKeepBlanksDefaultValue = 1;
+    xmlGetWarningsDefaultValue = 0;
+    xmlLoadExtDtdDefaultValue = 5;
+    xmlPedanticParserDefaultValue = 0;
+    xmlDoValidityCheckingDefaultValue = 0;
+    xmlSetGenericErrorFunc(NULL, NULL);
+}
+
+void
+LibXML_cleanup_callbacks() {
     
+    return; 
+    xs_warn("      cleanup parser callbacks!\n"); 
+
+    xmlCleanupInputCallbacks();
+    xmlRegisterDefaultInputCallbacks();
+/*    if ( LibXML_old_ext_ent_loader != NULL ) { */
+/*        xmlSetExternalEntityLoader( NULL ); */
+/*        xmlSetExternalEntityLoader( LibXML_old_ext_ent_loader ); */
+/*        LibXML_old_ext_ent_loader = NULL; */
+/*    } */
+/*    xsltSetGenericDebugFunc(NULL, NULL); */
+
 }
 
-int 
-LibXML_input_match(char const * filename)
-{
-    int results = 0;
-    SV * global_cb;
-    SV * callback = NULL;
-
-    if (LibXML_match_cb && SvTRUE(LibXML_match_cb)) {
-        callback = LibXML_match_cb;
-    }
-    else if ((global_cb = perl_get_sv("XML::LibXML::match_cb", FALSE))
-             && SvTRUE(global_cb)) {
-        callback = global_cb;
-    }
-
-    if (callback) {
-        int count;
-        SV * res;
-
-        dSP;
-
-        ENTER;
-        SAVETMPS;
-
-        PUSHMARK(SP);
-        EXTEND(SP, 1);
-        PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
-        PUTBACK;
-
-        count = perl_call_sv(callback, G_SCALAR);
-
-        SPAGAIN;
-        
-        if (count != 1) {
-            croak("match callback must return a single value");
-        }
-        
-        res = POPs;
-
-        if (SvTRUE(res)) {
-            results = 1;
-        }
-        
-        PUTBACK;
-        FREETMPS;
-        LEAVE;
-    }
-    
-    return results;
-}
-
-void * 
-LibXML_input_open(char const * filename)
-{
-    SV * results;
-    SV * global_cb;
-    SV * callback = NULL;
-
-    if (LibXML_open_cb && SvTRUE(LibXML_open_cb)) {
-        callback = LibXML_open_cb;
-    }
-    else if ((global_cb = perl_get_sv("XML::LibXML::open_cb", FALSE))
-            && SvTRUE(global_cb)) {
-        callback = global_cb;
-    }
-
-    if (callback) {
-        int count;
-
-        dSP;
-
-        ENTER;
-        SAVETMPS;
-
-        PUSHMARK(SP);
-        EXTEND(SP, 1);
-        PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
-        PUTBACK;
-
-        count = perl_call_sv(callback, G_SCALAR);
-
-        SPAGAIN;
-        
-        if (count != 1) {
-            croak("open callback must return a single value");
-        }
-
-        results = POPs;
-
-        SvREFCNT_inc(results);
-
-        PUTBACK;
-        FREETMPS;
-        LEAVE;
-    }
-    
-    return (void *)results;
-}
-
-int 
-LibXML_input_read(void * context, char * buffer, int len)
-{
-    SV * results = NULL;
-    STRLEN res_len = 0;
-    const char * output;
-    SV * global_cb;
-    SV * callback = NULL;
-    SV * ctxt = (SV *)context;
-
-    if (LibXML_read_cb && SvTRUE(LibXML_read_cb)) {
-        callback = LibXML_read_cb;
-    }
-    else if ((global_cb = perl_get_sv("XML::LibXML::read_cb", FALSE))
-            && SvTRUE(global_cb)) {
-        callback = global_cb;
-    }
-    
-    if (callback) {
-        int count;
-
-        dSP;
-
-        ENTER;
-        SAVETMPS;
-
-        PUSHMARK(SP);
-        EXTEND(SP, 2);
-        PUSHs(ctxt);
-        PUSHs(sv_2mortal(newSViv(len)));
-        PUTBACK;
-
-        count = perl_call_sv(callback, G_SCALAR);
-
-        SPAGAIN;
-        
-        if (count != 1) {
-            croak("read callback must return a single value");
-        }
-
-        output = POPp;
-        if (output != NULL) {
-            res_len = strlen(output);
-            if (res_len) {
-                strncpy(buffer, output, res_len);
-            }
-            else {
-                buffer[0] = 0;
-            }
-        }
-        
-        FREETMPS;
-        LEAVE;
-    }
-    
-    /* warn("read, asked for: %d, returning: [%d] %s\n", len, res_len, buffer); */
-    return res_len;
-}
-
-void 
-LibXML_input_close(void * context)
-{
-    SV * global_cb;
-    SV * callback = NULL;
-    SV * ctxt = (SV *)context;
-
-    if (LibXML_close_cb && SvTRUE(LibXML_close_cb)) {
-        callback = LibXML_close_cb;
-    }
-    else if ((global_cb = perl_get_sv("XML::LibXML::close_cb", FALSE))
-            && SvTRUE(global_cb)) {
-        callback = global_cb;
-    }
-
-    if (callback) {
-        int count;
-
-        dSP;
-
-        ENTER;
-        SAVETMPS;
-
-        PUSHMARK(SP);
-        EXTEND(SP, 1);
-        PUSHs(ctxt);
-        PUTBACK;
-
-        count = perl_call_sv(callback, G_SCALAR);
-
-        SPAGAIN;
-
-        SvREFCNT_dec(ctxt);
-        
-        if (!count) {
-            croak("close callback failed");
-        }
-
-        PUTBACK;
-        FREETMPS;
-        LEAVE;
-    }
-}
-
-void
-LibXML_error_handler(void * ctxt, const char * msg, ...)
-{
-    va_list args;
-    SV * sv;
-    
-    sv = NEWSV(0,512);
-    
-    va_start(args, msg);
-    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
-    va_end(args);
-    
-    if (LibXML_error != NULL) {
-        sv_catsv(LibXML_error, sv); /* remember the last error */
-    }
-    else {
-        croak(SvPV(sv, PL_na));
-    }
-    SvREFCNT_dec(sv);
-}
-
-void
-LibXML_validity_error(void * ctxt, const char * msg, ...)
-{
-    va_list args;
-    SV * sv;
-    
-    sv = NEWSV(0,512);
-    
-    va_start(args, msg);
-    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
-    va_end(args);
-    
-    if (LibXML_error != NULL) {
-        sv_catsv(LibXML_error, sv); /* remember the last error */
-    }
-    else {
-        croak(SvPV(sv, PL_na));
-    }
-    SvREFCNT_dec(sv);
-}
-
-void
-LibXML_validity_warning(void * ctxt, const char * msg, ...)
-{
-    va_list args;
-    STRLEN len;
-    SV * sv;
-    
-    sv = NEWSV(0,512);
-    
-    va_start(args, msg);
-    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
-    va_end(args);
-    
-    warn(SvPV(sv, len));
-    SvREFCNT_dec(sv);
-}
-
-int
-LibXML_read_perl (SV * ioref, char * buffer, int len)
-{
-    dSP;
-    
-    int cnt;
-    SV * read_results;
-    STRLEN read_length;
-    char * chars;
-    SV * tbuff = NEWSV(0,len);
-    SV * tsize = newSViv(len);
-    
-    ENTER;
-    SAVETMPS;
-    
-    PUSHMARK(SP);
-    EXTEND(SP, 3);
-    PUSHs(ioref);
-    PUSHs(sv_2mortal(tbuff));
-    PUSHs(sv_2mortal(tsize));
-    PUTBACK;
-    
-    if (sv_isobject(ioref)) {
-        cnt = perl_call_method("read", G_SCALAR);
-    }
-    else {
-        cnt = perl_call_pv("__read", G_SCALAR);
-    }
-    
-    SPAGAIN;
-    
-    if (cnt != 1) {
-        croak("read method call failed");
-    }
-    
-    read_results = POPs;
-    
-    if (!SvOK(read_results)) {
-        croak("read error");
-    }
-    
-    read_length = SvIV(read_results);
-    
-    chars = SvPV(tbuff, read_length);
-    strncpy(buffer, chars, read_length);
-    
-    FREETMPS;
-    LEAVE;
-    
-    return read_length;
-}
+/* ****************************************************************
+ * general parse functions 
+ * **************************************************************** */
 
 xmlDocPtr
 LibXML_parse_stream(SV * self, SV * ioref, char * directory)
         croak( "Empty Stream" );
     }
     
-    if (!well_formed || (xmlDoValidityCheckingDefaultValue && !valid && (doc->intSubset || doc->extSubset) )) {
+    if (
+        !well_formed
+        || ( xmlDoValidityCheckingDefaultValue
+             && !valid
+             && (doc->intSubset
+                 || doc->extSubset) ) 
+        ) {
         xmlFreeDoc(doc);
         return NULL;
     }
+
     /* this should be done by libxml2 !? */
     if (doc->encoding == NULL) {
-        doc->encoding = xmlStrdup((const xmlChar*)"utf-8");
+        /*  *LEAK NOTE* i am not shure if this is correct */
+        doc->encoding = xmlStrdup((const xmlChar*)"UTF-8");
     }
 
     if ( directory == NULL ) {
     
     read_length = LibXML_read_perl(ioref, buffer, 4);
     if (read_length > 0) {
-        ctxt = htmlCreatePushParserCtxt(NULL, NULL, buffer, read_length, NULL, XML_CHAR_ENCODING_NONE);
+        ctxt = htmlCreatePushParserCtxt(NULL, NULL, buffer, read_length,
+                                        NULL, XML_CHAR_ENCODING_NONE);
         if (ctxt == NULL) {
-            croak("Could not create html push parser context: %s", strerror(errno));
-        }
+            croak("Could not create html push parser context: %s",
+                  strerror(errno));
+        }
+
         ctxt->_private = (void*)self;
 
         while(read_length = LibXML_read_perl(ioref, buffer, 1024)) {
     return doc;
 }
 
-void
-LibXML_cleanup_parser() {
-    xmlSubstituteEntitiesDefaultValue = 1;
-    xmlKeepBlanksDefaultValue = 1;
-    xmlGetWarningsDefaultValue = 0;
-    xmlLoadExtDtdDefaultValue = 5;
-    xmlPedanticParserDefaultValue = 0;
-    xmlDoValidityCheckingDefaultValue = 0;
-    xmlSetGenericErrorFunc(NULL, NULL);
-}
-
-void
-LibXML_init_parser( SV * self ) {
-    /* we fetch all switches and callbacks from the hash */
-
-    xmlSetGenericErrorFunc(PerlIO_stderr(), 
-                           (xmlGenericErrorFunc)LibXML_error_handler);
-
-    if ( self != NULL ) {
-        /* first fetch the values from the hash */
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        SV * RETVAL  = NULL; /* dummy for the stupid macro */
-
-        item = hv_fetch( real_obj, "XML_LIBXML_VALIDATION", 21, 0 );
-        xmlDoValidityCheckingDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
-
-        item = hv_fetch( real_obj, "XML_LIBXML_EXPAND_ENTITIES", 26, 0 );
-        xmlSubstituteEntitiesDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
-
-        item = hv_fetch( real_obj, "XML_LIBXML_KEEP_BLANKS", 22, 0 );
-        xmlKeepBlanksDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
-        item = hv_fetch( real_obj, "XML_LIBXML_PEDANTIC", 19, 0 );
-        xmlPedanticParserDefaultValue = item != NULL && SvTRUE(*item) ? 1 : 0;
-
-        item = hv_fetch( real_obj, "XML_LIBXML_EXT_DTD", 18, 0 );
-        if ( item != NULL && SvTRUE(*item) )
-            xmlLoadExtDtdDefaultValue |= 1;
-        else
-            xmlLoadExtDtdDefaultValue ^= 1;
-
-        item = hv_fetch( real_obj, "XML_LIBXML_COMPLETE_ATTR", 24, 0 );
-        if (item != NULL && SvTRUE(*item))
-            xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
-        else
-            xmlLoadExtDtdDefaultValue ^= XML_COMPLETE_ATTRS;
-        /* now fetch the callbacks */
-
-        item = hv_fetch( real_obj, "XML_LIBXML_READ_CB", 18, 0 );
-        if ( item != NULL && SvTRUE(*item))
-            LibXML_read_cb= *item;
-
-        item = hv_fetch( real_obj, "XML_LIBXML_MATCH_CB", 19, 0 );
-        if ( item != NULL  && SvTRUE(*item)) 
-            LibXML_match_cb= *item;
-
-        item = hv_fetch( real_obj, "XML_LIBXML_OPEN_CB", 18, 0 );
-        if ( item != NULL  && SvTRUE(*item)) 
-            LibXML_open_cb = *item;
-
-        item = hv_fetch( real_obj, "XML_LIBXML_CLOSE_CB", 19, 0 );
-        if ( item != NULL  && SvTRUE(*item)) 
-            LibXML_close_cb = *item;
-
-    }
-
-    return;
-/*    LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader(); */
-/*    warn("      init parser callbacks!\n"); */
-
+MODULE = XML::LibXML         PACKAGE = XML::LibXML
+
+PROTOTYPES: DISABLE
+
+BOOT:
+    LIBXML_TEST_VERSION
+    xmlInitParser();
+
+    /* make the callback mechnism available to perl coders */
     xmlRegisterInputCallbacks((xmlInputMatchCallback) LibXML_input_match,
                               (xmlInputOpenCallback) LibXML_input_open,
                               (xmlInputReadCallback) LibXML_input_read,
                               (xmlInputCloseCallback) LibXML_input_close);
 
-    xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_load_external_entity );
-
-}
-
-void
-LibXML_cleanup_callbacks() {
-    
-    return; 
-/*   warn("      cleanup parser callbacks!\n"); */
-
-    xmlCleanupInputCallbacks();
-    xmlRegisterDefaultInputCallbacks();
-/*    if ( LibXML_old_ext_ent_loader != NULL ) { */
-        /* xmlSetExternalEntityLoader( NULL ); */
-/*        xmlSetExternalEntityLoader( LibXML_old_ext_ent_loader ); */
-/*        LibXML_old_ext_ent_loader = NULL; */
-/*    } */
-
-/*    xsltSetGenericDebugFunc(NULL, NULL); */
-
-}
-
-MODULE = XML::LibXML         PACKAGE = XML::LibXML
-
-PROTOTYPES: DISABLE
-
-BOOT:
-    LIBXML_TEST_VERSION
-    xmlInitParser();
-    xmlRegisterInputCallbacks((xmlInputMatchCallback) LibXML_input_match,
-                              (xmlInputOpenCallback) LibXML_input_open,
-                              (xmlInputReadCallback) LibXML_input_read,
-                              (xmlInputCloseCallback) LibXML_input_close);
     xmlSetGenericErrorFunc( NULL , 
                            (xmlGenericErrorFunc)LibXML_error_handler);
     xmlDoValidityCheckingDefaultValue = 0;
     OUTPUT:
         RETVAL
 
-
 SV*
 _parse_string(self, string, directory = NULL)
         SV * self
         int valid;
         int ret;
         xmlDocPtr real_dom;
-        ProxyObject * proxy;
         HV* real_obj = (HV *)SvRV(self);
         SV** item    = NULL;
     CODE:
             real_dom->URL = xmlStrdup((const xmlChar*)directory);
         }
 
-        if (!well_formed || (xmlDoValidityCheckingDefaultValue && !valid && (real_dom->intSubset || real_dom->extSubset) )) {
+        if (!well_formed
+            || (xmlDoValidityCheckingDefaultValue
+                && !valid 
+                && (real_dom->intSubset || real_dom->extSubset) ) ) {
             xmlFreeDoc(real_dom);
             RETVAL = &PL_sv_undef;    
             croak(SvPV(LibXML_error, len));
         }
+        else if (xmlDoValidityCheckingDefaultValue
+                 && SvLEN(LibXML_error) > 0
+                 && (real_dom->intSubset || real_dom->extSubset) ) {
+            croak(SvPV(LibXML_error, len));
+        }
         else {
-            STRLEN n_a;
-            # ok check the xincludes
-            item = hv_fetch( real_obj, "XML_LIBXML_EXPAND_XINCLUDE", 26, 0 );
-            if ( item != NULL && SvTRUE(*item) ) {
-                # warn( "xinclude\n" );
-                xmlXIncludeProcess(real_dom);
-            }
-
-            RETVAL = nodeToSv((xmlNodePtr)real_dom);
-            real_dom->_private = RETVAL;
-            setSvNodeExtra(RETVAL,RETVAL);
+            RETVAL = PmmNodeToSv((xmlNodePtr)real_dom, NULL);
         }        
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser(); 
         char * CLASS = "XML::LibXML::Document";
         STRLEN len;
         xmlDocPtr real_dom;
-        ProxyObject* proxy;
     CODE:
         LibXML_error = NEWSV(0, 512);
         sv_setpvn(LibXML_error, "", 0);
             RETVAL = &PL_sv_undef;    
             croak(SvPV(LibXML_error, len));
         }
+        else if (xmlDoValidityCheckingDefaultValue
+                 && SvLEN(LibXML_error) > 0
+                 && (real_dom->intSubset || real_dom->extSubset)  ) {
+            croak(SvPV(LibXML_error, len));
+        }
         else {
-            STRLEN n_a;
-            HV* real_self = (HV*)SvRV(self);
-            SV** item;
-            # ok check the xincludes
-            item = hv_fetch( real_self, "XML_LIBXML_EXPAND_XINCLUDE", 26, 0 );
-            if ( item != NULL && SvTRUE(*item) ) 
-                xmlXIncludeProcess(real_dom);
-
-            RETVAL = nodeToSv((xmlNodePtr)real_dom);
-            real_dom->_private = RETVAL;
-            setSvNodeExtra(RETVAL,RETVAL);
+            RETVAL = PmmNodeToSv((xmlNodePtr)real_dom,NULL);
         }
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
     OUTPUT:
         RETVAL
-        
+
 SV*
 _parse_file(self, filename)
         SV * self
         int valid = 0;
         STRLEN len;
         xmlDocPtr real_dom = NULL;
-        ProxyObject * proxy = NULL;
     CODE:
         LibXML_init_parser(self);
         ctxt = xmlCreateFileParserCtxt(filename);
         
         sv_2mortal(LibXML_error);
         
-        if (!well_formed || (xmlDoValidityCheckingDefaultValue && !valid && (real_dom->intSubset || real_dom->extSubset) )) {
+        if (!well_formed || (xmlDoValidityCheckingDefaultValue && (!valid|| SvLEN(LibXML_error) > 0 ) && (real_dom->intSubset || real_dom->extSubset) )) {
             xmlFreeDoc(real_dom);
             RETVAL = &PL_sv_undef ;  
             croak(SvPV(LibXML_error, len));
         }
         else {
-            HV* real_self = (HV*)SvRV(self);
-            SV** item = NULL;
-
-            # ok check the xincludes
-            item = hv_fetch( real_self, "XML_LIBXML_EXPAND_XINCLUDE", 26, 0 );
-            if ( item != NULL && SvTRUE(*item) )  {
-                # warn( "xincludes\n" );
-                xmlXIncludeProcess(real_dom);
-            }
-
-            RETVAL = nodeToSv((xmlNodePtr)real_dom);
-            real_dom->_private = RETVAL;
-            setSvNodeExtra(RETVAL,RETVAL);
+            RETVAL = PmmNodeToSv((xmlNodePtr)real_dom, NULL);
         }
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
         int well_formed;
         int ret;
         xmlDocPtr real_dom;
-        ProxyObject * proxy;
     CODE:
         ptr = SvPV(string, len);
         if (len == 0) {
             SV * newURI = newSVpvf("unknown-%12.12d", real_dom);
             real_dom->URL = xmlStrdup((const xmlChar*)SvPV(newURI, n_a));
             SvREFCNT_dec(newURI);
-            RETVAL = nodeToSv((xmlNodePtr)real_dom);
-            real_dom->_private = RETVAL;
-            setSvNodeExtra(RETVAL,RETVAL);
+            RETVAL = PmmNodeToSv((xmlNodePtr)real_dom, NULL);
         }
     OUTPUT:
         RETVAL
             SV * newURI = newSVpvf("unknown-%12.12d", real_dom);
             real_dom->URL = xmlStrdup((const xmlChar*)SvPV(newURI, n_a));
             SvREFCNT_dec(newURI);
-            RETVAL = nodeToSv((xmlNodePtr)real_dom);
-            real_dom->_private = RETVAL;
-            setSvNodeExtra(RETVAL,RETVAL);
+            RETVAL = PmmNodeToSv( (xmlNodePtr)real_dom, NULL ); 
         }
     OUTPUT:
         RETVAL
         char * CLASS = "XML::LibXML::Document";
         STRLEN len;
         xmlDocPtr real_dom;
-        ProxyObject * proxy;
     CODE:
         LibXML_error = NEWSV(0, 512);
         sv_setpvn(LibXML_error, "", 0);
             croak(SvPV(LibXML_error, len));
         }
         else {
-            RETVAL = nodeToSv( (xmlNodePtr)real_dom ); 
-            real_dom->_private = RETVAL;
-            setSvNodeExtra(RETVAL,RETVAL);
+            RETVAL = PmmNodeToSv( (xmlNodePtr)real_dom, NULL ); 
         }
     OUTPUT:
         RETVAL
         xmlChar *chunk;
         xmlNodePtr rv = NULL;
         xmlNodePtr fragment= NULL;
-        ProxyObject *ret=NULL;
         xmlNodePtr rv_end = NULL;
         char * ptr;
         STRLEN len;
 
         if ( chunk != NULL ) {
             LibXML_error = sv_2mortal(newSVpv("", 0));
+
             LibXML_init_parser(self);
             rv = domReadWellBalancedString( NULL, chunk );
             LibXML_cleanup_callbacks();
                 # warn( "good chunk, create fragment" );
 
                 /* step 1: create the fragment */
-                fragment = xmlNewDocFragment( NULL );
-                RETVAL = nodeToSv(fragment);
-                setSvNodeExtra(RETVAL,RETVAL);
+                fragment = xmlNewDocFragment( NULL );        
+                RETVAL = PmmNodeToSv(fragment,NULL);
 
                 /* step 2: set the node list to the fragment */
                 fragment->children = rv;
             }
             else {
                 # warn( "bad chunk" );
+                croak(SvPV(LibXML_error, len));
                 XSRETURN_UNDEF;
             }
             /* free the chunk we created */
     OUTPUT:
         RETVAL
 
-void
-processXIncludes( self, dom )
+
+int
+_processXIncludes( self, dom )
         SV * self
         SV * dom
     PREINIT:
-        xmlDocPtr real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
+        xmlDocPtr real_dom = (xmlDocPtr)PmmSvNode(dom);
+        char * ERROR;
+        STRLEN len;
     CODE:
-        # first init the stuff for the parser
+        if ( real_dom == NULL ) {
+            croak("No document to process!");
+        }
+        LibXML_error = sv_2mortal(newSVpv("", 0));
+
         LibXML_init_parser(self);
-        xmlXIncludeProcess(real_dom);        
+        RETVAL = xmlXIncludeProcess(real_dom);        
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
 
+        ERROR = SvPV(LibXML_error, len );
+    
+        if ( len > 0 ){
+                croak(ERROR);
+                XSRETURN_UNDEF;            
+        }
+        else {
+            RETVAL = 1;
+        }
+    OUTPUT:
+        RETVAL
+
 SV*
 encodeToUTF8( encoding, string )
         const char * encoding
     OUTPUT:
         RETVAL
 
-
 MODULE = XML::LibXML         PACKAGE = XML::LibXML::Document
 
-void
-DESTROY(self)
-        ProxyObject* self
-    CODE:
-        if ( self->object != NULL ) {
-            if ( self->extra != NULL && SvREFCNT( self->extra ) > 1 ) {
-                SvREFCNT_dec( self->extra );
-#                warn( "TWO Document nodes" );
-            } else {
-                xmlFreeDoc((xmlDocPtr)self->object);
-#                warn( "REAL DOCUMENT DROP SUCCEEDS" );
-            }
-        }        
-        self->object = NULL;
-        Safefree( self );
-
 SV *
-toString(self, format=0)
-        ProxyObject* self
+_toString(self, format=0)
+        SV * self
         int format
     PREINIT:
         xmlDocPtr real_dom;
         xmlChar *result=NULL;
         int len=0;
+        SV* internalFlag = NULL;
+        int oldTagFlag = xmlSaveNoEmptyTags;
+        xmlDtdPtr intSubset = NULL;
     CODE:
-        real_dom = (xmlDocPtr)self->object;
+        real_dom = (xmlDocPtr)PmmNODE(SvPROXYNODE(self));
+        internalFlag = perl_get_sv("XML::LibXML::setTagCompression", 0);
+        if( internalFlag ) {
+            xmlSaveNoEmptyTags = SvTRUE(internalFlag);
+        }
+
+        internalFlag = perl_get_sv("XML::LibXML::skipDTD", 0);
+        if ( internalFlag && SvTRUE(internalFlag) ) {
+            intSubset = xmlGetIntSubset( real_dom );
+            if ( intSubset )
+                xmlUnlinkNode( (xmlNodePtr)intSubset );
+        }
+
         if ( format <= 0 ) {
             # warn( "use no formated toString!" );
             xmlDocDumpMemory(real_dom, &result, &len);
             xmlIndentTreeOutput = t_indent_var;
         }
 
+        if ( intSubset != NULL ) {
+            if (real_dom->children == NULL)
+                 xmlAddChild((xmlNodePtr) real_dom, (xmlNodePtr) intSubset);
+            else
+                xmlAddPrevSibling(real_dom->children, (xmlNodePtr) intSubset);
+        }
+
+        xmlSaveNoEmptyTags = oldTagFlag;
+
     	if (result == NULL) {
 	        # warn("Failed to convert doc to string");           
-            RETVAL = &PL_sv_undef;
+            XSRETURN_UNDEF;
     	} else {
             # warn("%s, %d\n",result, len);
-            RETVAL = newSVpvn((char *)result, (STRLEN)len);
+            RETVAL = C2Sv( result, real_dom->encoding );
             xmlFree(result);
-#ifdef HAVE_UTF8
-            xs_warn( "use utf8" );
-            SvUTF8_on(RETVAL);
-#endif
         }
     OUTPUT:
         RETVAL
 
+int 
+toFH( self, filehandler, format=1 )
+        SV * self
+        SV * filehandler
+        int format
+    PREINIT:
+        xmlOutputBufferPtr buffer;
+        const xmlChar * encoding = NULL;
+        xmlCharEncodingHandlerPtr handler = NULL;
+        SV* internalFlag = NULL;
+        int oldTagFlag = xmlSaveNoEmptyTags;
+        xmlDtdPtr intSubset = NULL;
+        xmlDocPtr doc = (xmlDocPtr)PmmSvNode( self );
+    CODE:
+        internalFlag = perl_get_sv("XML::LibXML::setTagCompression", 0);
+        if( internalFlag ) {
+            xmlSaveNoEmptyTags = SvTRUE(internalFlag);
+        }
+
+        internalFlag = perl_get_sv("XML::LibXML::skipDTD", 0);
+        if ( internalFlag && SvTRUE(internalFlag) ) {
+            intSubset = xmlGetIntSubset( doc );
+            if ( intSubset )
+                xmlUnlinkNode( (xmlNodePtr)intSubset );
+        }
+
+        xmlRegisterDefaultOutputCallbacks();
+        encoding = ((xmlDocPtr) PmmSvNode(self))->encoding;
+        if ( encoding != NULL ) {
+            if ( xmlParseCharEncoding(encoding) != XML_CHAR_ENCODING_UTF8) {
+                handler = xmlFindCharEncodingHandler(encoding);
+            }
+        }
+        else {
+            warn("no encoding?");
+        }
+        buffer = xmlOutputBufferCreateIO( (xmlOutputWriteCallback) &LibXML_output_write_handler,
+                                          (xmlOutputCloseCallback)&LibXML_output_close_handler,
+                                          filehandler,
+                                          handler ); 
+        RETVAL =xmlSaveFormatFileTo( buffer, 
+                                     doc,
+                                     encoding,
+                                     format);
+        if ( intSubset != NULL ) {
+            if (doc->children == NULL)
+                xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) intSubset);
+            else
+                xmlAddPrevSibling(doc->children, (xmlNodePtr) intSubset);
+        }
+
+        xmlSaveNoEmptyTags = oldTagFlag;
+        xmlOutputBufferClose( buffer );
+    OUTPUT:
+        RETVAL    
+
+int 
+toFile( self, filename )
+        SV * self
+        char * filename
+    PREINIT:
+        SV* internalFlag = NULL;
+        int oldTagFlag = xmlSaveNoEmptyTags;
+    CODE:
+        internalFlag = perl_get_sv("XML::LibXML::setTagCompression", 0);
+        if( internalFlag ) {
+            xmlSaveNoEmptyTags = SvTRUE(internalFlag);
+        }
+
+        RETVAL = xmlSaveFile( filename, (xmlDocPtr)PmmSvNode(self) );
+
+        xmlSaveNoEmptyTags = oldTagFlag;   
+        if ( RETVAL > 0 ) 
+            RETVAL = 1;
+        else 
+            XSRETURN_UNDEF;
+    OUTPUT:
+        RETVAL
+
 SV *
 toStringHTML(self)
-        ProxyObject* self
+        SV * self
     PREINIT:
         xmlDocPtr real_dom;
         xmlChar *result=NULL;
         int len=0;
     CODE:
-        real_dom = (xmlDocPtr)self->object;
+        real_dom = (xmlDocPtr)PmmNODE(SvPROXYNODE(self));
         # warn( "use no formated toString!" );
         htmlDocDumpMemory(real_dom, &result, &len);
 
     	if (result == NULL) {
-	    # warn("Failed to convert doc to string");           
-            RETVAL = &PL_sv_undef;
-    	} else {
+            XSRETURN_UNDEF;
+      	} else {
             # warn("%s, %d\n",result, len);
             RETVAL = newSVpvn((char *)result, (STRLEN)len);
             xmlFree(result);
     OUTPUT:
         RETVAL
 
-int
-is_valid(self, ...)
-        xmlDocPtr self
+
+const char *
+URI( pdoc )
+        SV * pdoc
+    CODE:
+        RETVAL = xmlStrdup(((xmlDocPtr)PmmSvNode(pdoc))->URL );
+    OUTPUT:
+        RETVAL
+
+void
+setBaseURI( doc, new_URI )
+        SV * doc
+        char * new_URI
+    CODE:
+        if (new_URI) {
+            xmlFree((xmlChar*)((xmlDocPtr)PmmSvNode(doc))->URL );
+            ((xmlDocPtr)PmmSvNode(doc))->URL = xmlStrdup((const xmlChar*)new_URI);
+        }
+
+
+
+SV*
+createDocument( CLASS, version="1.0", encoding=NULL )
+        char * CLASS
+        char * version 
+        char * encoding
+    ALIAS:
+        XML::LibXML::Document::new = 1
     PREINIT:
-        xmlValidCtxt cvp;
-        ProxyObject * dtd_proxy;
+        xmlDocPtr doc=NULL;
+    CODE:
+        doc = xmlNewDoc(version);
+        if (encoding && *encoding!=0) {
+            doc->encoding = xmlStrdup(encoding);
+        }
+        RETVAL = PmmNodeToSv((xmlNodePtr)doc,NULL);
+    OUTPUT:
+        RETVAL
+
+SV* 
+createInternalSubset( doc, Pname, extID, sysID )
+        SV * doc
+        SV * Pname
+        SV * extID
+        SV * sysID
+    PREINIT:
+        xmlDocPtr document = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlChar * name = NULL;
+        xmlChar * externalID = NULL;
+        xmlChar * systemID = NULL; 
+    CODE:
+        document = (xmlDocPtr)PmmSvNode( doc );
+        if ( document == NULL ) {
+            XSRETURN_UNDEF;   
+        }
+
+        name = Sv2C( Pname, NULL );
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }  
+
+        externalID = Sv2C(extID, NULL);
+        systemID   = Sv2C(sysID, NULL);
+
+        dtd = xmlCreateIntSubset( document, name, externalID, systemID );
+        xmlFree(externalID);
+        xmlFree(systemID);
+        xmlFree(name);
+        if ( dtd ) {
+            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(doc) );
+        }
+        else {
+            XSRETURN_UNDEF;
+        }
+    OUTPUT:
+        RETVAL
+
+SV* 
+createExternalSubset( doc, Pname, extID, sysID )
+        SV * doc
+        SV * Pname
+        SV * extID
+        SV * sysID
+    PREINIT:
+        xmlDocPtr document = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlChar * name = NULL;
+        xmlChar * externalID = NULL;
+        xmlChar * systemID = NULL; 
+    CODE:
+        document = (xmlDocPtr)PmmSvNode( doc );
+        if ( document == NULL ) {
+            XSRETURN_UNDEF;   
+        }
+
+        name = Sv2C( Pname, NULL );
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }  
+
+        externalID = Sv2C(extID, NULL);
+        systemID   = Sv2C(sysID, NULL);
+
+        dtd = xmlNewDtd( document, name, externalID, systemID );
+
+        xmlFree(externalID);
+        xmlFree(systemID);
+        xmlFree(name);
+        if ( dtd ) {
+            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(doc) );
+        }
+        else {
+            XSRETURN_UNDEF;
+        }
+    OUTPUT:
+        RETVAL
+
+SV* 
+createDTD( doc, Pname, extID, sysID )
+        SV * doc
+        SV * Pname
+        SV * extID
+        SV * sysID
+    PREINIT:
+        xmlDocPtr document = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlChar * name = NULL;
+        xmlChar * externalID = NULL;
+        xmlChar * systemID = NULL; 
+    CODE:
+        document = (xmlDocPtr)PmmSvNode( doc );
+        if ( document == NULL ) {
+            XSRETURN_UNDEF;   
+        }
+
+        name = Sv2C( Pname, NULL );
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }  
+
+        externalID = Sv2C(extID, NULL);
+        systemID   = Sv2C(sysID, NULL);
+
+        dtd = xmlNewDtd( NULL, name, externalID, systemID );
+        dtd->doc = document;
+
+        xmlFree(externalID);
+        xmlFree(systemID);
+        xmlFree(name);
+        if ( dtd ) {
+            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(doc) );
+        }
+        else {
+            XSRETURN_UNDEF;
+        }
+    OUTPUT:
+        RETVAL
+