Commits

ph...@9ae0c189-cd1f-4510-a509-f4891f5cf20d  committed 4924887

Modified Files:
perl-libxml-sax.c
+ the code should be faster now

LibXML.xs LibXML.pm
[fix] some parser problems introduced by LibXML_init_error() stuff
[fix] error reporting
(reported by Petr Pajas)

xpath.c
+ it's possible to query document fragments
( reported by Al Calbazana)

  • Participants
  • Parent commits 43acd4e

Comments (0)

Files changed (4)

 use Carp;
 
 use XML::LibXML::Common qw(:encoding :libxml :w3c);
+
 use XML::LibXML::NodeList;
 use IO::Handle; # for FH reads called as methods
 
     my $self = shift;
 
     if ( defined $self->{CONTEXT} ) {
-        delete $self->{COMTEXT};
+        delete $self->{CONTEXT};
     }
 
     if ( defined $self->{SAX} ) {
     }
 }
 
-
 sub push {
     my $self = shift;
 
     if ( not defined $self->{CONTEXT} ) {
-        if ( defined $self->{SAX} ) {
-            $self->{CONTEXT} = $self->_start_push(1);
-        }
-        else {
-            $self->{CONTEXT} = $self->_start_push(0);
-        }
+        $self->init_push();
     }
 
     foreach ( @_ ) {
                             sv_setpvn(LibXML_error, "", 0);
 
 #define LibXML_croak_error() if ( SvCUR( LibXML_error ) > 0 ) { \
-                                 croak(SvPV(LibXML_error, len)); \
+                                 croak("%s",SvPV(LibXML_error, len)); \
                              } 
 
 /* this should keep the default */
         }
     CODE:
         ctxt = xmlCreateMemoryParserCtxt(ptr, len);
-
+        LibXML_init_parser(self);
         if (ctxt == NULL) {
             croak("Couldn't create memory parser context: %s", strerror(errno));
         }
+
         PmmSAXInitContext( ctxt, self );
 
         ctxt->sax = PSaxGetHandler();
 
-        LibXML_init_parser(self);
+        /* LibXML_init_parser(self); */
         RETVAL = xmlParseDocument(ctxt);
 
         xmlFree( ctxt->sax );
         if ( real_dom == NULL ) {
             croak("No document to process!");
         }
+
         LibXML_init_parser(self);
+
         RETVAL = xmlXIncludeProcess(real_dom);        
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
-    
-        if ( len > 0 ){
-            LibXML_croak_error();
+
+        sv_2mortal( LibXML_error );
+
+        LibXML_croak_error();
+
+        if ( RETVAL > 0 ){
+            croak( "unknown error due XInclude" );
             XSRETURN_UNDEF;            
         }
         else {
         xmlParserCtxtPtr ctxt = NULL;
     CODE:
         /* create empty context */
+        LibXML_init_parser(self);
         if ( with_sax == 1 ) {
             ctxt = xmlCreatePushParserCtxt( PSaxGetHandler(),
                                             NULL,
             XSRETURN_UNDEF;
         }
 
-        LibXML_init_parser(self);
+        LibXML_init_error();
+        
         xmlParseChunk(ctxt, chunk, len, 0);
 
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();    
 
-        sv_2mortal(LibXML_error);
+        sv_2mortal(LibXML_error); 
 
         RETVAL = 1;
     OUTPUT:
     CODE:
         PmmNODE( SvPROXYNODE( pctxt ) ) = NULL;
 
-        LibXML_init_parser(self);
+        LibXML_init_error();
+        /* LibXML_init_parser(self); */
+
         xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();    
 
         sv_2mortal(LibXML_error);
 
+
         if ( ctxt->node != NULL && restore == 0 ) {
-            xmlFreeParserCtxt(ctxt);
+            xmlFreeParserCtxt(ctxt);            
             LibXML_croak_error();
         }
 
     CODE:
         PmmNODE( SvPROXYNODE( pctxt ) ) = NULL;
 
-        LibXML_init_parser(self);
+        LibXML_init_error();
+        /* LibXML_init_parser(self); */
         xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();    

File perl-libxml-sax.c

 #include "XSUB.h"
 #include "ppport.h"
 
-
 #include <stdlib.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
 #include <libxml/entities.h>
 #include <libxml/xmlerror.h>
 
-#include "perl-libxml-mm.h"
-
 #ifdef __cplusplus
 }
 #endif
     xmlNodePtr ns_stack;
     xmlSAXLocator * locator;
     xmlDocPtr ns_stack_root;
+    SV ** handler;
 } PmmSAXVector;
 
 typedef PmmSAXVector* PmmSAXVectorPtr;
 static U32 VersionHash;
 static U32 EncodingHash;
 
-void
-PmmSAXInitialize() {
-    PERL_HASH(PrefixHash, "Prefix", 6);
-    PERL_HASH(NsURIHash, "NamespaceURI", 12);
-    PERL_HASH(NameHash, "Name", 4);
-    PERL_HASH(LocalNameHash, "LocalName", 9);
-    PERL_HASH(AttributesHash, "Attributes", 10);
-    PERL_HASH(ValueHash, "Value", 5);
-    PERL_HASH(DataHash, "Data", 4);
-    PERL_HASH(TargetHash, "Target", 6);
-    PERL_HASH(VersionHash, "Version", 7);
-    PERL_HASH(EncodingHash, "Encoding", 8);
+/* helper function C2Sv is ment to work faster than the perl-libxml-mm
+   version. this shortcut is usefull, because SAX handles only UTF8
+   strings, so there is no conversion logic required.
+*/
+SV*
+_C2Sv( const xmlChar *string, const xmlChar *dummy )
+{
+    SV *retval = &PL_sv_undef;
+    STRLEN len;
+    if ( string != NULL ) {
+        len = xmlStrlen( string );
+        retval = newSVpvn( (const char *)string, len );
+#ifdef HAVE_UTF8
+        SvUTF8_on( retval );
+#endif
+    }
+    return retval;
 }
 
 void
-PmmSAXInitContext( xmlParserCtxtPtr ctxt, SV * parser ) {
+PmmSAXInitialize()
+{
+    PERL_HASH(PrefixHash,     "Prefix",        6);
+    PERL_HASH(NsURIHash,      "NamespaceURI", 12);
+    PERL_HASH(NameHash,       "Name",          4);
+    PERL_HASH(LocalNameHash,  "LocalName",     9);
+    PERL_HASH(AttributesHash, "Attributes",   10);
+    PERL_HASH(ValueHash,      "Value",         5);
+    PERL_HASH(DataHash,       "Data",          4);
+    PERL_HASH(TargetHash,     "Target",        6);
+    PERL_HASH(VersionHash,    "Version",       7);
+    PERL_HASH(EncodingHash,   "Encoding",      8);
+}
+
+void
+PmmSAXInitContext( xmlParserCtxtPtr ctxt, SV * parser )
+{
     xmlNodePtr ns_stack = NULL;
     PmmSAXVectorPtr vec = NULL;
+    SV ** th;
     dTHX;
 
     vec = (PmmSAXVector*) xmlMalloc( sizeof(PmmSAXVector) );
     vec->ns_stack_root = xmlNewDoc(NULL);
-    vec->ns_stack = xmlNewDocNode(vec->ns_stack_root,NULL , "stack", NULL );
+    vec->ns_stack      = xmlNewDocNode(vec->ns_stack_root,
+                                       NULL,
+                                       "stack",
+                                       NULL );
+
     xmlAddChild((xmlNodePtr)vec->ns_stack_root, vec->ns_stack);
+
     vec->locator = NULL;
+
     SvREFCNT_inc( parser );
-    vec->parser = parser;
+    vec->parser  = parser;
+    th = hv_fetch( (HV*)SvRV(parser), "HANDLER", 7, 0 );
+    if ( th != NULL && SvTRUE(*th) ) {
+        vec->handler = th  ;
+    }
+    else {
+        vec->handler = NULL  ;
+    }
+
     ctxt->_private = (void*)vec;
 }
 
 void 
-PmmSAXCloseContext( xmlParserCtxtPtr ctxt ) {
+PmmSAXCloseContext( xmlParserCtxtPtr ctxt )
+{
     PmmSAXVector * vec = (PmmSAXVectorPtr) ctxt->_private;
     dTHX;
 
-    vec = (PmmSAXVector*) ctxt->_private;
+    vec->handler = NULL;
     SvREFCNT_dec( vec->parser );
+
     xmlFreeDoc( vec->ns_stack_root );
     xmlFree( vec );
 }
 
 
 xmlNsPtr
-PmmGetNsMapping( xmlNodePtr ns_stack, const xmlChar * prefix ) {
-    xmlNsPtr ret = NULL;
+PmmGetNsMapping( xmlNodePtr ns_stack, const xmlChar * prefix )
+{
     if ( ns_stack != NULL ) {
-        if ( prefix != NULL) {
-            ret = xmlSearchNs( ns_stack->doc, ns_stack, prefix );
-        }
-        else {
-            ret = xmlSearchNs( ns_stack->doc, ns_stack, NULL );
-        }
-
+        return xmlSearchNs( ns_stack->doc, ns_stack, prefix );
     }
     
-    return ret;
+    return NULL;
 }
 
 
 void
-PSaxStartPrefix( PmmSAXVectorPtr sax, const xmlChar * prefix, const xmlChar * uri, SV ** handler )
+PSaxStartPrefix( PmmSAXVectorPtr sax, const xmlChar * prefix,
+                 const xmlChar * uri, SV ** handler )
 {
     HV * param = newHV();
 
     dSP;
 
     hv_store(param, "NamespaceURI", 12,
-             C2Sv(uri, NULL), NsURIHash);
+             _C2Sv(uri, NULL), NsURIHash);
 
     if ( prefix != NULL ) {
         hv_store(param, "Prefix", 6,
-                 C2Sv(prefix, NULL), PrefixHash);
+                 _C2Sv(prefix, NULL), PrefixHash);
     }
     else {
         hv_store(param, "Prefix", 6,
-                 C2Sv("", NULL), PrefixHash);
+                 _C2Sv("", NULL), PrefixHash);
     }
 
     
 }
 
 void
-PSaxEndPrefix( PmmSAXVectorPtr sax, const xmlChar * prefix, const xmlChar * uri, SV ** handler )
+PSaxEndPrefix( PmmSAXVectorPtr sax, const xmlChar * prefix,
+               const xmlChar * uri, SV ** handler )
 {
     HV * param = newHV();
 
     dSP;
 
     hv_store(param, "NamespaceURI", 12,
-             C2Sv(uri, NULL), NsURIHash);
+             _C2Sv(uri, NULL), NsURIHash);
 
     if ( prefix != NULL ) {
         hv_store(param, "Prefix", 6,
-                 C2Sv(prefix, NULL), PrefixHash);
+                 _C2Sv(prefix, NULL), PrefixHash);
     }
     else {
         hv_store(param, "Prefix", 6,
-                 C2Sv("", NULL), PrefixHash);
+                 _C2Sv("", NULL), PrefixHash);
     }
     
     ENTER;
 }
 
 void
-PmmNarrowNsStack( PmmSAXVectorPtr sax, SV **handler ) {
+PmmNarrowNsStack( PmmSAXVectorPtr sax, SV **handler )
+{
     xmlNodePtr parent = sax->ns_stack->parent;
     xmlNsPtr list = sax->ns_stack->nsDef;
     while ( list ) {
 }
 
 void
-PmmAddNamespace( PmmSAXVectorPtr sax, const xmlChar * name, const xmlChar * href, SV **handler) {
+PmmAddNamespace( PmmSAXVectorPtr sax, const xmlChar * name,
+                 const xmlChar * href, SV **handler)
+{
+    xmlNsPtr ns         = NULL;
+    xmlChar * nodename  = NULL;
+    xmlChar * prefix    = NULL;
+    xmlChar * localname = NULL;
 
-    if ( sax->ns_stack != NULL ) {
-        xmlNsPtr ns = NULL;
-        xmlChar * nodename = xmlStrdup(sax->ns_stack->name);
-        xmlChar * prefix = NULL;
-        xmlChar * localname = NULL;
 
-        localname = xmlSplitQName( NULL, nodename, &prefix );
-        xmlFree( nodename );
+    if ( sax->ns_stack == NULL ) {
+        return;
+    }
 
+    nodename = xmlStrdup(sax->ns_stack->name);
+    localname = xmlSplitQName( NULL, nodename, &prefix );
+    xmlFree( nodename );
 
-        if ( name != NULL ) {
-            ns = xmlNewNs( sax->ns_stack, href, name );         
-            PSaxStartPrefix( sax, name, href, handler );
+    if ( name != NULL ) {
+        ns = xmlNewNs( sax->ns_stack, href, name );         
+        PSaxStartPrefix( sax, name, href, handler );
+        
+        if ( sax->ns_stack->ns == NULL
+             && xmlStrEqual( prefix , name ) ) {
+            sax->ns_stack->ns = ns;
+            xmlFree( (xmlChar*) sax->ns_stack->name );
+            sax->ns_stack->name = (const xmlChar*) xmlStrdup( localname );
+        }
+    }
+    else {
+        ns = xmlNewNs( sax->ns_stack, href, NULL );
+        PSaxStartPrefix( sax, NULL, href, handler );
+        if ( prefix = NULL ) {
+            sax->ns_stack->ns = ns;
+        }
+    }
 
-            if ( xmlStrEqual( prefix , name ) ) {
-                sax->ns_stack->ns = ns;
-                xmlFree( (xmlChar*) sax->ns_stack->name );
-                sax->ns_stack->name = (const xmlChar*) xmlStrdup( localname );
-            }
-        }
-        else {
-            ns = xmlNewNs( sax->ns_stack, href, NULL );
-            PSaxStartPrefix( sax, NULL, href, handler );
-            if ( prefix = NULL ) {
-                sax->ns_stack->ns = ns;
-            }
-        }
-        if ( prefix ) {
-            xmlFree( prefix );
-            xmlFree( localname );
-        }
+    if ( prefix != NULL ) {
+        xmlFree( prefix );
+    }
+    if ( localname != NULL ) {
+        xmlFree( localname );
     }
 }
 
 HV *
-PmmGenElementSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * name ) {
+PmmGenElementSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * name )
+{
     HV * retval = newHV();
 
     xmlNsPtr ns = NULL;
     if ( name != NULL && xmlStrlen( name )  ) {
         xmlChar *localname = NULL, *prefix = NULL;
         hv_store(retval, "Name", 4,
-                 C2Sv(name, NULL), NameHash);
+                 _C2Sv(name, NULL), NameHash);
 
-        if ( sax->ns_stack->ns == NULL ) { 
+        if ( sax->ns_stack->ns != NULL ) { 
             localname = xmlSplitQName(NULL, name, &prefix);
  
             ns = PmmGetNsMapping( sax->ns_stack, prefix );
         
         if ( ns != NULL ) {
             hv_store(retval, "NamespaceURI", 12,
-                     C2Sv(ns->href, NULL), NsURIHash);
+                     _C2Sv(ns->href, NULL), NsURIHash);
             if ( ns->prefix ) {
                 hv_store(retval, "Prefix", 6,
-                         C2Sv(ns->prefix, NULL), PrefixHash);
+                         _C2Sv(ns->prefix, NULL), PrefixHash);
             }
             else {
                 hv_store(retval, "Prefix", 6,
-                         C2Sv("", NULL), PrefixHash);                
+                         _C2Sv("", NULL), PrefixHash);                
             }
 
             hv_store(retval, "LocalName", 9,
-                     C2Sv(sax->ns_stack->name, NULL), LocalNameHash);
+                     _C2Sv(sax->ns_stack->name, NULL), LocalNameHash);
         } 
         else {
             hv_store(retval, "NamespaceURI", 12,
-                     C2Sv("", NULL), NsURIHash);
+                     _C2Sv("", NULL), NsURIHash);
             hv_store(retval, "Prefix", 6,
-                     C2Sv("", NULL), PrefixHash);
+                     _C2Sv("", NULL), PrefixHash);
             hv_store(retval, "LocalName", 9,
-                     C2Sv(name, NULL), LocalNameHash);
+                     _C2Sv(name, NULL), LocalNameHash);
 
         }
     }            
 }
 
 xmlChar *
-PmmGenNsName( const xmlChar * name, xmlChar * nsURI ) {
+PmmGenNsName( const xmlChar * name, const xmlChar * nsURI )
+{
     int namelen = 0;
     int urilen = 0;
     xmlChar * retval = NULL;
 }
 
 HV *
-PmmGenAttributeHashSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar **attr, SV ** handler ) {
-    HV * retval = NULL;
-    HV * atV = NULL;
-    xmlChar * nsURI = NULL;
-    xmlNsPtr ns = NULL;
+PmmGenAttributeHashSV( pTHX_ PmmSAXVectorPtr sax,
+                       const xmlChar **attr, SV ** handler )
+{
+    HV * retval     = NULL;
+    HV * atV        = NULL;
+    xmlNsPtr ns     = NULL;
 
-    U32 atnameHash;
+    U32 atnameHash = 0;
     int len = 0;
-    const xmlChar **ta = attr;
-    const xmlChar * name = NULL;
+
+    const xmlChar * nsURI = NULL;
+    const xmlChar **ta    = attr;
+    const xmlChar * name  = NULL;
     const xmlChar * value = NULL;
-    xmlChar * keyname = NULL;
+
+    xmlChar * keyname     = NULL;
+    xmlChar * localname   = NULL;
+    xmlChar * prefix      = NULL;
 
     if ( ta != NULL ) {
         retval = newHV();
         while ( *ta != NULL ) {
-            xmlChar * localname = NULL;
-            xmlChar * prefix = NULL;
-
             atV = newHV();
-            name = *ta; ta++;
+            name = *ta;  ta++;
             value = *ta; ta++;
 
             if ( name != NULL && xmlStrlen( name ) ) {
                 localname = xmlSplitQName(NULL, name, &prefix);
 
                 hv_store(atV, "Name", 4,
-                         C2Sv(name, NULL), NameHash);
+                         _C2Sv(name, NULL), NameHash);
                 hv_store(atV, "Value", 5,
-                         C2Sv(value, NULL), ValueHash);
+                         _C2Sv(value, NULL), ValueHash);
 
                 if ( prefix != NULL ) {
                     if ( xmlStrEqual( "xmlns", prefix ) ) {
                                          localname,
                                          value,
                                          handler);
-                    }
-                    ns = PmmGetNsMapping( sax->ns_stack, prefix );
-                    
-                    hv_store(atV, "Prefix", 6,
-                             C2Sv(prefix, NULL), PrefixHash);
 
-                    if ( ns != NULL ) {
-                        nsURI = xmlStrdup( ns->href );
+                        nsURI = "http://www.w3.org/2000/xmlns/";
+
+                        hv_store(atV, "Prefix", 6,
+                                 _C2Sv(prefix, NULL), PrefixHash);
+                        hv_store(atV, "LocalName", 9,
+                                 _C2Sv(localname,NULL), LocalNameHash);
                         hv_store(atV, "NamespaceURI", 12,
-                                 C2Sv(ns->href, NULL), NsURIHash);
+                                 _C2Sv("http://www.w3.org/2000/xmlns/",NULL),
+                                 NsURIHash);
                     }
                     else {
-                        hv_store(atV, "NamespaceURI", 12,
-                                 C2Sv("",NULL), NsURIHash);
+                        ns = PmmGetNsMapping( sax->ns_stack, prefix );
+
+                        if ( ns != NULL ) {
+                            nsURI = ns->href;
+
+                            hv_store(atV, "NamespaceURI", 12,
+                                     _C2Sv(ns->href, NULL), NsURIHash);
+                            hv_store(atV, "Prefix", 6,
+                                     _C2Sv(prefix, NULL), PrefixHash);
+                            hv_store(atV, "LocalName", 9,
+                                     _C2Sv(localname, NULL), LocalNameHash);
+                        }
+                        else {
+                            hv_store(atV, "NamespaceURI", 12,
+                                     _C2Sv("",NULL), NsURIHash);
+                            hv_store(atV, "Prefix", 6,
+                                     _C2Sv("", NULL), PrefixHash);
+                            hv_store(atV, "LocalName", 9,
+                                     _C2Sv(name, NULL), LocalNameHash);
+                        }
                     }
-
-                    hv_store(atV, "LocalName", 9,
-                             C2Sv(localname, NULL), LocalNameHash);
                     xmlFree( prefix );
                 }
                 else if ( xmlStrEqual( "xmlns", name ) ) {
                     /* a default namespace */
                     PmmAddNamespace( sax, NULL, value, handler);  
-                    
+                    nsURI = "http://www.w3.org/2000/xmlns/";
+
                     hv_store(atV, "Prefix", 6,
-                             C2Sv(localname, NULL), PrefixHash);
+                             _C2Sv(localname, NULL), PrefixHash);
                     hv_store(atV, "LocalName", 9,
-                             C2Sv("",NULL), LocalNameHash);
+                             _C2Sv("",NULL), LocalNameHash);
                     hv_store(atV, "NamespaceURI", 12,
-                             C2Sv("http://www.w3.org/2000/xmlns/",NULL),
+                             _C2Sv("http://www.w3.org/2000/xmlns/",NULL),
                              NsURIHash);
                     
                 }
                 else {
                     hv_store(atV, "Prefix", 6,
-                             C2Sv("",NULL), PrefixHash);
+                             _C2Sv("",NULL), PrefixHash);
                     hv_store(atV, "LocalName", 9,
-                             C2Sv(localname, NULL), LocalNameHash);
+                             _C2Sv(localname, NULL), LocalNameHash);
                     hv_store(atV, "NamespaceURI", 12,
-                             C2Sv("",NULL), NsURIHash);
+                             _C2Sv("",NULL), NsURIHash);
                     
                 }
                 
                          len,
                          newRV_noinc((SV*)atV),
                          atnameHash );
-                if ( nsURI != NULL ) {
-                    xmlFree( nsURI );
-                    nsURI = NULL;
-                }
+
                 xmlFree( keyname );
                 xmlFree(localname);
             }            
 }
 
 HV * 
-PmmGenCharDataSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * data ) {
+PmmGenCharDataSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * data )
+{
     HV * retval = newHV();
 
     if ( data != NULL && xmlStrlen( data ) ) {
         hv_store(retval, "Data", 4,
-                 C2Sv(data, NULL), DataHash);
+                 _C2Sv(data, NULL), DataHash);
     }
 
     return retval;
 }
 
 HV * 
-PmmGenPISV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * target, const xmlChar * data ) {
+PmmGenPISV( pTHX_ PmmSAXVectorPtr sax,
+            const xmlChar * target,
+            const xmlChar * data )
+{
     HV * retval = newHV();
 
     if ( target != NULL && xmlStrlen( target ) ) {
         hv_store(retval, "Target", 6,
-                 C2Sv(target, NULL), TargetHash);
+                 _C2Sv(target, NULL), TargetHash);
 
         if ( data != NULL && xmlStrlen( data ) ) {
             hv_store(retval, "Data", 4,
-                     C2Sv(data, NULL), DataHash);
+                     _C2Sv(data, NULL), DataHash);
         }
         else {
             hv_store(retval, "Data", 4,
-                     C2Sv("", NULL), DataHash);
+                     _C2Sv("", NULL), DataHash);
         }
     }
 
 PSaxStartDocument(void * ctx)
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
-    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
-    int count = 0;
-    HV* real_obj = (HV *)SvRV(sax->parser);
-    HV* empty = newHV();
-    SV ** handler = hv_fetch( real_obj, "HANDLER", 7, 0 );
+    PmmSAXVectorPtr sax   = (PmmSAXVectorPtr)ctxt->_private;
+    int count             = 0;
+    HV* real_obj          = (HV *)SvRV(sax->parser);
+    HV* empty             = newHV();
+    SV ** handler         = sax->handler;
 
     if ( handler != NULL ) {
         dTHX;
 
         if ( ctxt->version != NULL ) {
             hv_store(empty, "Version", 7,
-                     C2Sv(ctxt->version, NULL), VersionHash);
+                     _C2Sv(ctxt->version, NULL), VersionHash);
         }
         else {
             hv_store(empty, "Version", 7,
-                     C2Sv("1.0", NULL), VersionHash);
+                     _C2Sv("1.0", NULL), VersionHash);
         }
         
         if ( ctxt->encoding != NULL ) {
             hv_store(empty, "Encoding", 8,
-                     C2Sv(ctxt->encoding, NULL), EncodingHash);
+                     _C2Sv(ctxt->encoding, NULL), EncodingHash);
         }
         XPUSHs(newRV_noinc((SV*)empty ));
 
 PSaxEndDocument(void * ctx)
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
-    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
-    int count = 0;
+    PmmSAXVectorPtr  sax  = (PmmSAXVectorPtr)ctxt->_private;
+    int count             = 0;
 
     dTHX;
     dSP;
 }
 
 int
-PSaxStartElement(void *ctx, const xmlChar * name, const xmlChar** attr) {
+PSaxStartElement(void *ctx, const xmlChar * name, const xmlChar** attr)
+{
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
-    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
-    int count = 0;
-    SV * attrhash = NULL;
-    HV* real_obj = (HV *)SvRV(sax->parser);
-    HV* empty = newHV();
-    HV * element = NULL;
-    SV ** handler = hv_fetch( real_obj, "HANDLER", 7, 0 );
+    PmmSAXVectorPtr  sax  = (PmmSAXVectorPtr)ctxt->_private;
+    int count             = 0;
+    SV * attrhash         = NULL;
+    HV * real_obj         = (HV *)SvRV(sax->parser);
+    HV * element          = NULL;
+    SV ** handler         = sax->handler;
     
     dTHX;
     dSP;
     SAVETMPS;
 
     PmmExtendNsStack(sax, name);
+
     attrhash = (SV*) PmmGenAttributeHashSV(aTHX_ sax, attr, handler );
-    
-    element = PmmGenElementSV(aTHX_ sax, name);
+    element  = PmmGenElementSV(aTHX_ sax, name);
 
     if ( attrhash != NULL ) {
-        hv_store( element, "Attributes",10, newRV_noinc(attrhash), AttributesHash );
+        hv_store( element,
+                  "Attributes",
+                  10,
+                  newRV_noinc(attrhash),
+                  AttributesHash );
     }
     else {
-        hv_store( element, "Attributes",10, newRV_noinc((SV*)empty), AttributesHash );
+        hv_store( element,
+                  "Attributes",
+                  10,
+                  newRV_noinc((SV*)newHV()),
+                  AttributesHash );
     }
     
     PUSHMARK(SP) ;
 int
 PSaxEndElement(void *ctx, const xmlChar * name) {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
-    int count = 0;
-    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
-    HV* real_obj = (HV *)SvRV(sax->parser);
-    HV* empty = newHV();
-    SV ** handler = hv_fetch( real_obj, "HANDLER", 7, 0 );
+    PmmSAXVectorPtr  sax  = (PmmSAXVectorPtr)ctxt->_private;
+    int count             = 0;
+    HV* real_obj          = (HV *)SvRV(sax->parser);
+    SV ** handler         = sax->handler;
 
     dTHX;
     dSP;
     int count = 0;
     HV* real_obj = (HV *)SvRV(sax->parser);
     HV* empty = newHV();
-    SV ** handler = hv_fetch( real_obj, "HANDLER", 7, 0 );
+    SV ** handler = sax->handler;
 
     if ( ch != NULL && handler != NULL ) {
         xmlChar * data = xmlStrndup( ch, len );
     int count = 0;
     HV* real_obj = (HV *)SvRV(sax->parser);
     HV* empty = newHV();
-    SV ** handler = hv_fetch( real_obj, "HANDLER", 7, 0 );
+    SV ** handler = sax->handler;
 
     if ( ch != NULL && handler != NULL ) {
         xmlChar * data = xmlStrdup( ch );
 
     HV* real_obj = (HV *)SvRV(sax->parser);
     HV* empty = newHV();
-    SV ** handler = hv_fetch( real_obj, "HANDLER", 7, 0 );
+    SV ** handler = sax->handler;
 
     if ( ch != NULL && handler != NULL ) {
         xmlChar * data = xmlStrndup( ch, len );
 PSaxProcessingInstruction( void * ctx, const xmlChar * target, const xmlChar * data )
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
-    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
-    int count = 0;
-    HV* real_obj = (HV *)SvRV(sax->parser);
-    HV* empty = newHV();
-    SV ** handler = hv_fetch( real_obj, "HANDLER", 7, 0 );
+    PmmSAXVectorPtr sax   = (PmmSAXVectorPtr)ctxt->_private;
+    int count             = 0;
+    HV* real_obj          = (HV *)SvRV(sax->parser);
+    HV* empty             = newHV();
+    SV ** handler         = sax->handler;
 
     if ( handler != NULL ) {
         dTHX;
 #include <libxml/xpathInternals.h>
 #include <libxml/uri.h>
 
+#include "EXTERN.h"
+
 #include "dom.h"
 
 void
     xmlXPathObjectPtr obj = NULL, obj2 = NULL;
     xmlChar *base = NULL, *URI = NULL;
 
-
     if ((nargs < 1) || (nargs > 2)) {
         ctxt->error = XPATH_INVALID_ARITY;
         return;
     if ( refNode != NULL && path != NULL ) {
         xmlXPathContextPtr ctxt;
         xmlXPathCompExprPtr comp;
-    
+
+        xmlDocPtr tdoc = NULL;
+        xmlNodePtr froot = refNode;
+
+        comp = xmlXPathCompile( path );
+        if ( comp == NULL ) {
+            return NULL;
+        }
+        
+        if ( refNode->doc == NULL ) {
+            /* if one XPaths a node from a fragment, libxml2 will
+               refuse the lookup. this is not very usefull for XML
+               scripters. thus we need to create a temporary document
+               to make libxml2 do it's job correctly.
+             */
+            tdoc = xmlNewDoc( NULL );
+
+            /* find refnode's root node */
+            while ( froot != NULL ) {
+                if ( froot->parent == NULL ) {
+                    break;
+                }
+                froot = froot->parent;
+            }
+            xmlAddChild((xmlNodePtr)tdoc, froot);
+
+            refNode->doc = tdoc;
+        }
+
         /* prepare the xpath context */
         ctxt = xmlXPathNewContext( refNode->doc );
         ctxt->node = refNode;
-    
         /* get the namespace information */
         if (refNode->type == XML_DOCUMENT_NODE) {
             ctxt->namespaces = xmlGetNsList( refNode->doc,
                              (const xmlChar *) "document",
                              perlDocumentFunction);
        
+        res = xmlXPathCompiledEval(comp, ctxt);
 
-        comp = xmlXPathCompile( path );
-        if (comp != NULL) {
-            res = xmlXPathCompiledEval(comp, ctxt);
-            xmlXPathFreeCompExpr(comp);
-        }
+        xmlXPathFreeCompExpr(comp);
 
         if (ctxt->namespaces != NULL) {
             xmlFree( ctxt->namespaces );
         }
 
         xmlXPathFreeContext(ctxt);
+
+        if ( tdoc != NULL ) {
+            /* after looking through a fragment, we need to drop the
+               fake document again */
+            froot->doc = NULL;
+            tdoc->children = NULL;
+            tdoc->last     = NULL;
+            froot->parent  = NULL;
+            refNode->doc = NULL;
+
+            xmlFreeDoc( tdoc );
+        }
     }
     return res;
 }