Commits

Anonymous committed 0af198a

Modified Files:
LibXML.xs LibXML.pm perl-libxml-sax.c perl-libxml-sax.h
+ made XML::LibXML work with XML::SAX.

Changes MANIFEST
+ version updates

Comments (0)

Files changed (6)

    - fixed attribute setting of the string parser
    - fixed external entity loading for entity expansion
    - fixed nodeValue() to handle entities and entity refs correctly
+   - SAX::Parser ignores now hidden XINCLUDE nodes.
+   - fixed SAX::Builder to recognize namespace declarations correctly
    - compatibility fixes
    - importNode() bug fix 
    - fixed library tests and output in Makefile.PL
 
 sub set_handler {
     my $self = shift;
-    $self->{HANDLER} = $_[0];
+    if ( defined $_[0] ) {
+        $self->{HANDLER} = $_[0];
 
-    $self->{SAX} = {NAMESPACES => {},
-                    ELSTACK    => []};
+        $self->{SAX} = {State => 0,
+                        ELSTACK    => []};
+    }
+    else {
+        # undef SAX handling
+        delete $self->{HANDLER};
+        delete $self->{SAX};
+    }
 }
 
 sub _auto_expand {
     if ( defined $self->{SAX} ) {
         my $string = shift;
         eval { $self->_parse_sax_string($string); };
-
         my $err = $@;
         $self->{_State_} = 0;
         if ($err) {
     return $result;
 }
 
-sub parse_chunk { my $self = shift; return $self->parse_xml_chunk(@_); }
-
 sub processXIncludes {
     my $self = shift;
     my $doc = shift;
 
 sub start_document {
     my $parser = shift;
+    $parser->{SAX}->{State} = 1;
     $parser->{HANDLER}->start_document({});
 }
 
+sub end_document {
+    my $parser = shift;
+    $parser->{SAX}->{State} = 0;
+}
+
 sub xml_decl {
     my ( $parser, $version, $encoding ) = @_;
 
     $parser->{HANDLER}->xml_decl($decl);
 }
 
-sub end_document {
-    my $parser = shift;
-    $parser->{HANDLER}->end_document({});
-}
+sub start_element {
+    my (  $parser, $elem, $attrs ) = @_;
+    my $saxattr = {};
 
-sub start_element {
-    my (  $parser, $name, %attrs ) = @_;
-    my $saxattr = {};
-    foreach my $att ( keys %attrs ) {
-        next unless $att =~ /^xmlns/;
-        $parser->{Namespaces}->{$att} = $attrs{$att};
+    push @{$parser->{SAX}->{ELSTACK}}, $elem;
+    if ( defined $attrs ) {
+        $parser->{HANDLER}->start_element( { %$elem, Attributes=>$attrs} )
     }
 
-    foreach my $att ( keys %attrs ) {
-        next if $att =~ /^xmlns/;
-        $saxattr->{$att} = {Name         => $att,
-                            Value        => $attrs{$att},
-                            NamespaceURI => "",
-                            Prefix       => "",
-                            LocalName    => $att};
-
-        if ( $att =~ /([^\:]+):(.+)/ ) {
-            if ( exists  $parser->{SAX}->{Namespaces}->{"xmlns:$1"} ) {
-                $saxattr->{$att}->{NamespaceURI} = $parser->{SAX}->{Namespaces}->{"xmlns:$1"};
-                $saxattr->{$att}->{LocalName} = $2;
-                $saxattr->{$att}->{Prefix} = $1;
-            }
-        }
-    }
-
-    my $elem = { Name => $name };
-    if ( $name =~ /([^\:]+)\:(.+)/ ) {
-        my $xmlns = "xmlns:$1";
-        if ( exists $parser->{SAX}->{Namespaces}->{$xmlns} ){
-            $elem->{LocalName} = $2;
-            $elem->{Prefix} = $1;
-            $elem->{NamespaceURI} = $parser->{SAX}->{Namespaces}->{$xmlns};
-        }
-        else {
-             $elem->{LocalName} = $name;
-             $elem->{Prefix} = "";
-             $elem->{NamespaceURI} = "";
-        }
-    }
-    else {
-        $elem->{LocalName} = $name;
-        $elem->{Prefix} = "";
-        $elem->{NamespaceURI} = "";
-    }
-    push @{$parser->{SAX}->{ELSTACK}}, $elem;
-    $parser->{HANDLER}->start_element( { %$elem, Attributes=>$saxattr} )
-
 }
 
 sub end_element {
     my (  $parser, $name ) = @_;
     my $elem = pop @{$parser->{SAX}->{ELSTACK}};
     if ( $elem->{Name} ne $name ) {
-        croak( "cought error where parser should work" );
+        croak( "cought error where parser should work ($elem->{Name} != $name" );
     }
     $parser->{HANDLER}->end_element( $elem );
 }
 
 =head1 SEE ALSO
 
-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>
-L<XML::LibXML::DocumentFragment>
+L<XML::LibXSLT>, L<XML::LibXML::DOM>, L<XML::LibXML::SAX>
 
 =cut
             croak("Could not create push parser context: %s", strerror(errno));
         }
         ctxt->directory = directory;
-        ctxt->_private = (void*)self;
+        PmmSAXInitContext( ctxt, self );
+
         while(read_length = LibXML_read_perl(ioref, buffer, 1024)) {
             xmlParseChunk(ctxt, buffer, read_length, 0);
         }
 
         xmlFree(ctxt->sax);
         ctxt->sax = NULL;
+        PmmSAXCloseContext(ctxt);
         xmlFreeParserCtxt(ctxt);
 
     }
 BOOT:
     LIBXML_TEST_VERSION
     xmlInitParser();
+    PmmSAXInitialize();
 
     /* make the callback mechnism available to perl coders */
     xmlRegisterInputCallbacks((xmlInputMatchCallback) LibXML_input_match,
         }
     CODE:
         ctxt = xmlCreateMemoryParserCtxt(ptr, len);
+
         if (ctxt == NULL) {
             croak("Couldn't create memory parser context: %s", strerror(errno));
         }
-
-        ctxt->_private = (void*)self;
+        PmmSAXInitContext( ctxt, self );
 
         ctxt->sax = PSaxGetHandler();
 
         RETVAL = xmlParseDocument(ctxt);
         xmlFree( ctxt->sax );
         ctxt->sax = NULL;
+        PmmSAXCloseContext(ctxt);
         xmlFreeParserCtxt(ctxt);
 
         LibXML_cleanup_callbacks();
         }
 
         ctxt->sax = PSaxGetHandler();
-        ctxt->_private = (void*)self;
+        PmmSAXInitContext( ctxt, self );
         
         LibXML_error = NEWSV(0, 512);
         sv_setpvn(LibXML_error, "", 0);
 
         xmlFree(ctxt->sax);
         ctxt->sax = NULL;
+        PmmSAXCloseContext(ctxt);
         xmlFreeParserCtxt(ctxt);
                 
         sv_2mortal(LibXML_error);
             if (ctxt == NULL) {
                 croak("Couldn't create memory parser context: %s", strerror(errno));
             }   
-            ctxt->_private = (void*)self;
+            PmmSAXInitContext( ctxt, self );         
             ctxt->sax = PSaxGetHandler();
 
             LibXML_error = sv_2mortal(newSVpv("", 0));
                                                    chunk,
                                                    &nodes );       
             xmlFree( handler );            
+            PmmSAXCloseContext(ctxt);
+            xmlFreeParserCtxt(ctxt);
+
             LibXML_cleanup_callbacks();
             LibXML_cleanup_parser();    
             xmlFree( chunk );
         else {
             ctxt = xmlCreatePushParserCtxt( NULL, NULL, NULL, 0, NULL );
         }
-
+        PmmSAXInitContext( ctxt, self );
         sv_2mortal(LibXML_error);
 
         RETVAL = PmmContextSv( ctxt );
         sv_setpvn(LibXML_error, "", 0);
 
         LibXML_init_parser(self);
-
-        ctxt->_private = (void*)self;
         xmlParseChunk(ctxt, chunk, len, 0);
 
         LibXML_cleanup_callbacks();
         sv_setpvn(LibXML_error, "", 0);
 
         LibXML_init_parser(self);
-        ctxt->_private = (void*)self;
         xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();    
         sv_setpvn(LibXML_error, "", 0);
 
         LibXML_init_parser(self);
-        ctxt->_private = (void*)self;
         xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();    
 
         xmlFree(ctxt->sax);
         ctxt->sax = NULL;
+        PmmSAXCloseContext(ctxt);
         xmlFreeParserCtxt(ctxt);
         XSRETURN_UNDEF;
 
             xmlFreeNs(ns);
         }
 
+int
+nodeType(self)
+        SV * self
+    ALIAS:
+        getType = 1
+    PREINIT:
+        xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self));
+    CODE:
+        RETVAL = ns->type;
+    OUTPUT:
+        RETVAL
+
 SV*
 href(self)
         SV * self
 lib/XML/LibXML/Attr.pod
 lib/XML/LibXML/Comment.pod
 lib/XML/LibXML/DOM.pod
+lib/XML/LibXML/SAX.pod
 lib/XML/LibXML/Dtd.pod
 lib/XML/LibXML/Node.pod
 lib/XML/LibXML/CDATASection.pod
 lib/XML/LibXML/Literal.pm
 lib/XML/LibXML/Boolean.pm
 lib/XML/LibXML/Number.pm
+lib/XML/LibXML/SAX.pm
 lib/XML/LibXML/SAX/Generator.pm
 lib/XML/LibXML/SAX/Builder.pm
 lib/XML/LibXML/SAX/Parser.pm

perl-libxml-sax.c

 #include <libxml/entities.h>
 #include <libxml/xmlerror.h>
 
+#include "perl-libxml-mm.h"
+
 #ifdef __cplusplus
 }
 #endif
 
+#define NSDELIM ':'
+#define NSDEFAULTURI "http://www.w3.org/XML/1998/namespace"
+
+typedef struct {
+    SV * parser;
+    xmlNodePtr ns_stack;
+} PmmSAXVector;
+
+typedef PmmSAXVector* PmmSAXVectorPtr;
+
+static U32 PrefixHash; /* pre-computed */
+static U32 NsURIHash;
+static U32 NameHash;
+static U32 LocalNameHash;
+static U32 AttributesHash;
+static U32 ValueHash;
+static U32 DataHash;
+static U32 TargetHash;
+
+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);
+}
+
+void
+PmmSAXInitContext( xmlParserCtxtPtr ctxt, SV * parser ) {
+    xmlNodePtr ns_stack = NULL;
+    PmmSAXVectorPtr vec = NULL;
+    vec = (PmmSAXVector*) xmlMalloc( sizeof(PmmSAXVector) );
+    vec->ns_stack = xmlNewNode( NULL, "stack" );
+    SvREFCNT_inc( parser );
+    vec->parser = parser;
+    ctxt->_private = (void*)vec;
+}
+
+void 
+PmmSAXCloseContext( xmlParserCtxtPtr ctxt ) {
+    PmmSAXVector * vec = (PmmSAXVectorPtr) ctxt->_private;
+    vec = (PmmSAXVector*) ctxt->_private;
+    SvREFCNT_dec( vec->parser );
+    xmlFreeNode( vec->ns_stack );
+    xmlFree( vec );
+}
+
+void 
+PmmExtendNsStack( PmmSAXVectorPtr sax ) {
+    xmlNodePtr newNS = xmlNewNode( NULL, "stack" );
+    xmlAddChild(sax->ns_stack, newNS);
+    sax->ns_stack = newNS;
+}
+
+void
+PmmNarrowNsStack( PmmSAXVectorPtr sax ) {
+    xmlNodePtr parent = sax->ns_stack->parent;
+    xmlUnlinkNode(sax->ns_stack);
+    sax->ns_stack = parent;
+}
+
+xmlNsPtr
+PmmGetNsMapping( xmlNodePtr ns_stack, const xmlChar * prefix ) {
+    xmlNsPtr ret = NULL;
+
+    if ( ns_stack != NULL ) {
+        if ( prefix != NULL) {
+            ret = xmlSearchNs( NULL, ns_stack, prefix );
+        }
+        else {
+            ret = xmlSearchNs( NULL, ns_stack, NULL );
+        }
+    }
+    
+    return ret;
+}
+
+const xmlChar *
+PmmDetectNamespace( const xmlChar * name ) {
+    const xmlChar *pos = xmlStrchr( name, (xmlChar)NSDELIM );
+    if ( pos != NULL ) {
+        return pos;
+    }
+    return NULL;    
+}
+
+const xmlChar *
+PmmDetectNamespaceDecl( const xmlChar * name ) {
+    const xmlChar *pos = xmlStrchr( name, (xmlChar)NSDELIM );
+    xmlChar *decl= NULL;
+    int len = 0;
+
+    if ( xmlStrcmp( "xmlns", name ) == 0 ) {
+        return name;
+    }
+
+    if ( pos == NULL ) {
+        return NULL;
+    }
+
+    len = pos - name;
+    decl = xmlStrndup( name, len );
+    
+    if ( xmlStrcmp( "xmlns", decl ) != 0 ) {
+        pos= NULL;
+    }
+
+    xmlFree( decl );
+
+    return pos;
+}
+
+void
+PmmAddNamespace( xmlNodePtr ns_stack, const xmlChar * name, const xmlChar * href) {
+    if ( ns_stack != NULL ) {
+        xmlNsPtr ns = NULL;
+        const xmlChar *pos = xmlStrchr( name, NSDELIM );
+        xmlChar *decl= NULL;
+        if ( pos != NULL ) {
+            pos++;
+            decl = xmlStrdup( pos );
+            if ( decl != NULL && xmlStrlen( decl ) ) {
+                ns = xmlNewNs( ns_stack, decl, href );
+            }
+            xmlFree( decl );
+        }
+        else {
+            ns = xmlNewNs( ns_stack, NULL, href );
+        }
+    }
+}
+
+HV *
+PmmGenElementSV( PmmSAXVectorPtr sax, const xmlChar * name ) {
+    HV * retval = newHV();
+    SV *empty_sv = sv_2mortal(C2Sv("", NULL));
+    xmlNsPtr ns = NULL;
+    if ( name != NULL && xmlStrlen( name )  ) {
+        const xmlChar * pos = PmmDetectNamespace( name );
+
+        hv_store(retval, "Name", 4,
+                 C2Sv(name, NULL), NameHash);
+
+        if ( pos != NULL ) {
+            xmlChar * localname = NULL;
+            xmlChar * prefix = NULL;
+            prefix = xmlStrndup( name, pos - name );
+            /* pos++; skip the colon */
+            localname = xmlStrdup(++pos);
+            ns = PmmGetNsMapping( sax->ns_stack, prefix );
+
+            hv_store(retval, "Prefix", 6,
+                     C2Sv(prefix, NULL), PrefixHash);
+
+            if ( ns != NULL ) {
+                hv_store(retval, "NamespaceURI", 12,
+                         C2Sv(ns->href, NULL), NsURIHash);
+            } 
+            else {
+                hv_store(retval, "NamespaceURI", 12,
+                         SvREFCNT_inc(empty_sv), NsURIHash);
+            }
+
+            hv_store(retval, "LocalName", 9,
+                     C2Sv(localname, NULL), LocalNameHash);
+
+            xmlFree(localname);
+            xmlFree(prefix);
+        }
+        else {
+            hv_store(retval, "Prefix", 6,
+                     SvREFCNT_inc(empty_sv), PrefixHash);
+            hv_store(retval, "NamespaceURI", 12,
+                     SvREFCNT_inc(empty_sv), NsURIHash);
+            hv_store(retval, "LocalName", 9,
+                     C2Sv(name, NULL), LocalNameHash);
+        }
+        
+        
+    }
+    return retval;
+}
+
+HV *
+PmmGenAttributeSV( PmmSAXVectorPtr sax,
+                   const xmlChar * name,
+                   const xmlChar * value ) {
+    HV * retval = newHV();
+    SV *empty_sv = sv_2mortal(C2Sv("", NULL));
+
+    if ( name != NULL && xmlStrlen( name )  ) {
+        const xmlChar * pos = PmmDetectNamespaceDecl( name );
+
+        hv_store(retval, "Name", 4,
+                 C2Sv(name, NULL), NameHash);
+        hv_store(retval, "Value", 5,
+                 C2Sv(value, NULL), ValueHash);
+
+        if ( pos != NULL ) {
+            xmlNsPtr ns = NULL;
+            xmlChar * localname = NULL;
+            xmlChar * prefix = NULL;
+            
+            prefix = xmlStrndup( name, pos - name );
+            /* pos++; skip the colon */
+            localname = xmlStrdup(++pos);
+
+            ns = PmmGetNsMapping( sax->ns_stack, prefix );
+
+            hv_store(retval, "Prefix", 6,
+                     C2Sv(prefix, NULL), PrefixHash);
+
+            if ( ns != NULL ) {
+                hv_store(retval, "NamespaceURI", 12,
+                         C2Sv(ns->href, NULL), NsURIHash);
+            }
+            else {
+                hv_store(retval, "NamespaceURI", 12,
+                         SvREFCNT_inc(empty_sv), NsURIHash);
+            }
+
+            hv_store(retval, "LocalName", 9,
+                     C2Sv(localname, NULL), LocalNameHash);
+
+            xmlFree(localname);
+            xmlFree(prefix);
+        }
+        else {
+            hv_store(retval, "Prefix", 6,
+                     SvREFCNT_inc(empty_sv), PrefixHash);
+            hv_store(retval, "NamespaceURI", 12,
+                     SvREFCNT_inc(empty_sv), NsURIHash);
+            hv_store(retval, "LocalName", 9,
+                     C2Sv(name, NULL), LocalNameHash);            
+        }
+    }
+
+    return retval;
+}
+
+HV *
+PmmGenAttributeHashSV( PmmSAXVectorPtr sax, const xmlChar **attr ) {
+    HV * retval = newHV();
+    SV * atV = NULL;
+    U32 atnameHash;
+    int len = 0;
+    const xmlChar **ta = attr;
+    const xmlChar * name = NULL;
+    const xmlChar * value = NULL;
+    if ( attr != NULL ) {
+        while ( *ta != NULL ) {
+            if ( PmmDetectNamespaceDecl( *ta ) ) {
+                name = *ta; ta++;
+                value = *ta; ta++;
+                PmmAddNamespace(sax->ns_stack, name, value);                
+            }
+            else {
+                ta++;ta++;
+            }
+        }
+        
+        ta = attr;
+        while ( *ta != NULL ) {
+            name = *ta; ta++;
+            value = *ta; ta++;
+            atV = (SV*) PmmGenAttributeSV( sax, name, value );
+            len = xmlStrlen( name );
+            PERL_HASH( atnameHash, name, len );
+            hv_store(retval, name, len, newRV_noinc(atV), atnameHash );
+        }
+    }
+    return retval;
+}
+
 int
 PSaxStartDocument(void * ctx)
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
     dSP;
     
     SAVETMPS;
 
     PUSHMARK(SP) ;
-    XPUSHs(sv_mortalcopy((SV*)ctxt->_private));
+    PUSHs(sax->parser);
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::start_document", 0 );
     SPAGAIN;
 
     PUSHMARK(SP) ;
-    XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
+    PUSHs(sax->parser);
 
-    if ( ctxt->version != NULL ) 
-        XPUSHs(sv_2mortal(newSVpv((char*)ctxt->version, 0)));
+    if ( ctxt->version != NULL ) {
+        PUSHs(C2Sv(ctxt->version, NULL));
+    }
 
-    if ( ctxt->encoding != NULL ) 
-        XPUSHs(sv_2mortal(newSVpv((char*)ctxt->encoding, 0)));    
+    if ( ctxt->encoding != NULL ) {
+        PUSHs(C2Sv(ctxt->encoding, NULL));
+    }
 
     PUTBACK;
     
 PSaxEndDocument(void * ctx)
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
 
     dSP;
     SAVETMPS;
 
     PUSHMARK(SP) ;
-    XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
+    PUSHs(sax->parser);
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::end_document", 0 );
 int
 PSaxStartElement(void *ctx, const xmlChar * name, const xmlChar** attr) {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
-
+    SV * attrhash = NULL;
+ 
     dSP;
     
     ENTER;
     SAVETMPS;
+
+    PmmExtendNsStack(sax);
+    attrhash = (SV*) PmmGenAttributeHashSV( sax, attr );
     
     PUSHMARK(SP) ;
-    XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
-
-    XPUSHs(sv_2mortal(newSVpv((char*)name, 0)));
-
-    if ( attr != NULL ) {
-        const xmlChar ** ta = attr;
-        while ( *ta ) {
-            XPUSHs(sv_2mortal(newSVpv((char*)*ta, 0)));
-            ta++;
-            XPUSHs(sv_2mortal(newSVpv((char*)*ta, 0)));
-            ta++;
-        }
-    }
-
+    PUSHs(sax->parser);
+    XPUSHs(newRV_noinc((SV*)PmmGenElementSV(sax,name)));
+    XPUSHs(newRV_noinc(attrhash));
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::start_element", 0 );
 PSaxEndElement(void *ctx, const xmlChar * name) {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
     int count = 0;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
 
     dSP;
     
     SAVETMPS;
 
     PUSHMARK(SP) ;
-
-    XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
-
-    XPUSHs(sv_2mortal(newSVpv((char*)name, 0)));
+    PUSHs(sax->parser);
+    PUSHs(C2Sv(name, NULL));
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::end_element", 0 );
     FREETMPS ;
     LEAVE ;
 
+    PmmNarrowNsStack(sax);
+
     return 1;
 }
 
 int
 PSaxCharacters(void *ctx, const xmlChar * ch, int len) {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
+
     if ( ch != NULL ) {
         xmlChar * data = xmlStrndup( ch, len );
 
         SAVETMPS;
 
         PUSHMARK(SP) ;
-        XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
-        XPUSHs(sv_2mortal(newSVpv((char*)data, 0)));
+        PUSHs(sax->parser);
+        PUSHs(C2Sv(data, NULL));
         PUTBACK;
 
         count = perl_call_pv( "XML::LibXML::_SAXParser::characters", 0 );
 int
 PSaxComment(void *ctx, const xmlChar * ch) {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
     if ( ch != NULL ) {
         xmlChar * data = xmlStrdup( ch );
         SAVETMPS;
 
         PUSHMARK(SP) ;
-        XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
-        XPUSHs(sv_2mortal(newSVpv((char*)data, 0)));
+        PUSHs(sax->parser);
+        PUSHs(C2Sv(data, NULL));
         PUTBACK;
 
         count = perl_call_pv( "XML::LibXML::_SAXParser::comment", 0 );
 int
 PSaxCDATABlock(void *ctx, const xmlChar * ch, int len) {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
     if ( ch != NULL ) {
         xmlChar * data = xmlStrndup( ch, len );
         SAVETMPS;
 
         PUSHMARK(SP) ;
-        XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
-        XPUSHs(sv_2mortal(newSVpv((char*)data, 0)));
+        PUSHs(sax->parser);
+        PUSHs(C2Sv(data, NULL));
         PUTBACK;
 
         count = perl_call_pv( "XML::LibXML::_SAXParser::cdata_block", 0 );
 PSaxProcessingInstruction( void * ctx, const xmlChar * target, const xmlChar * data )
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
 
     dSP;
     SAVETMPS;
 
     PUSHMARK(SP) ;
-    XPUSHs(sv_mortalcopy((SV*)((xmlParserCtxtPtr)ctxt->userData)->_private));
-    XPUSHs(sv_2mortal(newSVpv((char*)target, 0)));
-    XPUSHs(sv_2mortal(newSVpv((char*)data, 0)));
+    PUSHs(sax->parser);
+    PUSHs(C2Sv(target, NULL));
+    PUSHs(C2Sv(data, NULL));
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::processing_instruction", 0 );
     return 1;
 }
 
+/* NOTE:
+ * end document is not handled by the parser itself! use 
+ * XML::LibXML::SAX instead!
+ */
 xmlSAXHandlerPtr
 PSaxGetHandler()
 {

perl-libxml-sax.h

 }
 #endif
 
+/* has to be called in BOOT sequence */
+void
+PmmSAXInitialize();
+
+void
+PmmSAXInitContext( xmlParserCtxtPtr ctxt, SV * parser );
+
+void 
+PmmSAXCloseContext( xmlParserCtxtPtr ctxt );
+
 xmlSAXHandlerPtr
 PSaxGetHandler();
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.