Commits

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

Modified Files:
LibXML.pm LibXML.xs dom.c
+ appendChild works now with document fragments without segfaulting
+ parse_xml_chunk parses a well balanced string and returns a
document fragment. This function can be used to test the well balanceness
of a string.

Changes
so we know that :)

  • Participants
  • Parent commits fc1d343

Comments (0)

Files changed (4)

 Revision history for Perl extension XML::LibXML
 
 1.32
+   - new parsefunction: $parser->parse_xml_chunk($string);
+   - appendChild( $doc_fragment ) bug fixed
    - removed obsolete files (parser.?)
    - fixed getElementsByTagName and getElementsByTagNameNS to fit the spec
    - new functions in XML::LibXML::Element:
     return $result;
 }
 
+sub parse_xml_chunk {
+    my $self = shift;
+    # max 2 parameter:
+    # 1: the chunk
+    # 2: the encoding of the string
+    croak("parse already in progress") if $self->{_State_};
+    $self->{_State_} = 1;
+    my $result;
+    eval {
+        $self->init_parser();
+        $result = $self->_parse_xml_chunk( @_ );
+        if ( $result ) {
+            $result->_fix_extra;
+        }
+
+        # we should include this to document fragments as well ...
+        # if ( $self->{XML_LIBXML_EXPAND_XINCLUDE} ) {
+        #     $result->process_xinclude();
+        # }
+    };
+    my $err = $@;
+    $self->{_State_} = 0;
+    if ($err) {
+        croak $err;
+    }
+    return $result;
+}
+
 sub parse_fh {
     my $self = shift;
     croak("parse already in progress") if $self->{_State_};
         RETVAL
 
 SV*
+_parse_xml_chunk( self, chunk, encoding="UTF-8" )
+        SV * self
+        char * chunk
+        char * encoding
+    PREINIT:
+        char * CLASS = "XML::LibXML::DocumentFragment";
+        xmlNodePtr rv = NULL;
+        xmlNodePtr fragment= NULL;
+        ProxyObject *ret=NULL;
+        xmlNodePtr rv_end = NULL;
+    CODE:
+        if ( encoding == NULL ) encoding = "UTF-8";
+
+        chunk = domEncodeString( encoding, chunk );
+
+        if ( chunk != NULL ) {
+            LibXML_error = sv_2mortal(newSVpv("", 0));
+            rv = domReadWellBalancedString( NULL, chunk );
+            LibXML_cleanup_callbacks();
+            LibXML_cleanup_parser();    
+
+            if ( rv != NULL ) {
+                /* now we append the nodelist to a document
+                   fragment which is unbound to a Document!!!! */
+                # warn( "good chunk, create fragment" );
+
+                /* step 1: create the fragment */
+                fragment = xmlNewDocFragment( NULL );
+                # if ( !fragment ) warn( "no fragment!\n" );
+                ret = make_proxy_node( fragment );
+                RETVAL = NEWSV(0,0);
+                sv_setref_pv( RETVAL, (char *)CLASS, (void*)ret );
+                ret->extra = RETVAL;
+                # warn( "NEW FRAGMENT DOCUMENT" );
+                # SvREFCNT_inc(RETVAL);
+
+                /* step 2: set the node list to the fragment */
+                fragment->children = rv;
+                rv->parent = fragment;
+                rv_end = rv;
+                while ( rv_end->next != NULL ) {
+                    rv_end = rv_end->next;
+                    rv_end->parent = fragment;
+                }
+                fragment->last = rv_end;
+            }
+            else {
+                # warn( "bad chunk" );
+                RETVAL = &PL_sv_undef;
+            }
+            /* free the chunk we created */
+            xmlFree( chunk );
+        }
+    OUTPUT:
+        RETVAL
+
+SV*
 encodeToUTF8( encoding, string )
         const char * encoding
         const char * string
         ProxyObject* cproxy = NULL;
         xmlNodePtr test = NULL;
     CODE:
-
-        # test = domAppendChild( parent->object, child->object );
-        # update the proxies if nessecary
-        if ( !(((xmlNodePtr)parent->object)->type == XML_DOCUMENT_NODE
-             && ((xmlNodePtr)child->object)->type == XML_ELEMENT_NODE ) 
-             && domAppendChild( parent->object, child->object ) != NULL ) {
-            if ( parent == NULL ) {
-                croak("parent problem!\n");
-            }
-
-            if ( ((xmlNodePtr)parent->object)->type == XML_DOCUMENT_NODE ) {
-                pproxy = parent;
-            }
-            else if ( parent->extra != NULL ){
-                pproxy = (ProxyObject*)SvIV((SV*)SvRV(parent->extra));
-            }
-            if ( child->extra != NULL ) {
-                cproxy = (ProxyObject*)SvIV((SV*)SvRV(child->extra));
-            }
-            if ( child->extra == NULL || parent->extra == NULL || pproxy->object != cproxy->object ) {
+        if ( parent == NULL ) {
+               croak("parent problem!\n");
+        }
+        if ( child == NULL ) {
+               croak("child problem!\n");
+        }
+
+        # warn( "append Child \n" );
+        if (((xmlNodePtr)parent->object)->type == XML_DOCUMENT_NODE
+             && ((xmlNodePtr)child->object)->type == XML_ELEMENT_NODE ) {
+            # warn( "use setDocumentElement!!!!\n" );
+            
+        }
+        else {
+            # test = domAppendChild( parent->object, child->object );
+            # update the proxies if nessecary
+            # warn( "real append\n" );
+            if ( domAppendChild( parent->object, child->object ) != NULL ) {
+
+                # warn( "node appended\n" );    
+                /* if we appended a fragment we do not need to change refcounts */
+                if ( !((xmlNodePtr)parent->object)->type == XML_DOCUMENT_FRAG_NODE ) {
+                    if ( ((xmlNodePtr)parent->object)->type == XML_DOCUMENT_NODE ) {
+                        pproxy = parent;
+                    }
+                    else if ( parent->extra != NULL ){
+                        pproxy = (ProxyObject*)SvIV((SV*)SvRV(parent->extra));
+                    }
+
+                    if ( child->extra != NULL ) {
+                        warn( "c1\n" );
+                        cproxy = (ProxyObject*)SvIV((SV*)SvRV(child->extra));
+                        warn( "c2\n" );    
+                    }
+
+                    if ( child->extra == NULL
+                         || parent->extra == NULL
+                         || pproxy->object != cproxy->object ) {
       
-                # warn("different documents");
-                if ( child->extra != NULL ){
-                    # warn("decrease child documents");   
-                    SvREFCNT_dec(child->extra);
+                        # warn("different documents");
+                        if ( child->extra != NULL ){
+                            # warn("decrease child documents");   
+                            SvREFCNT_dec(child->extra);
+                        }
+
+                        child->extra = parent->extra;
+
+                        if ( child->extra != NULL ){
+                            # warn("increase child documents");   
+                            SvREFCNT_inc(child->extra);
+                        }
+                    }
+                    else {
+                        # warn( "object failure\n" );
+                    }
                 }
-
-                child->extra = parent->extra;
-
-                if ( child->extra != NULL ){
-                    # warn("increase child documents");   
-                    SvREFCNT_inc(child->extra);
+                else {
+                    # warn( "fragment append!\n" );
                 }
             }
             else {
-                # warn( "object failure\n" );
+                # warn("append problem ...\n");
             }
         }
 
 
 MODULE = XML::LibXML         PACKAGE = XML::LibXML::DocumentFragment
 
+void
+_fix_extra(node_sv)
+        SV * node_sv
+    PREINIT:
+        ProxyObject* node;
+    CODE:
+        node = (ProxyObject *)SvIV((SV*)SvRV(node_sv));
+        node->extra = node_sv;
+
 SV*
 new( CLASS )
         char * CLASS
   xmlNodePtr helper = NULL;
   xmlNodePtr nodes  = NULL;
   
-  if ( doc && block ) {
+  if ( block ) {
     /* read and encode the chunk */
     retCode = xmlParseBalancedChunkMemory( doc, 
                                            NULL,
                                            0,
                                            block,
                                            &nodes );
-    
+
     /* error handling */
     if ( retCode != 0 ) {
       /* if the code was not well balanced, we will not return 
 domAppendChild( xmlNodePtr self,
                 xmlNodePtr newChild ){
     /* unbinds the new node if nessecary ... does not handle attributes :P */
+    /* fprintf( stderr,"check if child is not parent of the current node\n"); */
     newChild = domIsNotParentOf( newChild, self );
 
     if ( self == NULL ) {
               && newChild->children == NULL ) 
          ){
         /* HIERARCHIY_REQUEST_ERR */
+        /* fprintf(stderr,"HIERARCHIY_REQUEST_ERR\n"); */
         return NULL;
     }
 
     if ( newChild->doc == self->doc ){
+        /* fprintf(stderr,"child part of the current dom\n"); */
         newChild= domUnbindNode( newChild );
     }
     else {
         /* WRONG_DOCUMENT_ERR - non conform implementation*/
+        /* fprintf(stderr,"WRONG_DOCUMENT_ERR - non conform implementation\n"); */
         newChild= domImportNode( self->doc, newChild, 1 );
+        /* fprintf(stderr,"post import\n");  */
+
     }
-  
-  if ( self->children != NULL ) {
-    newChild = insert_node_to_nodelist( self->last, newChild , NULL );
-  }
-  else if (newChild->type == XML_DOCUMENT_FRAG_NODE ) {
-    xmlNodePtr cld = newChild->children;
-    self->children = newChild->children;
-    self->last     = newChild->last;
-    while( cld != NULL ){
-      cld->parent = self;
-      cld = cld->next;
+ 
+    /* fprintf(stderr,"real append\n");  */
+    if ( self->children != NULL ) {
+        /* fprintf(stderr,"append to the end of the child list\n");  */
+        newChild = insert_node_to_nodelist( self->last, newChild , NULL );
     }
-    cld->parent = self;
+    else if (newChild->type == XML_DOCUMENT_FRAG_NODE ) {
+        xmlNodePtr cld = newChild->children;
+        /* fprintf(stderr," insert a fragment into an empty node\n");  */
+        self->children = newChild->children;
+        self->last     = newChild->last;
+        while( cld != NULL ){
+            cld->parent = self;
+            cld = cld->next;
+        }
+        /* cld->parent = self; */
+        
+        newChild->children = NULL;
+        newChild->last = NULL;
+        /* cld = self->children; */
+    }
+    else {
+        /* fprintf(stderr,"single node, no children\n");  */
+
+        self->children = newChild;
+        self->last     = newChild;
+        newChild->parent= self;
+    }
     
-    newChild->children = NULL;
-    newChild->last = NULL;
-    cld = self->children;
-  }
-  else {
-    self->children = newChild;
-    self->last     = newChild;
-    newChild->parent= self;
-  }
-  return newChild;
+    /* fprintf(stderr,"append done...\n");  */
+    return newChild;
 }
 
 
  **/
 xmlNodePtr
 domIsNotParentOf( xmlNodePtr node1, xmlNodePtr node2 ) {
-  xmlNodePtr helper = NULL;
+    xmlNodePtr helper = NULL;
 
-  if ( node1 == NULL ) {
-    return NULL;
-  }
-
-  if( node2 == NULL || node1->doc != node2->doc) {
-    return node1;
-  }
-  
-  helper= node2;
-  while ( helper!=NULL ) {
-    if( helper == node1 ) {
-      return NULL;
+    if ( node1 == NULL ) {
+        return NULL;
     }
     
-    helper = helper->parent;
-    if ( (xmlDocPtr) helper == node2->doc ) {
-      helper = NULL;
+    if( node2 == NULL || node1->doc != node2->doc) {
+        return node1;
     }
-  }
-
-  return node1;
+    if( node2->type == XML_DOCUMENT_NODE ){  
+      return node1;
+    }
+    
+    helper= node2;
+    while ( helper!=NULL ) {
+        if( helper == node1 ) {
+            return NULL;
+        }
+        
+        helper = helper->parent;
+        if ( (xmlDocPtr) helper == node2->doc ) {
+            helper = NULL;
+        }
+    }
+    
+    return node1;
 }
 
 /**