Commits

ph...@9ae0c189-cd1f-4510-a509-f4891f5cf20d  committed 24d7354

Modified Files:
LibXML.xs
+ fixed a bunch of segfaults :(

lib/XML/LibXML/Iterator.pm
+ documentation
+ minor fixes(?)

  • Participants
  • Parent commits 670930b

Comments (0)

Files changed (2)

 
 #define LibXML_init_error() LibXML_error = NEWSV(0, 512); \
                             sv_setpvn(LibXML_error, "", 0);
-// #define LibXML_init_error()
+
 #define LibXML_croak_error() if ( SvCUR( LibXML_error ) > 0 ) { \
                                  croak("%s",SvPV(LibXML_error, len)); \
                              } 
         sv_catsv(LibXML_error, sv); /* remember the last error */
     }
     else {
-        /* warn("%s", SvPV(sv, PL_na)); */
-
-        //warn("%s", SvPV(sv, PL_na)); 
        croak("%s",SvPV(sv, PL_na));
     }
     SvREFCNT_dec(sv);
             LibXML_close_cb= item2;
     }
 
-     // LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader(); 
-     // xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_load_external_entity );
+     /* LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader();  */
+     /* xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_load_external_entity ); */
 
     return; 
 
         SV * extID
         SV * sysID
     PREINIT:
-        xmlDocPtr document = NULL;
+        xmlDocPtr real_doc = NULL;
         xmlDtdPtr dtd = NULL;
         xmlChar * name = NULL;
         xmlChar * externalID = NULL;
         xmlChar * systemID = NULL; 
     CODE:
-        document = (xmlDocPtr)PmmSvNode( doc );
-        if ( document == NULL ) {
+        real_doc = (xmlDocPtr)PmmSvNode( doc );
+        if ( real_doc == NULL ) {
             XSRETURN_UNDEF;   
         }
 
         externalID = Sv2C(extID, NULL);
         systemID   = Sv2C(sysID, NULL);
 
-        dtd = xmlNewDtd( document, name, externalID, systemID );
+        dtd = xmlNewDtd( real_doc, name, externalID, systemID );
 
         xmlFree(externalID);
         xmlFree(systemID);
         SV * extID
         SV * sysID
     PREINIT:
-        xmlDocPtr document = NULL;
+        xmlDocPtr real_doc = NULL;
         xmlDtdPtr dtd = NULL;
         xmlChar * name = NULL;
         xmlChar * externalID = NULL;
         xmlChar * systemID = NULL; 
     CODE:
-        document = (xmlDocPtr)PmmSvNode( doc );
-        if ( document == NULL ) {
+        real_doc = (xmlDocPtr)PmmSvNode( doc );
+        if ( real_doc == NULL ) {
             XSRETURN_UNDEF;   
         }
 
         systemID   = Sv2C(sysID, NULL);
 
         dtd = xmlNewDtd( NULL, name, externalID, systemID );
-        dtd->doc = document;
+        dtd->doc = real_doc;
 
         xmlFree(externalID);
         xmlFree(systemID);
         xmlNodePtr newNode;
         xmlDocPtr real_doc;
         xmlChar * elname = NULL;
+        ProxyNodePtr docfrag = NULL;
     CODE:
         STRLEN len;
         real_doc = (xmlDocPtr)PmmSvNode(dom);
+        docfrag = PmmNewFragment( real_doc );
        
         elname = nodeSv2C( name , (xmlNodePtr) real_doc );
         if ( elname != NULL || xmlStrlen(elname) > 0 ) {
             xmlFree(elname);
             if ( newNode != NULL ) {        
                 newNode->doc = real_doc;
+                PmmNODE(docfrag)->children = PmmNODE(docfrag)->last = newNode;
+                newNode->parent = PmmNODE( docfrag );
                 xs_warn( newNode->name );
-                RETVAL = PmmNodeToSv(newNode,NULL);
+                RETVAL = PmmNodeToSv(newNode,docfrag);
             }
             else {
                 xs_warn( "no node created!" );
         const xmlChar * pchar  = NULL;
         xmlNsPtr ns            = NULL;
         xmlDocPtr doc          = NULL;
+        ProxyNodePtr docfrag   = NULL;
         xmlNodePtr newNode     = NULL;
     CODE:
         doc = (xmlDocPtr)PmmSvNode( pdoc );
             newNode = xmlNewNode( NULL , localname );
             newNode->doc = doc;
         }
-
+        
         xmlSetNs(newNode, ns);
-
-        RETVAL = PmmNodeToSv(newNode,NULL);
+        docfrag = PmmNewFragment( doc );
+        PmmNODE(docfrag)->children = PmmNODE(docfrag)->last = newNode;
+        newNode->parent = PmmNODE( docfrag );
+        RETVAL = PmmNodeToSv(newNode, docfrag);
     
         if ( prefix != NULL ) {
             xmlFree(prefix);
         xmlNodePtr newNode;
         xmlDocPtr real_doc;
         xmlChar * elname = NULL;
+        ProxyNodePtr docfrag = NULL;
     CODE:
         STRLEN len;
         real_doc = (xmlDocPtr)PmmSvNode(doc);
+        docfrag = PmmNewFragment( real_doc );
        
         elname = nodeSv2C( content , (xmlNodePtr) real_doc );
         if ( elname != NULL || xmlStrlen(elname) > 0 ) {
             xmlFree(elname);
             if ( newNode != NULL ) {        
                 newNode->doc = real_doc;
-                RETVAL = PmmNodeToSv(newNode,NULL);
+                PmmNODE(docfrag)->children = PmmNODE(docfrag)->last = newNode;
+                newNode->parent = PmmNODE( docfrag );
+                xs_warn( newNode->name );
+                RETVAL = PmmNodeToSv(newNode,docfrag);
             }
             else {
                 xs_warn( "no node created!" );
         xmlNodePtr newNode;
         xmlDocPtr real_doc;
         xmlChar * elname = NULL;
+        ProxyNodePtr docfrag = NULL;
     CODE:
         STRLEN len;
         real_doc = (xmlDocPtr)PmmSvNode(doc);
+        docfrag = PmmNewFragment( real_doc );
        
         elname = nodeSv2C( content , (xmlNodePtr) real_doc );
         if ( elname != NULL || xmlStrlen(elname) > 0 ) {
             xmlFree(elname);
             if ( newNode != NULL ) {        
                 newNode->doc = real_doc;
-                RETVAL = PmmNodeToSv(newNode,NULL);
+                PmmNODE(docfrag)->children = PmmNODE(docfrag)->last = newNode;
+                newNode->parent = PmmNODE( docfrag );
+                xs_warn( newNode->name );
+                RETVAL = PmmNodeToSv(newNode,docfrag);
             }
             else {
                 xs_warn( "no node created!" );
         xmlNodePtr newNode;
         xmlDocPtr real_doc;
         xmlChar * elname = NULL;
+        ProxyNodePtr docfrag = NULL;
     CODE:
         real_doc = (xmlDocPtr)PmmSvNode(doc);
+        docfrag = PmmNewFragment( real_doc );
        
         elname = nodeSv2C( content , (xmlNodePtr) real_doc );
         if ( elname != NULL || xmlStrlen(elname) > 0 ) {
             xmlFree(elname);
             if ( newNode != NULL ) {        
                 newNode->doc = real_doc;
-                RETVAL = PmmNodeToSv( newNode, NULL );
+                PmmNODE(docfrag)->children = PmmNODE(docfrag)->last = newNode;
+                newNode->parent = PmmNODE( docfrag );
+                xs_warn( newNode->name );
+                RETVAL = PmmNodeToSv(newNode,docfrag);
             }
             else {
                 xs_warn( "no node created!" );
         xmlNodePtr newNode;
         xmlDocPtr doc = (xmlDocPtr)PmmSvNode(pdoc);
         xmlChar * name = Sv2C( pname, NULL );
+        ProxyNodePtr docfrag = NULL;        
     CODE:
         if ( name == NULL ) {
             XSRETURN_UNDEF;
         if ( newNode == NULL ) {
             XSRETURN_UNDEF;
         }
-        RETVAL = PmmNodeToSv( newNode, NULL );
+        docfrag = PmmNewFragment( doc );
+        PmmNODE(docfrag)->children = PmmNODE(docfrag)->last = newNode;
+        newNode->parent = PmmNODE( docfrag );
+
+        RETVAL = PmmNodeToSv( newNode, docfrag );
     OUTPUT:
         RETVAL
 
         }
         value = nodeSv2C( pvalue , (xmlNodePtr) doc );
         self = xmlNewDocProp( doc, name, value );
-        RETVAL = PmmNodeToSv((xmlNodePtr)self,NULL); 
+        RETVAL = PmmNodeToSv((xmlNodePtr)self, NULL); 
+
         xmlFree(name);
         if ( value ) {
             xmlFree(value);
                 self->ns = ns;
 
                 RETVAL = PmmNodeToSv((xmlNodePtr)self, NULL );
+
                 xmlFree(nsURI);
                 xmlFree(name);
                 if ( prefix ) {
         v = nodeSv2C(value, (xmlNodePtr)doc);
         PI = xmlNewPI(n,v);      
         PI->doc = doc;
-        /* RETVAL = PmmNodeToSv(PI, SvPROXYNODE(self)); */
-        RETVAL = PmmNodeToSv(PI, NULL);
+
+        RETVAL = PmmNodeToSv(PI,NULL);
+
         xmlFree(v);
         xmlFree(n);
     OUTPUT:
                 xmlDocSetRootElement( real_dom, elem );
             }
             else {
+                ProxyNodePtr frag = PmmNewFragment( real_dom );
                 xmlReplaceNode( oelem, elem );
+                domAppendChild( PmmNODE(frag),oelem );
+                PmmFixOwner( ((ProxyNodePtr)oelem->_private), frag);
             }
 
             if ( elem->_private != NULL ) {
     PREINIT:
         xmlNodePtr ret = NULL;
         xmlNodePtr real_node = NULL;
-        xmlDocPtr real_dom;
+        xmlDocPtr real_dom = NULL;
+        ProxyNodePtr frag = NULL;
     CODE:
         real_dom = (xmlDocPtr)PmmSvNode(dom);
         real_node=  PmmSvNode(node);
 
         ret = domImportNode( real_dom, real_node, 0 );
         if ( ret ) {
-            RETVAL = PmmNodeToSv( ret, SvPROXYNODE(dom));
+            frag = PmmNewFragment( real_dom );
+            PmmNODE(frag)->children = PmmNODE(frag)->last = ret;
+            ret->parent = PmmNODE( frag );
+            RETVAL = PmmNodeToSv( ret, frag);
         }
         else {
             XSRETURN_UNDEF;
         SV * node
     PREINIT:
         xmlNodePtr ret = NULL;
+        xmlNodePtr real_node = NULL;
+        xmlDocPtr real_dom = NULL;
         ProxyNodePtr frag = NULL;
-        xmlNodePtr real_node = NULL;
-        xmlDocPtr real_dom;
     CODE:
         real_dom = (xmlDocPtr)PmmSvNode(dom);
         real_node=  PmmSvNode(node);
         }
 
         ret = domImportNode( real_dom, real_node, 1 );
+
         if ( ret ) {
             frag = PmmNewFragment( real_dom );
-            domAppendChild( PmmNODE(frag), ret );
-            RETVAL = PmmNodeToSv(real_node, NULL);
-            PmmFixOwner(SvPROXYNODE(RETVAL),frag);
+            RETVAL = PmmNodeToSv(real_node, frag);
+            PmmNODE(frag)->children = PmmNODE(frag)->last = real_node;
+            real_node->parent = PmmNODE( frag );
+            PmmFixOwner(SvPROXYNODE(RETVAL), frag);
         }
         else {
             XSRETURN_UNDEF;
 DESTROY( node )
         SV * node
     CODE:
-        xs_warn("DESTROY NODE\n");
+        xs_warn("DESTROY PERL NODE\n");
         PmmREFCNT_dec(SvPROXYNODE(node));
 
 SV*
         XML::LibXML::Node::getName = 1
         XML::LibXML::Element::tagName = 2
     PREINIT:
-        char * name;
-        xmlNodePtr xnode = PmmSvNode(node);
+        char * name = NULL;
+        xmlNodePtr rnode = PmmSvNode(node);
     INIT:
-        if( xnode == NULL ) {
+        if( rnode == NULL ) {
             croak( "lost my node" );
         }
-        if( xnode->name == NULL ) {
+        if( rnode->name == NULL ) {
             croak( "lost the name!" );
         }
     CODE:
-        name =  domName( xnode );
+        name =  domName( rnode );
         RETVAL = C2Sv(name,NULL);
         xmlFree( name );
     OUTPUT:
         SV* oldChild
     PREINIT:
         xmlNodePtr pNode, nNode, oNode;
-        xmlNodePtr ret;
+        xmlNodePtr ret = NULL;
+        ProxyNodePtr frag = NULL;
     CODE:
         if ( newChild  == NULL
            || newChild == &PL_sv_undef
                 XSRETURN_UNDEF;
             }
             else {
+                frag = PmmNewFragment( pNode->doc );
                 /* create document fragment */
-                RETVAL = PmmNodeToSv(ret, NULL);
+                PmmNODE(frag)->children = PmmNODE(frag)->last = ret;
+                ret->parent = PmmNODE( frag );
+                RETVAL = PmmNodeToSv(ret, frag);
+
                 if ( nNode->_private != NULL ) {
                     PmmFixOwner( SvPROXYNODE(newChild),
                                  PmmOWNERPO(SvPROXYNODE(paren)) );
                 }
-                PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
+                PmmFixOwner( SvPROXYNODE(RETVAL), frag );
             }
         }
     OUTPUT:
         xmlNodePtr node = PmmSvNode( self );
         xmlNodePtr other = PmmSvNode( newNode );
         xmlNodePtr ret = NULL;
+        ProxyNodePtr frag = NULL;
     CODE:
         if ( other == NULL || domIsParent( node, other ) == 1 ) {
             XSRETURN_UNDEF;
         }
         ret = xmlReplaceNode( node, other );
         if ( ret ) {
-            RETVAL = PmmNodeToSv(ret,NULL);
+            if ( ret->type == XML_ATTRIBUTE_NODE ) {
+                frag = NULL;
+            }
+            else {
+                /* create document fragment */
+                frag = PmmNewFragment( node->doc );
+                PmmNODE(frag)->children = PmmNODE(frag)->last = ret;
+                ret->parent = PmmNODE( frag );
+            }
+                
+            RETVAL = PmmNodeToSv(ret, frag);
             if ( other->_private != NULL ) {
                 PmmFixOwner( SvPROXYNODE(newNode),
                              PmmOWNERPO(SvPROXYNODE(self)));
             }
-            PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
+            PmmFixOwner( SvPROXYNODE(RETVAL), frag );
         }
         else {
+            croak( "replacement failed" );
             XSRETURN_UNDEF;
         }
     OUTPUT:
                 XSRETURN_UNDEF;
             }
             else {
+                ProxyNodePtr frag = PmmNewFragment( ret->doc );
+                PmmNODE(frag)->children = PmmNODE(frag)->last = ret;
+                ret->parent = PmmNODE( frag );
                 RETVAL = PmmNodeToSv(ret,NULL);
-                PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
+                PmmFixOwner( SvPROXYNODE(RETVAL), frag );
             }
         }
     OUTPUT:
                     break;
                 }
             }
+
             rNode = domAppendChild( pNode, cNode );
+
             if ( rNode == NULL ) {
                 XSRETURN_UNDEF;
             }
         if ( other == NULL || other->type == XML_DOCUMENT_FRAG_NODE ) {
             XSRETURN_UNDEF;
         }
+
         ret = xmlAddSibling( node, other );
+
         if ( ret ) {
             RETVAL = PmmNodeToSv(ret,NULL);
             PmmFixOwner( SvPROXYNODE(RETVAL), PmmOWNERPO(SvPROXYNODE(self)) );
         int deep
     PREINIT:
         xmlNodePtr ret, node;
-        xmlDocPtr doc;
+        xmlDocPtr doc = NULL;
+        ProxyNodePtr frag = NULL;
     CODE:
         node = PmmSvNode( self );
         ret = PmmCloneNode( node, deep );
             
             # make namespaces available
             ret->ns = node->ns;
-
-            /* xmlReconciliateNs(ret->doc, ret); */
-
-            RETVAL = PmmNodeToSv(ret, NULL);
+            frag = PmmNewFragment( doc );
+            domAppendChild( PmmNODE(frag), ret );
+
+            RETVAL = PmmNodeToSv(ret, frag);
+        
         }   
     OUTPUT:
         RETVAL
         RETVAL
 
 SV*
-getAttribute( self, attr_name )
+getAttribute( self, attr_name, dom_enc = 0 )
         SV * self
         SV * attr_name
+        int dom_enc
     PREINIT:
         xmlNodePtr node = PmmSvNode( self );
         xmlChar * name = nodeSv2C(attr_name, node );
         xmlFree(name);
 
         if ( ret ) {
-            RETVAL = nodeC2Sv(ret, node);
+            if ( dom_enc == 1 ) { 
+                RETVAL = nodeC2Sv(ret, node);
+            }
+            else {
+                RETVAL = C2Sv(ret, NULL);
+            }
             xmlFree( ret );
         }
         else {
     PREINIT:
         xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self)); 
     CODE:
+        xs_warn( "DESTROY NS" );
         if (ns) {
             xmlFreeNs(ns);
         }

File lib/XML/LibXML/Iterator.pm

 #
 
 package XML::LibXML::Iterator;
+
 use strict;
 
 use overload
 the boundaries of a certain level. The iterator will get the next node
 for you until there is no node left to handle.
 
-In short: An iterator will answer the question about what is next to
-do.
+In short: An iterator will answer the question about what to do next.
 
 =head2 How to use XML::LibXML::Iterator?
 
 using either next() or previous(). Both function will return a
 XML::LibXML::Node object if there is such object available.
 
-Since the current object in the iterator is always available via the
-current() function, the position of the iterator can be changed inside
-a method or function.
+Since the current object hold by the iterator class is always
+available via the current() function.
 
+The following example may clearify this:
+
+  # get the document from wherever you like
+  my $doc = XML::LibXML->new->parse_stream( *SOMEINPUT );
+
+  # get the iterator for the document root.
+  my $iter = XML::LibXML::Iterator->new( $doc->documentElement );
+
+  # walk through the document
+  while ( $iter->next() ) {
+     my $curnode = $iter->current();
+     print $curnode->nodeType();
+  }
+
+  # now get back to the beginning
+  $iter->first();
+  my $curnode = $iter->current();
+  print $curnode->nodeType();
+
+Actually the functions next(), previous(), first(), last() and
+current() do return the node which is current after the
+operation. E.g. next() moves to the next node if possible and then
+returns the node. Thus the while-loop in the example can be written
+as
+
+  while ( $iter->next() ) {
+     print $_->nodeType();
+  }
+
+Note, that just relieing on the return value of next() and previous()
+is somewhat dangerous, because both functions return B<undef> in case
+of reaching the iteration boundaries. That means it is not possible
+to iterate past the last element or before the first one.
+
+=head2 Complex Iterations
+
+By default XML::LibXML::Iterator will access all nodes of a given DOM
+tree. An interation based on the default iterator will access each
+single node in the given subtree once. The order how the nodes will be
+accessed is given by the following order:
+
+  node -> node's childnodes -> node's next sibling
+
+This is great for a wide range of scripts. Nevertheless this is
+limited for some applications. XML::LibXML::Iterator allows to change
+that behaviour. This is done by resetting XML::LibXML::Iterator's
+iterator function. By using the method iterator_function() to override
+the default iterator function, it is possible to implement iterations
+based on any iteration rule imaginable.
+
+A valid iterator function has to take two parameters: As the first
+parameter it will recieve the iterator object itself, as second the
+direction of the iteration will be passed. The direction is either 1
+(for next()) or -1 (for previous()). As the iterator-function is
+called by next() and previous() the interator-function has to be aware
+about the iteration boundaries. In case the iteration would pass the
+boundary for that operation, the function has to return
+undefined. Also the iterator function has to return the new current node,
+instead of setting it itself.
+
+*DEVELOPER NOTE* In order a single stepping is rather limited, the
+direction is given by the sign of the passed integer value. The value
+of the passed parameter will be used as an indication how many steps
+should be done.  Therefor the interation direction should be tested
+relative to '0' and not as a equation. A basic template for a iterator
+function therefore will look like this:
+
+   sub iterator_func_templ {
+      my $iter = shift;
+      my $step = shift;
+      my $node = undef;
+      my $current = $iter->current();
+
+      if ( $step > 0 ) {
+          # move forward
+      }
+      else {
+          # move backward
+          $step *= -1; # remove the sign
+      }
+
+      return $node;
+   }
+
+=head2 Repeated Operation
+
+Another feature of XML::LibXML::Iterator is the ability to repeat a
+single operation on all nodes in scope. Instead of writing a loop one
+can specify the opeation as a function, that it applied on each node
+found. The function that does the trick, is named iterate().
+
+iterate() takes again two parameter: First the iterator object, second
+the node to operate on. iterate() will iterate through the entire
+document starting with the first node. If one has already started an
+iteration, the internal position will be reset to the first node.
+
+The following example will show how this works:
+
+  $iter->iterate( sub {shift; map {$_->setNodeName( lc $_->nodeName ) if $_->nodeType != NAMESPACE_DECLARATION } ($_[0], $_[0]->attributes);  } );
+
+This extra long line lowercases all tagnames and the names of the
+attributes in a given subtree.
 
 =head2 Functions
 
 will be called for each call of next() or previous(). It is used to
 find out about the next node recognized by the iterator.
 
-The iterator function has to take two parameters: As the first
-parameter it will recieve the iterator object, as second the direction
-of the iteration will be passed. The direction is either 1 (for next())
-or -1 (for previous()).
 
 The iterators iterate() function will take a function reference that
 takes as well two parameters. The first parameter is again the