Commits

Anonymous committed bd1353f

Modified Files:
Tag: mm_fix
branch with the fixed memory management
This is an almost complete reimplementation of the module.
the current implementation is closer to libxml2 than before.
only the parts, where libxml2 may cause memory problems, the
package uses a special implementation.

LibXML.xs LibXML.pm
- follows the new memory layer
the interface is basicly restructured towards DOM Level3
conformity
- implements namespaces correctly.
- node import is fixed.
- most memory problems are removed.
- node destruction is simplified
- ownerDocument works now correctly

perl-libxml-mm.h perl-libxml-mm.c
cleaned interface
all proxy handling is done by this layer. also the internal
ref counts and memory handling is done here.

dom.c dom.h
cleaned interface.
more functions are left to be done by libxml2 itself

  • Participants
  • Parent commits 0b5228b
  • Branches mm_fix

Comments (0)

Files changed (6)

                                )],
                );
 
-
 sub new {
     my $class = shift;
     my %options = @_;
     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);
+}
+
+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);
+}
+
+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
 #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 {
-            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);
             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);
             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
+        SV * self
         int format
     PREINIT:
         xmlDocPtr real_dom;
         xmlChar *result=NULL;
         int len=0;
     CODE:
-        real_dom = (xmlDocPtr)self->object;
+        real_dom = (xmlDocPtr)PmmNODE(SvPROXYNODE(self));
         if ( format <= 0 ) {
             # warn( "use no formated toString!" );
             xmlDocDumpMemory(real_dom, &result, &len);
 
     	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;
+    CODE:
+        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, 
+                                     (xmlDocPtr)PmmSvNode(self),
+                                     encoding,
+                                     format);
+
+        xmlOutputBufferClose( buffer );
+    OUTPUT:
+        RETVAL    
+
+int 
+toFile( self, filename )
+        SV * self
+        char * filename
+    CODE:
+        RETVAL = xmlSaveFile( filename, (xmlDocPtr)PmmSvNode(self) );   
+        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
-    PREINIT:
-        xmlValidCtxt cvp;
-        ProxyObject * dtd_proxy;
-        xmlDtdPtr dtd;
-        SV * dtd_sv;
+
+const char *
+URI( pdoc )
+        SV * pdoc
     CODE:
-        LibXML_error = sv_2mortal(newSVpv("", 0));
-        cvp.userData = (void*)PerlIO_stderr();
-        cvp.error = (xmlValidityErrorFunc)LibXML_validity_error;
-        cvp.warning = (xmlValidityWarningFunc)LibXML_validity_warning;
-        if (items > 1) {
-            dtd_sv = ST(1);
-            if ( sv_isobject(dtd_sv) && (SvTYPE(SvRV(dtd_sv)) == SVt_PVMG) ) {
-                dtd_proxy = (ProxyObject*)SvIV((SV*)SvRV( dtd_sv ));
-                if (dtd_proxy != NULL) {
-                    dtd = (xmlDtdPtr)dtd_proxy->object;
-                }
-            }
-            else {
-                croak("is_valid: argument must be a DTD object");
-            }
-            RETVAL = xmlValidateDtd(&cvp, self, dtd);
-        }
-        else {
-            RETVAL = xmlValidateDocument(&cvp, self);
-        }
+        RETVAL = xmlStrdup(((xmlDocPtr)PmmSvNode(pdoc))->URL );
     OUTPUT:
         RETVAL
 
-int
-validate(self, ...)
-        xmlDocPtr self
-    PREINIT:
-        xmlValidCtxt cvp;
-        ProxyObject * dtd_proxy;
-        xmlDtdPtr dtd;
-        SV * dtd_sv;
-        STRLEN n_a;
-    CODE:
-        LibXML_error = sv_2mortal(newSVpv("", 0));
-        cvp.userData = (void*)PerlIO_stderr();
-        cvp.error = (xmlValidityErrorFunc)LibXML_validity_error;
-        cvp.warning = (xmlValidityWarningFunc)LibXML_validity_warning;
-        if (items > 1) {
-            dtd_sv = ST(1);
-            if ( sv_isobject(dtd_sv) && (SvTYPE(SvRV(dtd_sv)) == SVt_PVMG) ) {
-                dtd_proxy = (ProxyObject*)SvIV((SV*)SvRV( dtd_sv ));
-                if (dtd_proxy != NULL) {
-                    dtd = (xmlDtdPtr)dtd_proxy->object;
-                }
-            }
-            else {
-                croak("is_valid: argument must be a DTD object");
-            }
-            RETVAL = xmlValidateDtd(&cvp, self , dtd);
-        }
-        else {
-            RETVAL = xmlValidateDocument(&cvp, self);
-        }
-        if (RETVAL == 0) {
-            croak(SvPV(LibXML_error, n_a));
-        }
-    OUTPUT:
-        RETVAL
-        
-
 void
-process_xinclude(self)
-        SV* self
-    PREINIT:
-        ProxyObject* real_self = (ProxyObject*)SvIV((SV*)SvRV(self));
-    CODE:
-        LibXML_init_parser( NULL );
-        xmlXIncludeProcess((xmlDocPtr)real_self->object);
-        LibXML_cleanup_callbacks();
-        LibXML_cleanup_parser();
-
-const char *
-URI (doc, new_URI=NULL)
-        xmlDocPtr doc
+setBaseURI( doc, new_URI )
+        SV * doc
         char * new_URI
     CODE:
-        RETVAL = xmlStrdup(doc->URL );
         if (new_URI) {
-            xmlFree( (xmlChar*) doc->URL);
-            doc->URL = xmlStrdup((xmlChar*)new_URI);
+            xmlFree((xmlChar*)((xmlDocPtr)PmmSvNode(doc))->URL );
+            ((xmlDocPtr)PmmSvNode(doc))->URL = xmlStrdup((const xmlChar*)new_URI);
         }
-    OUTPUT:
-        RETVAL
+
 
 SV*
-createDocument( CLASS, version="1.0", encoding=0 )
+createDocument( CLASS, version="1.0", encoding=NULL )
         char * CLASS
         char * version 
         char * encoding
     ALIAS:
         XML::LibXML::Document::new = 1
     PREINIT:
-        xmlDocPtr real_dom=NULL;
-        ProxyObject * ret= NULL;
+        xmlDocPtr doc=NULL;
     CODE:
-        real_dom = domCreateDocument( version, encoding ); 
-        RETVAL = nodeToSv((xmlNodePtr)real_dom);
-        real_dom->_private = RETVAL;
-        setSvNodeExtra(RETVAL,RETVAL);
+        doc = xmlNewDoc(version);
+        if (encoding && *encoding!=0) {
+            doc->encoding = xmlStrdup(encoding);
+        }
+        RETVAL = PmmNodeToSv((xmlNodePtr)doc,NULL);
     OUTPUT:
         RETVAL
 
+
 SV*
-createDocumentFragment( dom )
-        SV * dom
+createDocumentFragment( doc )
+        SV * doc
     PREINIT:
-        SV * frag_sv = NULL;
-        xmlDocPtr real_dom;
+        xmlDocPtr real_doc;
         xmlNodePtr fragment= NULL;
     CODE:
-        real_dom = (xmlDocPtr)getSvNode(dom);
-        RETVAL = nodeToSv(xmlNewDocFragment( real_dom ));
-        setSvNodeExtra(RETVAL, RETVAL);
+        real_doc = (xmlDocPtr)PmmSvNode(doc);
+        RETVAL = PmmNodeToSv(xmlNewDocFragment(real_doc),SvPROXYNODE(doc));
     OUTPUT:
         RETVAL
 
         SV * dom
         SV* name
     PREINIT:
-        xmlNodePtr docfrag,newNode;
-        xmlDocPtr real_dom;
+        xmlNodePtr newNode;
+        xmlDocPtr real_doc;
         xmlChar * elname = NULL;
-        SV * docfrag_sv = NULL;
+        ProxyNodePtr docfrag = NULL;
     CODE:
-        real_dom = (xmlDocPtr)getSvNode(dom);
-        docfrag = xmlNewDocFragment( real_dom );
-        docfrag_sv = nodeToSv(docfrag);
-        setSvNodeExtra(docfrag_sv, docfrag_sv);
-
-        elname = nodeSv2C( name , (xmlNodePtr) real_dom );
+        STRLEN len;
+        real_doc = (xmlDocPtr)PmmSvNode(dom);
+        docfrag = PmmNewFragment( real_doc );
+       
+        elname = nodeSv2C( name , (xmlNodePtr) real_doc );
         if ( elname != NULL || xmlStrlen(elname) > 0 ) {
             newNode = xmlNewNode(NULL , elname);
             xmlFree(elname);
-
             if ( newNode != NULL ) {        
-                newNode->doc = real_dom;
-                domAppendChild( docfrag, newNode );
+                newNode->doc = real_doc;
+                domAppendChild( PmmNODE(docfrag), newNode );
                 xs_warn( newNode->name );
-                RETVAL = nodeToSv(newNode);
-                setSvNodeExtra(RETVAL,docfrag_sv);
+                RETVAL = PmmNodeToSv(newNode,docfrag);
             }
             else {
                 xs_warn( "no node created!" );
         RETVAL
 
 SV*
-createElementNS( dom, nsURI, qname)
-         SV * dom
-         char *nsURI
-         SV* qname 
-     PREINIT:
-         xmlNodePtr newNode;
-         xmlChar *prefix;
-         xmlChar* quali_name;
-         xmlChar *lname = NULL;
-         xmlNsPtr ns = NULL;
-         xmlDocPtr real_dom;
-         xmlNodePtr docfrag = NULL;
-         xmlChar * encstring = NULL;
-         SV * docfrag_sv = NULL;
-     CODE:
-        real_dom = (xmlDocPtr)getSvNode(dom);
-
-        quali_name = nodeSv2C( qname , (xmlNodePtr) real_dom );
-
-        docfrag = xmlNewDocFragment( real_dom );
-        docfrag_sv = nodeToSv(docfrag);
-        setSvNodeExtra(docfrag_sv, docfrag_sv);
-
-        if ( nsURI != NULL && strlen(nsURI)!=0 ){
-            lname = xmlSplitQName2(quali_name, &prefix);
-            ns = domNewNs (0 , prefix, nsURI );
+createElementNS( pdoc, nsURI, name )
+        SV * pdoc
+        SV * nsURI
+        SV * name
+    PREINIT:
+        xmlChar * ename;
+        xmlChar * prefix;
+        xmlChar * localname;
+        xmlChar * eURI;
+        xmlNsPtr ns = NULL;
+        xmlDocPtr doc;
+        ProxyNodePtr docfrag = NULL;
+        xmlNodePtr newNode = NULL;
+    CODE:
+        doc = (xmlDocPtr)PmmSvNode( pdoc );
+        ename = nodeSv2C( name , (xmlNodePtr) doc );
+        eURI  = Sv2C( nsURI , NULL );
+
+        if ( eURI != NULL && xmlStrlen(eURI)!=0 ){
+            localname = xmlSplitQName2(ename, &prefix);
+
+            newNode = xmlNewNode( NULL , localname );
+            newNode->doc = doc;
+            
+            ns = xmlSearchNsByHref( doc, xmlDocGetRootElement(doc), eURI );
+            if ( ns == NULL ) {
+                /* create a new NS if the NS does not already exists */
+                ns = xmlNewNs(newNode, eURI , prefix );
+            }
+
+            if ( ns == NULL ) {
+                xmlFreeNode( newNode );
+                xmlFree(eURI);
+                xmlFree(localname);
+                xmlFree(prefix);
+                xmlFree(ename);
+                XSRETURN_UNDEF;
+            }
+
+            xmlSetNs(newNode, ns );
         }
         else {
-            lname = quali_name;
+            /* ordinary element */
+            localname = ename;
+        
+            newNode = xmlNewNode( NULL , localname );
+            newNode->doc = doc;
         }
 
-        newNode = xmlNewNode( ns , lname );
-
-        newNode->doc = real_dom;
-        domAppendChild( docfrag, newNode );
-        RETVAL = nodeToSv(newNode);
-        setSvNodeExtra(RETVAL,docfrag_sv);
-        xmlFree(quali_name);
-     OUTPUT:
+        docfrag = PmmNewFragment( doc );
+        domAppendChild( PmmNODE(docfrag), newNode );
+        RETVAL = PmmNodeToSv(newNode, docfrag);
+    
+        xmlFree(localname);
+        xmlFree(prefix);
+        xmlFree(eURI);
+        xmlFree(ename);
+    OUTPUT:
         RETVAL
 
 SV *
-createTextNode( dom, content )
-        SV * dom
+createTextNode( doc, content )
+        SV * doc
         SV * content
     PREINIT:
         xmlNodePtr newNode;
-        xmlDocPtr real_dom;
-        xmlNodePtr docfrag = NULL;
-        xmlChar * encstring = NULL;
-        SV * docfrag_sv = NULL;
+        xmlDocPtr real_doc;
+        xmlChar * elname = NULL;
+        ProxyNodePtr docfrag = NULL;
     CODE:
-        real_dom = (xmlDocPtr)getSvNode(dom);