1. Shlomi Fish
  2. perl-XML-LibXML

Commits

ph...@9ae0c189-cd1f-4510-a509-f4891f5cf20d  committed 8dbc003

Modified Files:
LibXML.xs
dom.c
dom.h
+ insertBefore
+ insertAfter
o XML::LibXML::Document::DESTROY segfault error removed
todo: proxy objects for Documents

example/libxml.xml
+ documentation
t/05dombasic.t
+ segfault tests
Added Files:
t/09append.t
tests insertBefore and insertAfter

  • Participants
  • Parent commits 6c07aa1
  • Branches default

Comments (0)

Files changed (7)

File LibXML.xs

View file
 DESTROY(self)
         xmlDocPtr self
     CODE:
-        if (self == NULL) {
-            XSRETURN_UNDEF;
-        }
-        xmlFreeDoc(self);
+        /* if (self == NULL) { */
+        /*    XSRETURN_UNDEF; */
+        /* } */
+        /* xmlFreeDoc(self); */
 
 SV *
 toString(self)
 DESTROY( node )
         xmlNodePtr node 
     CODE:
-        if ( node->parent == 0 ) {
         /**
          * this block should remove old (unbound) nodes from the system
          * but for some reason this condition is not valid ... :(
         /*domUnbindNode( node );  * before freeing we unbind the node from
 		                          * possible siblings */
         /* xmlFreeNode( node ); */
-    }
+    
 	
 int 
 getType( node ) 
         RETVAL
 
 
+void
+insertBefore( self, new, ref ) 
+        xmlNodePtr self
+        xmlNodePtr new
+        xmlNodePtr ref
+    CODE:
+        domInsertBefore( self, new, ref );
+
+void
+insertAfter( self, new, ref )
+        xmlNodePtr self
+        xmlNodePtr new
+        xmlNodePtr ref
+    CODE:
+        domInsertAfter( self, new, ref );
+
 xmlDocPtr
 getOwnerDocument( elem )
         xmlNodePtr elem
     PREINIT:
-        const char * CLASS = "XML::LibXML::NoGCDocument";
+        const char * CLASS = "XML::LibXML::Document";
     CODE:
         RETVAL = elem->doc;
     OUTPUT:

File dom.c

View file
   return old ;
 }
 
+xmlNodePtr
+domInsertBefore( xmlNodePtr self, 
+                 xmlNodePtr newChild,
+                 xmlNodePtr refChild ){
+  if ( self == NULL ) {
+    return NULL;
+  }
+
+  if ( refChild == NULL && newChild != NULL ) {
+    /* insert newChild as first Child */
+    if ( self->children == NULL ) {
+      return domAppendChild( self, newChild );
+    }
+    
+    domUnbindNode( newChild );
+
+    newChild->next = self->children;
+    self->children->prev = newChild;
+   
+    self->children = newChild;
+
+    return newChild;
+  }
+
+  if ( newChild != NULL && 
+       self == refChild->parent &&
+       refChild != newChild ) {
+    /* find the refchild, to avoid spoofed parents */
+    xmlNodePtr hn = self->children;
+    while ( hn ) {
+      if ( hn == refChild ) {
+        /* found refChild */
+        newChild = domUnbindNode( newChild );
+        newChild->parent = self;
+        newChild->next = refChild;
+        newChild->prev = refChild->prev;
+        if ( refChild->prev != NULL ) {
+          refChild->prev->next = newChild;
+        }
+        refChild->prev = newChild;
+        if ( refChild == self->children ) {
+          self->children = newChild;
+        }
+        return newChild;
+      }
+      hn = hn->next;
+    }
+  }
+  return NULL;
+}
+
+xmlNodePtr
+domInsertAfter( xmlNodePtr self, 
+                xmlNodePtr newChild,
+                xmlNodePtr refChild ){
+  if ( self == NULL ) {
+    return NULL;
+  }
+
+  if ( refChild == NULL ) {
+    return domAppendChild( self, newChild );
+  }
+
+  if ( newChild != NULL && 
+       self == refChild->parent &&
+       refChild != newChild ) {
+    /* find the refchild, to avoid spoofed parents */
+    xmlNodePtr hn = self->children;
+    while ( hn ) {
+      if ( hn == refChild ) {
+        /* found refChild */
+        newChild = domUnbindNode( newChild );
+        newChild->parent = self;
+        newChild->prev = refChild;
+        newChild->next = refChild->next;
+        if ( refChild->next != NULL ) {
+          refChild->next->prev = newChild;
+        }
+        refChild->next = newChild;
+
+        if ( refChild == self->last ) {
+          self->last = newChild;
+        }
+        return newChild;
+      }
+      hn = hn->next;
+    }
+  }
+  return NULL;
+}
+
 void
 domSetNodeValue( xmlNodePtr n , xmlChar* val ){
   if ( n == 0 ) 

File dom.h

View file
 domReplaceChild( xmlNodePtr self,
                  xmlNodePtr oldChlid,
                  xmlNodePtr newChild );
-/* xmlNodePtr */
-/* domInsertBefore( xmlNodePtr self,  */
-/* 		 xmlNodePtr newChild, */
-/* 		 xmlNodePtr refChild ); */
 xmlNodePtr
 domRemoveNode( xmlNodePtr self,
                xmlNodePtr Child );
+xmlNodePtr
+domInsertBefore( xmlNodePtr self, 
+                 xmlNodePtr newChild,
+                 xmlNodePtr refChild );
 
+xmlNodePtr
+domInsertAfter( xmlNodePtr self, 
+                xmlNodePtr newChild,
+                xmlNodePtr refChild );
 
 /* A.3 extra functionality not specified in DOM L1/2*/
 void

File example/libxml.xml

View file
 	it is allready bound to another document.
 </method>
 
+<method name="insertBefore" synopsis="$node->insertBefore( $newNode, $refNode )">
+    The method inserts <i>$newNode</i> before <i>$refNode</i>. If
+    <i>$refNode</i> is undefined, the newNode will be set as the new
+    first child of the parent node.
+</method>
+
+<method name="insertAfter" synopsis="$node->insertAfter( $newNode, $refNode )">
+    The method inserts <i>$newNode</i> after <i>$refNode</i>. If
+    <i>$refNode</i> is undefined, the newNode will be set as the new
+    last child of the parent node.
+</method>
+
 <method name="findnodes" synopsis="@nodes = $node->findnodes( $xpath_statement );">
 	<b>findnodes</b> performs the xpath statement on the current node and 
 	returns the result as an array. 

File lib/XML/LibXML/Node.pod

View file
   $childnode = $node->getLastChild()
   $dom = $node->getOwnerDocument()
   $node->setOwnerDocument( $dom );
+  $node->insertBefore( $newNode, $refNode )
+  $node->insertAfter( $newNode, $refNode )
   @nodes = $node->findnodes( $xpath_statement );
   @children = $node->getChildnodes();
   $xmlstring = $node->toString();
 
 This function binds a node to another DOM. This method unbinds the node first, if it is allready bound to another document.
 
+=item B<insertBefore>
+
+The method inserts I<$newNode> before I<$refNode> . If I<$refNode> is undefined, the newNode will be set as the new
+first child of the parent node.
+
+=item B<insertAfter>
+
+The method inserts I<$newNode> after I<$refNode> . If I<$refNode> is undefined, the newNode will be set as the new
+last child of the parent node.
+
 =item B<findnodes>
 
 B<findnodes> performs the xpath statement on the current node and returns the result as an array.

File t/05dombasic.t

View file
 # `make test'. After `make install' it should work as `perl test.pl'
 
 use Test;
-BEGIN { plan tests=>10; }
+BEGIN { plan tests=>13; }
 END {ok(0) unless $loaded;}
 use XML::LibXML;
 $loaded = 1;
 my $vers    = "1.0";
 my $enc     = "iso-8859-1";
 my $testtxt = "test";
-my $file    = "example/libxml.xml";
+my $file    = "example/dromeds.xml";
 
 my $dom = XML::LibXML::Document->createDocument( $vers, $enc );
 ok($dom);
 my $te = $dom->getDocumentElement();
 ok( defined $te && $te->getName() eq $elem->getName() );
 
+my $node;
+{
+    my $dom2 = XML::LibXML::Document->createDocument( $vers, $enc );
+    $node   = $dom2->createElement( $testtxt );
+    $dom2->setDocumentElement( $node );
+}
+
+# this ends scope and older versions should segfault here 
+ok( defined $node && $node->getName() eq $testtxt );
+
+{ 
+    my $dom2 = $node->getOwnerDocument();
+    ok( defined $dom2 && $dom2->isa( 'XML::LibXML::Document' ) ); 
+}
+
+# this ends scope and older versions should segfault here 
+ok( defined $node && $node->getName() eq $testtxt );
+
+
+
 my $text = $dom->createTextNode( $testtxt );
 ok( defined $text && $text->isa( "XML::LibXML::Text" ) );
 
   ok( defined $elem && 
       $elem->getType() == XML_ELEMENT_NODE &&
       $elem->isa( "XML::LibXML::Element" ) );
-}
+}

File t/09append.t

View file
+use Test;
+BEGIN { plan tests=>6; }
+END {ok(0) unless $loaded;}
+use XML::LibXML;
+$loaded = 1;
+ok($loaded);
+
+# this script tests if insertBefore and insertAfter functions work properly
+
+my ( $dom, $root, $node1, $node2, $node3 );
+
+$dom = XML::LibXML::Document->new( "1.0", "iso-8859-1" );
+
+$root  = $dom->createElement( "R" );
+$node1 = $dom->createElement( "a" );
+$node2 = $dom->createElement( "b" );
+$node3 = $dom->createElement( "c" );
+
+$dom->setDocumentElement( $root ); 
+$root->appendChild( $node1 );
+
+my @children = $root->getChildnodes();
+ok( ( scalar @children == 1 ) && ( $children[0]->getName() eq "a" ) );
+
+$root->insertBefore( $node2 , $node1 );
+ @children = $root->getChildnodes();
+ok( ( scalar @children == 2 ) && ( $children[0]->getName() eq "b" ) );
+
+$root->insertAfter( $node3 , $node1 );
+ @children = $root->getChildnodes();
+ok( ( scalar @children == 3 ) && ( $children[2]->getName() eq "c" ) );
+ 
+$root->removeChild( $node3 );
+@children = $root->getChildnodes();
+ok( ( scalar @children == 2  ) );
+
+# lets switch two nodes :)
+$root->insertAfter( $node2, $node1 ); 
+@children = $root->getChildnodes();
+ok( ( scalar @children == 2 ) && 
+    ( $children[1]->getName() eq "b" ) &&
+    ( $children[0]->getName() eq "a" ) );