Commits

Anonymous committed 4874c9d

Modified Files:
Changes
+ version information

LibXML.pm LibXML.xs
[fix] importNode(), adoptNode() bug fixed
+ setOwnerDocument()
- stupid warnings

dom.c
[fix] domImportNode() shows correct DOM behaviour

example/libxml.xml
+ documentation for adoptNode()
o updated docs for setOwnerDocument() and importNode()

t/04node.t
+ import and adoptation tests

Comments (0)

Files changed (6)

    - push parser interface
    - basic native libxml2 SAX interface
    - XML::LibXML::Document::process_xincludes reintroduced
+   - Class wide callbacks added 
    - code cleanings
+   - fixed library tests and output in Makefile.PL
    - more documentation
+   - more tests
+   - importNode() bug fix
+   - compatibility fixes
+   - cloneNode clones now within documents
 
 1.49
    - memory management has been completely rewritten.
     return undef;
 }
 
+sub setOwnerDocument {
+    my ( $self, $doc ) = @_;
+    $doc->adoptNode( $self );
+}
+
 1;
 
 package XML::LibXML::Document;
         real_node=  PmmSvNode(node);
         ret = domImportNode( real_dom, real_node, 0 );
         if ( ret ) {
-            RETVAL = newSVsv(node);
-            PmmFixOwner(SvPROXYNODE(node),SvPROXYNODE(dom));
+            RETVAL = PmmNodeToSv( ret, SvPROXYNODE(dom));
         }
         else {
             XSRETURN_UNDEF;
         SV * node
     PREINIT:
         xmlNodePtr ret = NULL;
+        ProxyNodePtr frag = NULL;
         xmlNodePtr real_node = NULL;
         xmlDocPtr real_dom;
     CODE:
         real_node=  PmmSvNode(node);
         ret = domImportNode( real_dom, real_node, 1 );
         if ( ret ) {
+            frag = PmmNewFragment( real_dom );
+            domAppendChild( PmmNODE(frag), ret );
             RETVAL = newSVsv(node);
-            PmmFixOwner(SvPROXYNODE(node),SvPROXYNODE(dom));
+            PmmFixOwner(SvPROXYNODE(node),frag);
         }
         else {
             XSRETURN_UNDEF;
             xmlFree(prefix);
         }
         else {
-            warn("node name normal\n");
+            xs_warn("node name normal\n");
             xmlNodeSetName(node, string );
         }
         xmlFree(string);
 SV*
 nextSibling( self ) 
         SV *self
+    ALIAS:
+        getNextSibling = 1
     CODE:
         RETVAL = PmmNodeToSv( PmmSvNode(self)->next,
                               PmmOWNERPO( SvPROXYNODE(self) ) ); 
 SV*
 previousSibling( self )
         SV *self
+    ALIAS:
+        getPreviousSibling = 1
     CODE:
         RETVAL = PmmNodeToSv( PmmSvNode(self)->prev,
                               PmmOWNERPO( SvPROXYNODE(self) ) ); 
         RETVAL
 
 SV*
-cloneNode( self, deep ) 
+cloneNode( self, deep=0 ) 
         SV* self
         int deep
     PREINIT:
         xmlNodePtr ret;
+        xmlDocPtr doc;
         ProxyNodePtr docfrag = NULL;
     CODE:
         if ( PmmSvNode( self )->type == XML_DTD_NODE ) {
         }
         else {
             ret = xmlCopyNode( PmmSvNode(self), deep );
-    
+            doc = PmmSvNode(self)->doc;
+            
+            if ( doc != NULL ) {
+                xmlSetTreeDoc(ret, doc);
+            }
+
             if (ret != NULL) {
                 docfrag = PmmNewFragment( ret->doc );
                 domAppendChild( PmmNODE(docfrag), ret );            
 xmlNodePtr
 domImportNode( xmlDocPtr doc, xmlNodePtr node, int move ) {
     xmlNodePtr return_node = node;
-    
-    if ( node && doc && node->doc != doc ) {
-        if ( move ) {
-            return_node = node;
-            if ( node->type != XML_DTD_NODE ) {
-                xmlUnlinkNode( node );
-            }
+
+    if ( move ) {
+        return_node = node;
+        if ( node->type != XML_DTD_NODE ) {
+            xmlUnlinkNode( node );
+        }
+    }
+    else {
+        if ( node->type == XML_DTD_NODE ) {
+            return_node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node);
         }
         else {
-            if ( node->type == XML_DTD_NODE ) {
-                return_node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node);
-            }
-            else {
-                return_node = xmlCopyNode( node, 1 );
-            }
+            return_node = xmlCopyNode( node, 1 );
         }
-        /* tell all children about the new boss */ 
+    }
 
+    /* tell all children about the new boss */ 
+    if ( node && doc && node->doc != doc ) {
         xmlSetTreeDoc(return_node, doc);
     }
  

example/libxml.xml

             </method>
 
             <method name="importNode"
-                    synopsis="$document->importNode( $node [, $move] );">
+                    synopsis="$document->importNode( $node );">
                 <p>
                     If a node is not part of a document, it can be
                     imported to another document. As specified in DOM
                     Level 2 Specification the Node will not be altered
-                    or removed from its original document by
-                    default. (<em>$node->cloneNode(1)</em> will get
-                    called implicitly).
-                </p>
-                <p>
-                    Sometimes it is nessecary to <em>move</em> a node
-                    between documents. In such a case the node will
-                    not be copied, but removed from the original
-                    document.
+                    or removed from its original document
+                    (<em>$node->cloneNode(1)</em> will get called implicitly).
                 </p>
                 <p>
 		<st>NOTE:</st> Don't try to use importNode() to import 
 		a limitation of libxml2 and not of XML::LibXML itself.
 		</p>
             </method>
+            <method name="adoptNode"
+                    synopsis="$document->adoptNode( $node );">
+                <p>
+                    If a node is not part of a document, it can be
+                    imported to another document. As specified in DOM
+                    Level 3 Specification the Node will not be altered
+                    but it will removed from its original document.
+                </p>
+                <p>
+                    After a document adopted a node, the node, its
+                    attributes and all its descendants belong to the
+                    new document. Because the node does not belong to
+                    the old document, it will be unlinked from its old
+                    location first.
+                </p>
+                <p>
+		<st>NOTE:</st> Don't try to adoptNode() to import subtrees
+		that contain entity references - even if the entity reference
+		is the root node of the subtree. This will cause serious
+		problems to your program. This is a limitation of libxml2 and
+		not of XML::LibXML itself.
+		</p>
+             </method>
 
         </description>
         <also>
             </method>
 
             <method name="setOwnerDocument" 
-                    synopsis="$node->setOwnerDocument( $dom );">
+                    synopsis="$node->setOwnerDocument( $doc );">
                 <p>
                     This function binds a node to another DOM. This
                     method unbinds the node first, if it is allready
                     bound to another document.
                 </p>
                 <p>
-                    Note that this is only safe with single nodes but not 
-                    with subtrees. In case of subtrees one should use 
-                    XML::LibXML::Document's importNode method.
+                    This function is the oposite calling of
+                    XML::LibXML::Document's adoptNode()
+                    function. Because of this it has the same
+                    limitations with Entity References as adoptNode().
                 </p>
             </method>
 
 
 use Test;
 
-BEGIN { plan tests => 101 };
+BEGIN { plan tests => 115 };
 use XML::LibXML;
 
 my $xmlstring = q{<foo>bar<foobar/><bar foo="foobar"/><!--foo--><![CDATA[&foo bar]]></foo>};
     ok(@att);
     ok(scalar(@att), 3);
     ok($attributes->length, 3);
+}
+
+print "# 7. importing and adopting\n";
+
+{
+    my $parser = XML::LibXML->new;
+    my $doc1 = $parser->parse_string( "<foo>bar<foobar/></foo>" );
+    my $doc2 = XML::LibXML::Document->new;
+
+    ok( $doc1 && $doc2 );
+    my $rnode1 = $doc1->documentElement;
+    ok( $rnode1 );
+    my $rnode2 = $doc2->importNode( $rnode1 );
+    ok( not $rnode2->isSameNode( $rnode1 ) ) ;
+    $doc2->setDocumentElement( $rnode2 );
+
+    my $node = $rnode2->cloneNode(0);
+    ok( $node );
+    my $cndoc = $node->ownerDocument;
+    ok( $cndoc );
+    ok( $cndoc->isSameNode( $doc2 ) );
+
+    my $xnode = XML::LibXML::Element->new("test");
+
+    my $node2 = $doc2->importNode($xnode);
+    ok( $node2 );
+    my $cndoc2 = $node2->ownerDocument;
+    ok( $cndoc2 );
+    ok( $cndoc2->isSameNode( $doc2 ) );
+ 
+    my $doc3 = XML::LibXML::Document->new;
+    my $node3 = $doc3->adoptNode( $xnode );
+    ok( $node3 );
+    ok( $xnode->isSameNode( $node3 ) );
+    ok( $doc3->isSameNode( $node3->ownerDocument ) );
+
+    my $xnode2 = XML::LibXML::Element->new("test");
+    $xnode2->setOwnerDocument( $doc3 ); # alternate version of adopt node
+    ok( $xnode2->ownerDocument );
+    ok( $doc3->isSameNode( $xnode2->ownerDocument ) );    
 }