Commits

Anonymous committed ffeffa7

LibXML.pm
+ XML::LibXML::DocumentFragment isa Node
+ improved iterator function
+ changed version number to 0.95

LibXML.xs
+ fixed some more memory leaks
+ introduced XML::LibXML::DocumentFragment Class
+ new Node::getOwner function
+ better array handling
+ DOM L2 conform naming aliases
+ fixed some entity encoding
+ make unbound nodes to be part of Document fragments, so they can get
destroyed
+ more proxy fixes and securety checks
+ setAttributeNode works now

PHISHS.CHANGES
+ updated the log

dom.c dom.h
+ domSetNodeValue function is aware of attributes
+ domReplaceNode updated
+ added internal function insert_node_to_nodelist, for
cleaner code in adding, insert and replace functions :)

example/libxml.xml
+ updated the docu

t/06nodetypes.t
+ added DocumentFragment tests

t/07nodelist.t
+ added attribute tests

t/09append.t
+ added some debugging code (as comment)

t/11memory.t
+ added document fragment memory release checks

Comments (0)

Files changed (11)

 use vars qw($VERSION @ISA @EXPORT);
 use Carp;
 
-$VERSION = "0.94";
+$VERSION = "0.95";
 require Exporter;
 require DynaLoader;
 
 sub XML_XINCLUDE_END(){20;}
 
 @XML::LibXML::Document::ISA         = 'XML::LibXML::Node';
-@XML::LibXML::Element::ISA      = 'XML::LibXML::Node';
-@XML::LibXML::Text::ISA         = 'XML::LibXML::Node';
-@XML::LibXML::Comment::ISA      = 'XML::LibXML::Text';
-@XML::LibXML::CDATASection::ISA = 'XML::LibXML::Text';
-@XML::LibXML::NoGCDocument::ISA = 'XML::LibXML::Document';
-@XML::LibXML::Attr::ISA         = 'XML::LibXML::Node';
+@XML::LibXML::Element::ISA          = 'XML::LibXML::Node';
+@XML::LibXML::Text::ISA             = 'XML::LibXML::Node';
+@XML::LibXML::Comment::ISA          = 'XML::LibXML::Text';
+@XML::LibXML::CDATASection::ISA     = 'XML::LibXML::Text';
+@XML::LibXML::Attr::ISA             = 'XML::LibXML::Node';
+@XML::LibXML::DocumentFragment::ISA = 'XML::LibXML::Node';
 
-# sub XML::LibXML::NoGCDocument::DESTROY () { }
 
 sub XML::LibXML::Node::iterator {
     my $self = shift;
     my $child = undef;
 
     my $rv = $funcref->( $self );
-    $child = $self->getFirstChild();
-    while ( $child ) {
+    foreach $child ( $self->childNodes() ){
         $rv = $child->iterator( $funcref );
-        $child = $child->getNextSibling();
     }
     return $rv;
 }
     close($handler);
   }
 
+=head1 Encoding
+
+All data will be stored UTF-8 encoded. Nevertheless the input and
+output functions are aware about the encoding of the owner
+document. By default all functions will assume, UTF-8 encoding of the
+passed strings unless the owner document has a different encoding. In
+such a case the functions will assume the encoding of the document to
+be valid.
+
+At the current state of implementation query functions like
+B<findnodes()>, B<getElementsByTagName()> or B<getAttribute()> accept
+B<only> UTF-8 encoded strings, even if the underlaying document has a
+different encoding. At first this seems to be a limitation, but on
+application level there is no way to make save asumptations about the
+encoding of the strings.
+
+Future releases will offer the opportunity to force an application
+wide encoding, so make shure that you installed the latest version of
+XML::LibXML.
+
+To encode or decode a string to or from UTF-8 B<XML::LibXML> exports
+two functions, which use the encoding mechanism of the underlaying
+implementation. These functions should be used, if external encoding
+is required (e.g. for queryfunctions).
+
+=head2 encodeToUTF8
+
+    $encodedstring = encodeToUTF8( $name_of_encoding, $sting_to_encode );
+
+The function will encode a string from the specified encoding to UTF-8.
+
+=head2 decodeFromUTF8
+
+    $decodedstring = decodeFromUTF8($name_of_encoding, $string_to_decode );
+
+This Function transforms an UTF-8 encoded string the specified
+encoding.  While transforms to ISO encodings may cause errors if the
+given stirng contains unsupported characters, this function can
+transform to UTF-16 encodings as well.
+
 =head1 AUTHOR
 
 Matt Sergeant, matt@sergeant.org
 L<XML::LibXSLT>, 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::CDATASection>, L<XML::LibXML::Attribute>
+L<XML::LibXML::DocumentFragment>
 
 =cut
     CODE:
         if ( self->object != NULL ) {
             xmlFreeDoc((xmlDocPtr)self->object);
-            # warn( "REAL DOCUMENT DROP SUCCEEDS" );
+            #warn( "REAL DOCUMENT DROP SUCCEEDS" );
         }        
         self->object = NULL;
         Safefree( self );
     OUTPUT:
         RETVAL
 
+SV*
+createDocumentFragment( dom )
+        SV * dom
+    PREINIT:
+        SV * frag_sv = NULL;
+        xmlDocPtr real_dom;
+        xmlNodePtr fragment= NULL;
+        ProxyObject *ret=NULL;
+        const char * CLASS = "XML::LibXML::DocumentFragment";
+    CODE:
+        real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
+        fragment = xmlNewDocFragment( real_dom );
+        ret = make_proxy_node( fragment );
+        RETVAL = sv_newmortal();
+        sv_setref_pv( RETVAL, (char *)CLASS, (void*)ret );
+        ret->extra = RETVAL;
+        # warn( "NEW FRAGMENT DOCUMENT" );
+        SvREFCNT_inc(RETVAL);
+        SvREFCNT_inc(RETVAL);
+    OUTPUT:
+        RETVAL
+
 ProxyObject *
 createElement( dom, name )
         SV * dom
         char * CLASS = "XML::LibXML::Element";
         xmlNodePtr newNode;
         xmlDocPtr real_dom;
+        xmlNodePtr docfrag = NULL;
+        ProxyObject * dfProxy= NULL;
+        SV * docfrag_sv = NULL;
     CODE:
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
 
+        docfrag = xmlNewDocFragment( real_dom );
+        dfProxy = make_proxy_node( docfrag );
+        docfrag_sv =sv_newmortal();
+        sv_setref_pv( docfrag_sv, "XML::LibXML::DocumentFragment", (void*)dfProxy );
+        dfProxy->extra = docfrag_sv;
+        # warn( "NEW FRAGMENT ELEMNT (%s)", name);
+        # SvREFCNT_inc(docfrag_sv);    
+
         newNode = xmlNewNode( NULL , 
                               domEncodeString( real_dom->encoding, name ) );
         newNode->doc = real_dom;
+        domAppendChild( docfrag, newNode );
         # warn( newNode->name );
         RETVAL = make_proxy_node(newNode);
-        RETVAL->extra = dom;
-        SvREFCNT_inc(dom);
+        RETVAL->extra = docfrag_sv;
+        SvREFCNT_inc(docfrag_sv);
     OUTPUT:
         RETVAL
 
          xmlChar *lname = NULL;
          xmlNsPtr ns = NULL;
          xmlDocPtr real_dom;
+         xmlNodePtr docfrag = NULL;
+         ProxyObject * dfProxy= NULL;
+         SV * docfrag_sv = NULL;
      CODE:
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
+
+        docfrag = xmlNewDocFragment( real_dom );
+        dfProxy = make_proxy_node( docfrag );
+        docfrag_sv =sv_newmortal();
+        sv_setref_pv( docfrag_sv, "XML::LibXML::DocumentFragment", (void*)dfProxy );
+        dfProxy->extra = docfrag_sv;
+        # warn( "NEW FRAGMENT ELEMENT NS (%s)", qname);
+        # SvREFCNT_inc(docfrag_sv);    
+
         if ( nsURI != NULL && strlen(nsURI)!=0 ){
             lname = xmlSplitQName2(qname, &prefix);
             ns = domNewNs (0 , 
         }
         newNode = xmlNewNode( ns ,
                               domEncodeString( real_dom->encoding, lname ) );
-        newNode->doc =(xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
+        newNode->doc = real_dom;
+        domAppendChild( docfrag, newNode );
+
         RETVAL = make_proxy_node(newNode);
-        RETVAL->extra = dom;
-        SvREFCNT_inc(dom);
+        RETVAL->extra = docfrag_sv;
+        SvREFCNT_inc(docfrag_sv);
      OUTPUT:
         RETVAL
 
         char * CLASS = "XML::LibXML::Text";
         xmlNodePtr newNode;
         xmlDocPtr real_dom;
+        xmlNodePtr docfrag = NULL;
+        ProxyObject * dfProxy= NULL;
+        SV * docfrag_sv = NULL;
     CODE:
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
 
+        docfrag = xmlNewDocFragment( real_dom );
+        dfProxy = make_proxy_node( docfrag );
+        docfrag_sv =sv_newmortal();
+        sv_setref_pv( docfrag_sv, "XML::LibXML::DocumentFragment", (void*)dfProxy );
+        dfProxy->extra = docfrag_sv;
+        # warn( "NEW FRAGMENT TEXT");
+        # SvREFCNT_inc(docfrag_sv);    
+
         newNode = xmlNewDocText( real_dom, 
                                  domEncodeString( real_dom->encoding,
                                                   content ) );
+        domAppendChild( docfrag, newNode );
+
         RETVAL = make_proxy_node(newNode);
-        RETVAL->extra = dom;
-        SvREFCNT_inc(dom);
+        RETVAL->extra = docfrag_sv;
+        SvREFCNT_inc(docfrag_sv);
     OUTPUT:
         RETVAL
 
         char * CLASS = "XML::LibXML::Comment";
         xmlNodePtr newNode;
         xmlDocPtr real_dom;
+        xmlNodePtr docfrag = NULL;
+        ProxyObject * dfProxy= NULL;
+        SV * docfrag_sv = NULL;
     CODE:
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
         content = domEncodeString( real_dom->encoding, content );
+        
+        newNode = xmlNewDocComment( real_dom, content );
+        
+        docfrag = xmlNewDocFragment( real_dom );
+        dfProxy = make_proxy_node( docfrag );
+        docfrag_sv =sv_newmortal();
+        sv_setref_pv( docfrag_sv, "XML::LibXML::DocumentFragment", (void*)dfProxy );
+        dfProxy->extra = docfrag_sv;
+        # warn( "NEW FRAGMENT COMMENT");
+        # SvREFCNT_inc(docfrag_sv);    
+        domAppendChild( docfrag, newNode );
 
-        newNode = xmlNewDocComment( real_dom, content );
         RETVAL = make_proxy_node(newNode);
-        RETVAL->extra = dom;
-        SvREFCNT_inc(dom);
+        RETVAL->extra = docfrag_sv;
+        SvREFCNT_inc(docfrag_sv);
     OUTPUT:
         RETVAL
 
         char * CLASS = "XML::LibXML::CDATASection";
         xmlNodePtr newNode;
         xmlDocPtr real_dom;
+        xmlNodePtr docfrag = NULL;
+        ProxyObject * dfProxy= NULL;
+        SV * docfrag_sv = NULL;
     CODE:
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
         content = domEncodeString( real_dom->encoding, content );
 
         newNode = domCreateCDATASection( real_dom, content );
+        
+        docfrag = xmlNewDocFragment( real_dom );
+        dfProxy = make_proxy_node( docfrag );
+        docfrag_sv =sv_newmortal();
+        sv_setref_pv( docfrag_sv, "XML::LibXML::DocumentFragment", (void*)dfProxy );
+        dfProxy->extra = docfrag_sv;
+        # warn( "NEW FRAGMENT CDATA");
+        # SvREFCNT_inc(docfrag_sv);    
+        domAppendChild( docfrag, newNode );
+
         RETVAL = make_proxy_node(newNode);
-        RETVAL->extra = dom;
-        SvREFCNT_inc(dom);
+        RETVAL->extra = docfrag_sv;
+        SvREFCNT_inc(docfrag_sv);
     OUTPUT:
         RETVAL
 
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
         name  = domEncodeString( real_dom->encoding, name );
         value = domEncodeString( real_dom->encoding, value );
-
+        
         newNode = (xmlNodePtr)xmlNewProp(NULL, name , value );
         newNode->doc = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
         if ( newNode->children!=NULL ) {
     PREINIT:
         xmlDocPtr real_dom;
         xmlNodePtr elem;
+        SV* oldsv =NULL;
     CODE:
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
-        SvREFCNT_dec(proxy->extra);
         elem = (xmlNodePtr)proxy->object;
+
         # please correct me if i am wrong: the document element HAS to be
         # an ELEMENT NODE
         if ( elem->type == XML_ELEMENT_NODE ) {
+            if( proxy->extra != NULL ) {
+                #warn( "decrease holder element" );
+                oldsv = proxy->extra;
+            }
             domSetDocumentElement( real_dom, elem );
             proxy->extra = dom;
             SvREFCNT_inc(dom);
+            SvREFCNT_dec( oldsv );  
         }
 
 ProxyObject *
 getDocumentElement( dom )
         SV * dom
+    ALIAS:
+        XML::LibXML::Document::documentElement = 1
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
         xmlNodePtr elem;
 ProxyObject *
 importNode( dom, node, move=0 ) 
         SV * dom
-        xmlNodePtr node
+        ProxyObject * node
         int move
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
-        xmlNodePtr ret;
+        xmlNodePtr ret = NULL;
+        xmlNodePtr real_node = NULL;
         xmlDocPtr real_dom;
     CODE:
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
+        real_node= (xmlNodePtr)node->object;
         RETVAL = NULL;
-        ret = domImportNode( real_dom, node, move );
+        ret = domImportNode( real_dom, real_node, move );
         if ( ret ) {
+            if ( node->extra != NULL ){
+                SvREFCNT_dec( node->extra );
+            }
             CLASS = domNodeTypeName( ret );
             RETVAL = make_proxy_node(ret);
             RETVAL->extra = dom;
     CODE:
         xmlFreeDtd(self);
 
-
 MODULE = XML::LibXML         PACKAGE = XML::LibXML::Node
 
 void
         real_node = (xmlNodePtr)node->object;
         if ( node->extra != NULL
              && real_node != NULL ){
+            if( real_node->type == XML_DOCUMENT_FRAG_NODE ) {
+                warn( "NODE DESTROY: NODE ISA DOCUMENT_FRAGMENT!" );
+            }
+
             if ( SvREFCNT( node->extra ) > 0 ){
                 SvREFCNT_dec(node->extra);
             }
 int 
 getType( node ) 
         xmlNodePtr node
+    ALIAS:
+        XML::LibXML::Node::nodeType = 1
     CODE:
         RETVAL = node->type;
     OUTPUT:
         RETVAL
 
 void
-unbindNode( elem )
-        xmlNodePtr elem
+unbindNode( proxyelem )
+        ProxyObject * proxyelem
+    PREINIT:
+        xmlNodePtr elem       = NULL;
+        xmlNodePtr docfrag    = NULL;
+        ProxyObject * dfProxy = NULL;
+        SV * docfrag_sv       = NULL;
     CODE:
+        elem = (xmlNodePtr)proxyelem->object;
         domUnbindNode( elem );
 
+        docfrag = xmlNewDocFragment( elem->doc );
+        dfProxy = make_proxy_node( docfrag );
+        docfrag_sv =sv_newmortal();
+        sv_setref_pv( docfrag_sv,
+                      "XML::LibXML::DocumentFragment", 
+                      (void*)dfProxy );
+        dfProxy->extra = docfrag_sv;
+        #warn("NEW FRAGMENT ON NODE %s", elem->name);
+        # SvREFCNT_inc(docfrag_sv);    
+
+        domAppendChild( docfrag, elem );
+        if( proxyelem->extra != NULL ){
+            SvREFCNT_dec( proxyelem->extra );
+        }    
+        proxyelem->extra = docfrag_sv;
+        SvREFCNT_inc(docfrag_sv);             
+
 ProxyObject *
 removeChild( paren, child ) 
         xmlNodePtr paren
                 if ( newChild->extra != NULL ){
                     # warn("increase child documents");   
                     SvREFCNT_inc(newChild->extra);
-                    SvREFCNT_inc(newChild->extra);
+                    # SvREFCNT_inc(newChild->extra);
                 }
             }
         }
     CODE:
         domAppendChild( parent->object, child->object );
         # update the proxies if nessecary
-        
+
         if ( parent->extra != NULL ){
             pproxy = (ProxyObject*)SvIV((SV*)SvRV(parent->extra));
         }
         if ( child->extra != NULL ) {
             cproxy = (ProxyObject*)SvIV((SV*)SvRV(child->extra));
         }
-        if ( pproxy == NULL || 
-             cproxy == NULL || 
-             pproxy->object != cproxy->object ) {
+        if ( child->extra == NULL || parent->extra == NULL || pproxy->object != cproxy->object ) {
       
             # warn("different documents");
             if ( child->extra != NULL ){
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
         xmlNodePtr ret;
+        xmlNodePtr docfrag = NULL;
+        ProxyObject * dfProxy= NULL;
+        SV * docfrag_sv = NULL;
     CODE:
         ret = xmlCopyNode( (xmlNodePtr)self->object, deep );
         RETVAL = NULL;
         if (ret != NULL) {
+            docfrag = xmlNewDocFragment( ret->doc );
+            dfProxy = make_proxy_node( docfrag );
+            docfrag_sv =sv_newmortal();
+            sv_setref_pv( docfrag_sv, "XML::LibXML::DocumentFragment", (void*)dfProxy );
+            dfProxy->extra = docfrag_sv;
+            # warn( "NEW FRAGMENT CLONE");
+            # SvREFCNT_inc(docfrag_sv);    
+            domAppendChild( docfrag, ret );            
+
             CLASS = domNodeTypeName( ret );
             RETVAL = make_proxy_node(ret);
-            if( self->extra != NULL ) {
-                RETVAL->extra = self->extra ;
-                SvREFCNT_inc(self->extra);                
-            }
+            RETVAL->extra = docfrag_sv ;
+            SvREFCNT_inc(docfrag_sv);                
         }
     OUTPUT:
         RETVAL
 ProxyObject *
 getParentNode( self )
         ProxyObject* self
+    ALIAS:
+        XML::LibXML::Node::parentNode = 1
     PREINIT:
         const char * CLASS = "XML::LibXML::Element";
         xmlNodePtr ret;
 ProxyObject *
 getNextSibling( elem )
         ProxyObject* elem
+    ALIAS:
+        XML::LibXML::Node::nextSibling = 1
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
         xmlNodePtr ret;
 ProxyObject *
 getPreviousSibling( elem )
         ProxyObject* elem
+    ALIAS:
+        XML::LibXML::Node::previousSibling = 1
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
         xmlNodePtr ret;
     CODE:
         ret = ((xmlNodePtr)elem->object)->prev;
         RETVAL = NULL;
-        if ( ret ) {
+        if ( ret != NULL ) {
             CLASS = domNodeTypeName( ret );
             RETVAL = make_proxy_node(ret);
             if( elem->extra != NULL ) {
 ProxyObject *
 getFirstChild( elem )
         ProxyObject* elem
+    ALIAS:
+        XML::LibXML::Node::firstChild = 1
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
         xmlNodePtr ret;
 ProxyObject *
 getLastChild( elem )
         ProxyObject* elem
+    ALIAS:
+        XML::LibXML::Node::lastChild = 1
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
         xmlNodePtr ret;
         if ( new->extra != NULL ) {
             cproxy = (ProxyObject*)SvIV((SV*)SvRV(new->extra));
         }
-        if ( pproxy == NULL || 
-             cproxy == NULL || 
-             pproxy->object != cproxy->object ) {
+        if ( pproxy->object != cproxy->object ) {
       
             # warn("different documents");
             if ( new->extra != NULL ){
-                # warn("decrease child documents");   
+                # warn("decrease old child document");   
                 SvREFCNT_dec(new->extra);
             }
 
             new->extra = self->extra;
 
             if ( new->extra != NULL ){
-                # warn("increase child documents");   
+                #warn("increase child document");   
                 SvREFCNT_inc(new->extra);
             }
         }
             }
         }
 
-
 SV*
 getOwnerDocument( elem )
         ProxyObject* elem
+    ALIAS:
+        XML::LibXML::Node::ownerDocument = 1
     CODE:
-        RETVAL = elem->extra;
-        SvREFCNT_inc( RETVAL );
+        RETVAL = &PL_sv_undef;
+        if( ((xmlNodePtr)elem->object)->doc != NULL && elem->extra != NULL ){
+            RETVAL = elem->extra;
+            SvREFCNT_inc( RETVAL );
+        }
+    OUTPUT:
+        RETVAL
+
+SV*
+getOwner( elem ) 
+        ProxyObject * elem
+    CODE:
+        RETVAL = &PL_sv_undef;
+        if( elem->extra != NULL ){
+            RETVAL = elem->extra;
+            SvREFCNT_inc( RETVAL );
+        }
     OUTPUT:
         RETVAL
 
     CODE:
         real_doc = (xmlDocPtr)doc->object;
         domSetOwnerDocument( elem->object, real_doc );
+        SvREFCNT_inc( doc->extra );
 
 SV*
 getName( node )
         xmlNodePtr node
+    ALIAS:
+        XML::LibXML::Node::nodeName = 1
+        XML::LibXML::Attr::name     = 2
     PREINIT:
         const char * name;
     CODE:
         domSetName( node, value );
 
 SV*
-getData( node ) 
-        xmlNodePtr node 
+getData( proxy_node ) 
+        ProxyObject * proxy_node 
+    ALIAS:
+        XML::LibXML::Attr::value     = 1
+        XML::LibXML::Node::nodeValue = 2
+        XML::LibXML::Attr::getValue  = 3
     PREINIT:
+        xmlNodePtr node;
         const char * content;
     CODE:
+        node = (xmlNodePtr) proxy_node->object; 
+
         if( node != NULL ) {
             if ( node->type != XML_ATTRIBUTE_NODE ){
                 if ( node->doc != NULL ){
         RETVAL
 
 
-SV*
+void
 findnodes( node, xpath )
         ProxyObject* node
         char * xpath 
     PREINIT:
-        xmlNodeSetPtr nodelist;
-        SV * element;
-        int len;
+        xmlNodeSetPtr nodelist = NULL;
+        SV * element = NULL ;
+        int len = 0 ;
+        int wantarray = GIMME_V;
     PPCODE:
-        len = 0;
         nodelist = domXPathSelect( node->object, xpath );
         if ( nodelist && nodelist->nodeNr > 0 ) {
             int i = 0 ;
             ProxyObject * proxy;
 
             len = nodelist->nodeNr;
-         
-            for( i ; i < len; i++){
+            if( wantarray != G_SCALAR ) {         
+                for( i ; i < len; i++){
                 /* we have to create a new instance of an objectptr. and then 
                  * place the current node into the new object. afterwards we can 
                  * push the object to the array!
                  */
-                element = 0;
-                tnode = nodelist->nodeTab[i];
-                element = sv_newmortal();
+                    element = 0;
+                    tnode = nodelist->nodeTab[i];
+                    element = sv_newmortal();
                 
-                proxy = make_proxy_node(tnode);
+                    proxy = make_proxy_node(tnode);
+                    if ( node->extra != NULL ) {
+                        proxy->extra = node->extra;
+                        SvREFCNT_inc(node->extra);
+                    }
+        
+                    element = sv_setref_pv( element, (char *)cls, (void*)proxy );
+                    cls = domNodeTypeName( tnode );
+                    XPUSHs( element );
+                }
+            }
+            else {
+                XPUSHs( newSViv(len) );
+            }
+            xmlXPathFreeNodeSet( nodelist );
+        }
+
+void
+getChildnodes( node )
+        ProxyObject* node
+    ALIAS:
+        XML::LibXML::Node::childNodes = 1
+    PREINIT:
+        xmlNodePtr cld;
+        SV * element;
+        int len = 0;
+        const char * cls = "XML::LibXML::Node";
+        ProxyObject * proxy;
+        int wantarray = GIMME_V;
+    PPCODE:
+        cld = ((xmlNodePtr)node->object)->children;
+        while ( cld ) {
+            if( wantarray != G_SCALAR ) {
+	            element = sv_newmortal();
+                cls = domNodeTypeName( cld );
+                proxy = make_proxy_node(cld);
                 if ( node->extra != NULL ) {
                     proxy->extra = node->extra;
                     SvREFCNT_inc(node->extra);
                 }
-
-                cls = domNodeTypeName( tnode );
-                XPUSHs( sv_setref_pv( element, (char *)cls, (void*)proxy ) );
+                element = sv_setref_pv( element, (char *)cls, (void*)proxy );
+                XPUSHs( element );
             }
-
-            xmlXPathFreeNodeSet( nodelist );
-        }
-        XSRETURN(len);
-
-SV*
-getChildnodes( node )
-        ProxyObject* node
-    PREINIT:
-        xmlNodePtr cld;
-        SV * element;
-        int len;
-        const char * cls = "XML::LibXML::Node";
-        ProxyObject * proxy;
-    PPCODE:
-        len = 0;
-	
-        cld = ((xmlNodePtr)node->object)->children;
-        while ( cld ) {	
-            element = sv_newmortal();
-            cls = domNodeTypeName( cld );
-            proxy = make_proxy_node(cld);
-            if ( node->extra != NULL ) {
-                proxy->extra = node->extra;
-                SvREFCNT_inc(node->extra);
-            }
-            XPUSHs( sv_setref_pv( element, (char *)cls, (void*)proxy ) );
             cld = cld->next;
             len++;
         }
-        XSRETURN(len);
+        if ( wantarray == G_SCALAR ) {
+            XPUSHs( newSViv(len) );
+        }        
 
 SV*
 toString( self )
 SV*
 getLocalName( node )
         xmlNodePtr node
+    ALIAS:
+        XML::LibXML::Node::localname = 1
     PREINIT:
         const char * lname;
     CODE:
 SV*
 getPrefix( node )
         xmlNodePtr node
+    ALIAS:
+        XML::LibXML::Node::prefix = 1
     PREINIT:
         const char * prefix;
     CODE:
     OUTPUT:
         RETVAL
 
+int 
+hasAttributes( node ) 
+        ProxyObject * node
+    CODE:
+        RETVAL = 0;
+        if( ((xmlNodePtr)node->object)->type == 1 
+            ||((xmlNodePtr)node->object)->type == 7
+            ||((xmlNodePtr)node->object)->type >= 9 ) {
+            if( ((xmlNodePtr)node->object)->properties != NULL ) {
+                RETVAL = 1;
+            }
+        }
+    OUTPUT:
+        RETVAL
+
+void
+getAttributes( node )
+        ProxyObject* node
+    ALIAS:
+        XML::LibXML::Node::attributes = 1
+    PREINIT:
+        xmlAttrPtr attr = NULL;
+        xmlNodePtr real_node = NULL;
+        SV * element;
+        int len=0;
+        const char * CLASS = "XML::LibXML::Attr";
+        int wantarray = GIMME_V;
+    PPCODE:
+        real_node = (xmlNodePtr) node->object;
+
+        attr      = real_node->properties;
+        while ( attr != NULL ) {
+            ProxyObject * proxy=NULL;
+            element = sv_newmortal();   
+            proxy = make_proxy_node((xmlNodePtr)attr);
+            if ( node->extra != NULL ) {
+                proxy->extra = node->extra;
+                SvREFCNT_inc(node->extra);
+            }
+            if ( wantarray != G_SCALAR ) {
+                XPUSHs( sv_setref_pv( element, (char *)CLASS, (void*)proxy ) );
+            }
+            attr = attr->next;
+            len++;
+         }
+         if( wantarray == G_SCALAR ) {
+            XPUSHs( newSViv( len ) );
+         }
+
+void
+getAttributesNS( node,nsURI )
+        ProxyObject* node
+        char * nsURI
+    PREINIT:
+        xmlAttrPtr attr = NULL;
+        xmlNodePtr real_node = NULL;
+        SV * element;
+        int len = 0;
+        const char * CLASS = "XML::LibXML::Attr";
+        int wantarray = GIMME_V;
+    PPCODE:
+        real_node = (xmlNodePtr) node->object;
+
+        attr      = real_node->properties;
+        while ( attr != NULL ) {
+            if( attr->ns != NULL && xmlStrcmp( nsURI, attr->ns->href ) == 0 ){ 
+                ProxyObject * proxy;
+                element = sv_newmortal();
+                
+                proxy = make_proxy_node((xmlNodePtr)attr);
+                if ( node->extra != NULL ) {
+                    proxy->extra = node->extra;
+                    SvREFCNT_inc(node->extra);
+                }
+                if( wantarray != G_SCALAR ) {
+                    XPUSHs( sv_setref_pv( element, (char *)CLASS, (void*)proxy ) );
+                }
+                len++;
+            }
+            attr = attr->next;
+        }
+         if( wantarray == G_SCALAR ) {
+            XPUSHs( newSViv( len ) );
+         }
+
 MODULE = XML::LibXML         PACKAGE = XML::LibXML::Element
 
 ProxyObject *
     CODE:
         # CLASS = "XML::LibXML::Element";
         newNode = xmlNewNode( 0, name );
-        if ( newNode != 0 ) {
+        if( newNode != NULL ) {
+            # init the keeping fragment
+            xmlNodePtr docfrag = NULL;
+            ProxyObject * dfProxy = NULL; 
+            SV * docfrag_sv = NULL;
+
+            docfrag = xmlNewDocFragment(NULL);
+            dfProxy = make_proxy_node( docfrag );
+
+            docfrag_sv = sv_newmortal(); 
+            sv_setref_pv( docfrag_sv, 
+                          "XML::LibXML::DocumentFragment", 
+                          (void*)dfProxy );
+            dfProxy->extra = docfrag_sv;
+            # SvREFCNT_inc(docfrag_sv);
+            # warn( "NEW FRAGMENT ELEMENT(%s)",name);
+         
             newNode->next     = 0;
             newNode->prev     = 0;
             newNode->children = 0 ;
             newNode->last     = 0;
             newNode->doc      = 0;
+
+            domAppendChild( docfrag, newNode );            
+
             RETVAL = make_proxy_node(newNode);
+            RETVAL->extra = docfrag_sv;
+            SvREFCNT_inc(docfrag_sv);
         }
     OUTPUT:
         RETVAL
     OUTPUT:
         RETVAL
 
-SV*
-getAttributes( node )
-        ProxyObject* node
-    PREINIT:
-        xmlAttrPtr attr = NULL;
-        xmlNodePtr real_node = NULL;
-        SV * element;
-        int len=0;
-        const char * CLASS = "XML::LibXML::Attr";
-    PPCODE:
-        real_node = (xmlNodePtr) node->object;
-
-        attr      = real_node->properties;
-        while ( attr != NULL ) {
-            ProxyObject * proxy=NULL;
-            element = sv_newmortal();   
-            proxy = make_proxy_node((xmlNodePtr)attr);
-            if ( node->extra != NULL ) {
-                proxy->extra = node->extra;
-                SvREFCNT_inc(node->extra);
-            }
-            XPUSHs( sv_setref_pv( element, (char *)CLASS, (void*)proxy ) );
-            attr = attr->next;
-            len++;
-         }
-        XSRETURN(len);
-
-SV*
-getAttributesNS( node,nsURI )
-        ProxyObject* node
-        char * nsURI
-    PREINIT:
-        xmlAttrPtr attr = NULL;
-        xmlNodePtr real_node = NULL;
-        SV * element;
-        int len = 0;
-        const char * CLASS = "XML::LibXML::Attr";
-    PPCODE:
-        real_node = (xmlNodePtr) node->object;
-
-        attr      = real_node->properties;
-        while ( attr != NULL ) {
-            if( attr->ns != NULL && xmlStrcmp( nsURI, attr->ns->href ) == 0 ){ 
-                ProxyObject * proxy;
-                element = sv_newmortal();
-                
-                proxy = make_proxy_node((xmlNodePtr)attr);
-                if ( node->extra != NULL ) {
-                    proxy->extra = node->extra;
-                    SvREFCNT_inc(node->extra);
-                }
-                XPUSHs( sv_setref_pv( element, (char *)CLASS, (void*)proxy ) );
-                len++;
-            }
-            attr = attr->next;
-        }
-        XSRETURN(len);
-
 void
 removeAttribute( elem, name ) 	
         xmlNodePtr elem
         ns = xmlSearchNsByHref(elem->doc, elem, nsURI);
         xmlUnsetNsProp( elem, ns, lname );
 
-SV*
+void
 getElementsByTagName( elem, name )
         ProxyObject* elem
         char * name 
     PREINIT:
         xmlNodeSetPtr nodelist;
         SV * element;
-        int len;
+        int len = 0;
+        int wantarray = GIMME_V;
     PPCODE:
-        len = 0;
         nodelist = domGetElementsByTagName( elem->object , name );
         if ( nodelist && nodelist->nodeNr > 0 ) {
             int i = 0 ;
             ProxyObject * proxy;
 
             len = nodelist->nodeNr;
-         
-            for( i ; i < len; i++){
+            if( wantarray == G_ARRAY ) {
+                for( i ; i < len; i++){
                 /* we have to create a new instance of an objectptr. and then 
                  * place the current node into the new object. afterwards we can 
                  * push the object to the array!
                  */
-                element = 0;
-                tnode = nodelist->nodeTab[i];
-                element = sv_newmortal();
+                    element = 0;
+                    tnode = nodelist->nodeTab[i];
+                    element = sv_newmortal();
                 
-                proxy = make_proxy_node(tnode);
-                if ( elem->extra != NULL ) {
-                    proxy->extra = elem->extra;
-                    SvREFCNT_inc(elem->extra);
+                    proxy = make_proxy_node(tnode);
+                    if ( elem->extra != NULL ) {
+                        proxy->extra = elem->extra;
+                        SvREFCNT_inc(elem->extra);
+                    }
+                    cls = domNodeTypeName( tnode );
+                    XPUSHs( sv_setref_pv( element, (char *)cls, (void*)proxy ) );
                 }
-                cls = domNodeTypeName( tnode );
-                XPUSHs( sv_setref_pv( element, (char *)cls, (void*)proxy ) );
             }
-
+            else {
+                XPUSHs( newSViv( len ) );
+            }
             xmlXPathFreeNodeSet( nodelist );
         }
-        XSRETURN(len);
 
-SV*
+void
 getElementsByTagNameNS( node, nsURI, name )
         ProxyObject* node
         char * nsURI
     PREINIT:
         xmlNodeSetPtr nodelist;
         SV * element;
-        int len;
+        int len = 0;
+        int wantarray = GIMME_V;
     PPCODE:
-        len = 0;
         nodelist = domGetElementsByTagNameNS( node->object , nsURI , name );
         if ( nodelist && nodelist->nodeNr > 0 ) {
             int i = 0 ;
             ProxyObject * proxy;
 
             len = nodelist->nodeNr;
-         
-            for( i ; i < len; i++){
+            if( wantarray == G_ARRAY ) {
+                for( i ; i < len; i++){
                 /* we have to create a new instance of an objectptr. and then 
                  * place the current node into the new object. afterwards we can 
                  * push the object to the array!
                  */
-                element = 0;
-                tnode = nodelist->nodeTab[i];
-                element = sv_newmortal();
+                    element = 0;
+                    tnode = nodelist->nodeTab[i];
+                    element = sv_newmortal();
                 
-                proxy = make_proxy_node(tnode);
-                if ( node->extra != NULL ) {
-                    proxy->extra = node->extra;
-                    SvREFCNT_inc(node->extra);
+                    proxy = make_proxy_node(tnode);
+                    if ( node->extra != NULL ) {
+                        proxy->extra = node->extra;
+                        SvREFCNT_inc(node->extra);
+                    }
+
+                    cls = domNodeTypeName( tnode );
+                    XPUSHs( sv_setref_pv( element, (char *)cls, (void*)proxy ) );
                 }
-
-                cls = domNodeTypeName( tnode );
-                XPUSHs( sv_setref_pv( element, (char *)cls, (void*)proxy ) );
             }
- 
+            else {
+                XPUSHs( newSViv( len ) );
+            }
             xmlXPathFreeNodeSet( nodelist );
         }
-        XSRETURN(len);
-
 
 void
 appendWellBalancedChunk( self, chunk )
 appendTextNode( self, xmlString )
         xmlNodePtr self
         char * xmlString
+    ALIAS:
+        XML::LibXML::Element::appendText = 1
     PREINIT: 
         xmlNodePtr tn;
     CODE:
 void
 setData( node, value )
         xmlNodePtr node
-        char * value 
+        char * value
+    ALIAS:
+        XML::LibXML::Attr::setValue = 1 
     CODE:
         if ( node->doc != NULL ) {
             value = domEncodeString( node->doc->encoding, value );
+            # encode the entities
+            value = xmlEncodeEntitiesReentrant( node->doc, value );
         }
         domSetNodeValue( node, value );
 
          * problems with iso encoded strings :(
          */
         newNode = xmlNewText( content );
-        RETVAL = make_proxy_node(newNode);
+        if( newNode != NULL ) {
+            # init the keeping fragment
+            xmlNodePtr docfrag = NULL;
+            ProxyObject * dfProxy = NULL; 
+            SV * docfrag_sv = NULL;
+
+            docfrag = xmlNewDocFragment(NULL);
+            dfProxy = make_proxy_node( docfrag );
+
+            docfrag_sv = sv_newmortal(); 
+            sv_setref_pv( docfrag_sv, 
+                          "XML::LibXML::DocumentFragment", 
+                          (void*)dfProxy );
+            dfProxy->extra = docfrag_sv;
+            # warn( "NEW FRAGMENT TEXT");
+            # SvREFCNT_inc(docfrag_sv);
+                     
+            domAppendChild( docfrag, newNode );            
+
+            RETVAL = make_proxy_node(newNode);
+            RETVAL->extra = docfrag_sv;
+            SvREFCNT_inc(docfrag_sv);
+        }
     OUTPUT:
         RETVAL
 
         xmlNodePtr newNode;
     CODE:
         newNode = xmlNewComment( content );
-        RETVAL = make_proxy_node(newNode);
+        if( newNode != NULL ) {
+            # init the keeping fragment
+            xmlNodePtr docfrag = NULL;
+            ProxyObject * dfProxy = NULL; 
+            SV * docfrag_sv = NULL;
+
+            docfrag = xmlNewDocFragment(NULL);
+            dfProxy = make_proxy_node( docfrag );
+
+            docfrag_sv = sv_newmortal(); 
+            sv_setref_pv( docfrag_sv, 
+                          "XML::LibXML::DocumentFragment", 
+                          (void*)dfProxy );
+            dfProxy->extra = docfrag_sv;
+            # warn( "NEW FRAGMENT COMMENT");
+            # SvREFCNT_inc(docfrag_sv);
+                     
+            domAppendChild( docfrag, newNode );            
+
+            RETVAL = make_proxy_node(newNode);
+            RETVAL->extra = docfrag_sv;
+            SvREFCNT_inc(docfrag_sv);
+        }
     OUTPUT:
         RETVAL
 
     PREINIT:
         xmlNodePtr newNode;
     CODE:
+        RETVAL = NULL;
         newNode = xmlNewCDataBlock( 0 , content, xmlStrlen( content ) );
-        RETVAL = make_proxy_node(newNode);
+        if ( newNode != NULL ){
+            # init the keeping fragment
+            xmlNodePtr docfrag = NULL;
+            ProxyObject * dfProxy = NULL; 
+            SV * docfrag_sv = NULL;
+
+            docfrag = xmlNewDocFragment(NULL);
+            dfProxy = make_proxy_node( docfrag );
+
+            docfrag_sv = sv_newmortal(); 
+            sv_setref_pv( docfrag_sv, 
+                          "XML::LibXML::DocumentFragment", 
+                          (void*)dfProxy );
+            dfProxy->extra = docfrag_sv;
+            # warn( "NEW FRAGMENT CDATA");
+            # SvREFCNT_inc(docfrag_sv);
+            
+            domAppendChild( docfrag, newNode );            
+
+            RETVAL = make_proxy_node(newNode);
+            RETVAL->extra = docfrag_sv;
+            SvREFCNT_inc(docfrag_sv);            
+        }
     OUTPUT:
         RETVAL
 
         char * name
         char * value
     PREINIT:
-        xmlNodePtr attr;
+        xmlNodePtr attr = NULL;
     CODE:
         attr = (xmlNodePtr)xmlNewProp( NULL, name, value );
         if ( attr ) {
     OUTPUT:
         RETVAL
 
-SV*
-getValue( attr )
-        xmlNodePtr attr;
-    PREINIT:
-        xmlBufferPtr buffer;
-        xmlNodePtr doc;
+void
+DESTROY(self)
+        ProxyObject* self
     CODE:
-        if ( attr != NULL && attr->children != NULL ) {
-            if ( attr->doc == NULL ) {
-                RETVAL = newSVpvn( attr->children->content, 
-                                   xmlStrlen( attr->children->content )  );
-            }
-            else {
-                char *str = domDecodeString( attr->doc->encoding, 
-                                             attr->children->content );
-                RETVAL =  newSVpvn( str, xmlStrlen( str ) );
-            }
+        if ( (xmlNodePtr)self->object != NULL 
+              && ((xmlNodePtr)self->object)->parent == NULL ) {
+            ((xmlNodePtr)self->object)->doc =NULL;
+            xmlFreeProp((xmlAttrPtr)self->object);            
+            # warn( "REAL ATTRIBUTE DROPPED" );
         }
-        else {
-            RETVAL = &PL_sv_undef;
+        # else {
+            # warn("ATTRIBUTE IS BOUND");
+        # }
+        if( self->extra != NULL ) {
+            SvREFCNT_dec(self->extra);
         }
-    OUTPUT:
-        RETVAL
-
-void
-setValue( attr, value )
-        xmlNodePtr attr 
-        char * value
-    CODE:
-        if ( attr->doc != NULL ) {
-            value = domEncodeString( attr->doc->encoding, value );
-        }
-
-        if ( attr->children != NULL ) {
-            domSetNodeValue( attr->children , value );
-        }
-        else {
-            xmlNodePtr newNode; 
-            if ( attr->doc != NULL ) {
-                newNode = xmlNewDocText( attr->doc , value );
-            }
-            else {
-                newNode = xmlNewText( value );                
-            }
-            if( newNode != NULL ) {
-                domAppendChild( attr, newNode ); 
-            }
-            else {
-                croak( "out of memory" );
-            }
-        }
+        self->object = NULL;
+        Safefree( self );
 
 ProxyObject *
 getOwnerElement( attrnode ) 
         ProxyObject * attrnode 
+    ALIAS:
+        XML::LibXML::Attr::ownerElement = 1
     PREINIT:
         const char * CLASS = "XML::LibXML::Node";
         xmlNodePtr attr;
         }
     OUTPUT:
         RETVAL
+
+SV*
+getParentElement( attrnode )
+        ProxyObject * attrnode
+    ALIAS:
+        XML::LibXML::Attr::parentNode = 1
+    CODE:
+        RETVAL = &PL_sv_undef;
+    OUTPUT:
+        RETVAL
+
+MODULE = XML::LibXML         PACKAGE = XML::LibXML::DocumentFragment
+
+SV*
+new( CLASS )
+        char * CLASS
+    PREINIT:
+        SV * frag_sv = NULL;
+        xmlNodePtr real_dom=NULL;
+        ProxyObject * ret= NULL;
+    CODE:
+        real_dom = xmlNewDocFragment( NULL ); 
+        ret = make_proxy_node( real_dom );
+        RETVAL = sv_newmortal();
+        sv_setref_pv( RETVAL, (char *)CLASS, (void*)ret );
+        ret->extra = RETVAL;
+        # warn( "NEW FRAGMENT FORCE NEW");
+        SvREFCNT_inc(RETVAL);
+        /* double incrementation needed here */
+        SvREFCNT_inc(RETVAL);
+    OUTPUT:
+        RETVAL
+
+void
+DESTROY(self)
+        ProxyObject* self
+    CODE:
+        if ( (xmlNodePtr)self->object != NULL ) {
+            # domSetOwnerDocument( (xmlNodePtr)self->object, NULL ); 
+            # if( ((xmlNodePtr)self->object)->children !=NULL){
+            #     warn("CLDNODES EXIST");
+            #     warn(" --> %s \n", ((xmlNodePtr)self->object)->children->name );
+            # }
+            
+            xmlFreeNode(self->object);
+            # warn( "REAL DOCUMENT FRAGMENT DROPPED" );
+        }
+        self->object = NULL;
+        Safefree( self );
 
 docs : pure_all
 \t\@$^X -Iblib/arch -Iblib/lib example/xml2pod.pl example/libxml.xml lib
-\t\@\$(TOUCH) Makefile.PL
+\t\@$^X -pi.old -e 's/a/a/' Makefile.PL
 \t\@echo "==> YOU MUST NOW RE-RUN $^X Makefile.PL <=="
 \t\@false
 
 the current version includes some securety fixes in dom.c and LibXML.xs
 
 also a better testsuite
+
+-- LibXML.xs_1.22
+
+completed function setAttributeNode
+added function getAttributes 
+added function getAttributesNS
+
+more node security fixes 
+
+these functions will return an array of attribute nodes.
+both will probably renamed before i make them public
+
+
+idea: global encoding constant, so all user input will be encoded from
+that encoding to utf8 INTERNALLY
+
+todo: add xmlEncodeEntitiesReentrant for all text content
+
+dom.h/dom.c
+
+introduced domSetAttributeNode
+cleaned the test suite
+
+LibXML.xs_1.23
+    + getOwner returns the Owner Node (root of the subtree)
+      of the current element 
+    + getOwnerDocument returns the Owner document of the node if any 
+    + proxy fixes
+    + introduced documentfragment
+      i will allways create a document fragment for EACH unbound node.
+      made the documentFragment a node 
+    + more securety checks and less memory leaks...
+    + better array handling
+    + DOM L2 conform naming (optional)
+    + entity encoding fixed
+
+dom.c_1.21
+   + domsetnodevalue is aware of attributes as well
+   + domreplacenode introduced
+   + added internal function insert_node_to_nodelist
+
+t/06nodetypes.t
+   + document_fragment tests 
+
+todo:
+    make shure appendChild or similar functions do not allow
+    wrong node type to be appended
+    make the node iterator function XS to avoid GC overhead 
+    for temporary iterator nodes.
     return doc;
 }
 
-/* this function is pretty neat, since you can read in well balanced 
+/**
+ * Name: domReadWellBalancedString
+ * Synopsis: xmlNodePtr domReadWellBalancedString( xmlDocPtr doc, xmlChar *string )
+ * @doc: the document, the string should belong to
+ * @string: the string to parse
+ *
+ * this function is pretty neat, since you can read in well balanced 
  * strings and get a list of nodes, which can be added to any other node.
+ * (shure - this should return a doucment_fragment, but still it doesn't)
  *
  * the code is pretty heavy i think, but deep in my heard i believe it's 
  * worth it :) (e.g. if you like to read a chunk of well-balanced code 
  * from a databasefield)
  *
- * in 99% i believe it is faster to create the dom by hand, and skip the 
- * parsing job which has to be done here.
- */
+ * in 99% the cases i believe it is faster than to create the dom by hand,
+ * and skip the parsing job which has to be done here.
+ **/
 xmlNodePtr 
 domReadWellBalancedString( xmlDocPtr doc, xmlChar* block ) {
   int retCode       = -1;
   return ret;
 }
 
+/** 
+ * internal helper: insert node to nodelist
+ * synopsis: xmlNodePtr insert_node_to_nodelist( leader, insertnode, followup );
+ * while leader and followup are allready list nodes. both may be NULL
+ * if leader is null the parents children will be reset
+ * if followup is null the parent last will be reset.
+ * leader and followup has to be followups in the nodelist!!!
+ * the function returns the node inserted. if a fragment was inserted,
+ * the first node of the list will returned
+ **/
+xmlNodePtr 
+insert_node_to_nodelist( xmlNodePtr lead, xmlNodePtr node, xmlNodePtr follow ){
+  xmlNodePtr cld1, cld2, par;
+  if( node == NULL ) {
+    return;
+  }
+
+  cld1 = node;
+  cld2 = node;
+  par = NULL;
+
+  if( lead != NULL ) {
+    par = lead->parent;
+  }
+  else if( follow != NULL ) {
+    par = follow->parent;
+  }
+
+  if( node->type == XML_DOCUMENT_FRAG_NODE ) {
+    xmlNodePtr hn = node->children;
+
+    cld1 = node->children;
+    cld2 = node->last;
+    node->last = node->children = NULL;
+
+    while ( hn ) {
+      hn->parent = par;
+      hn = hn->next;
+    }
+  }
+  
+
+  if( cld1 != NULL && cld2 != NULL && par != NULL ) {
+    cld1->parent = par;
+    cld2->parent = par;
+   
+    if ( lead == NULL ) {
+      par->children = cld1;
+    }
+    else {
+      if( lead->type == XML_TEXT_NODE && cld1->type == XML_TEXT_NODE ){
+        xmlChar * content = cld1->content;
+        cld1->content = xmlStrdup(lead->content);
+        xmlNodeAddContent(cld1, content);
+        cld1->prev  = lead->prev;
+        if ( lead->prev == NULL ) {
+          par->children = cld1;
+        }
+        else {
+          lead->prev->next = cld1;
+        }
+        lead->next = lead->prev = lead->parent = NULL;
+        /* we won't free any nodes here, since perl stil might use them */ 
+        /* xmlFreeNode( lead ); */
+      }
+      else {
+        lead->next = cld1;
+        cld1->prev  = lead;
+      }
+    }
+  
+    if ( follow == NULL ){
+      par->last = cld2;
+    } 
+    else {
+      if( follow->type == XML_TEXT_NODE && cld2->type == XML_TEXT_NODE ){
+        xmlNodeAddContent(cld2, follow->content);
+
+        cld2->next  = follow->prev;
+        if ( follow->prev == NULL ) {
+          par->last = cld2;
+        }
+        else {
+          follow->next->prev = cld2;
+        }
+        follow->next = follow->prev = follow->parent = NULL;
+        /* we won't free any nodes here, since perl stil might use them */ 
+        /* xmlFreeNode( follow ); */
+      }
+      else {
+        follow->prev = cld2;
+        cld2->next  = follow;
+      }
+    }
+  }
+
+  return cld1;
+}
+
 xmlNodePtr
 domUnbindNode( xmlNodePtr );
 
 xmlNodePtr
+domSetOwnerDocument( xmlNodePtr self, xmlDocPtr newDoc );
+
+xmlNodePtr
 domIsNotParentOf( xmlNodePtr node1, xmlNodePtr node2 );
 
 xmlNodePtr
  * If the node belongs to a namespace it returns the prefix and 
  * the local name. otherwise only the local name is returned.
  **/
-
-/* esther 0179-3929246; schlesische str 14; 10997 bln; estherman@gmx.de */
-
 const xmlChar*
 domName(xmlNodePtr node) {
   xmlChar *qname = NULL; 
   node->name = str;
 }
 
+/**
+ * Name: domAppendChild
+ * Synopsis: xmlNodePtr domAppendChild( xmlNodePtr par, xmlNodePtr newCld );
+ * @par: the node to append to
+ * @newCld: the node to append
+ *
+ * Returns newCld on success otherwise NULL
+ * The function will unbind newCld first if nesseccary. As well the 
+ * function will fail, if par or newCld is a Attribute Node OR if newCld 
+ * is a parent of par. 
+ * 
+ * If newCld belongs to a different DOM the node will be imported 
+ * implicit before it gets appended. 
+ **/
 xmlNodePtr
 domAppendChild( xmlNodePtr self,
                 xmlNodePtr newChild ){
-  /* unbind the new node if nessecary ...  */
+  /* unbinds the new node if nessecary ... does not handle attributes :P */
+  newChild = domIsNotParentOf( newChild, self );
 
-  newChild = domIsNotParentOf( newChild, self );
-  if ( newChild == NULL ){
-    return NULL;
-  }
   if ( self == NULL ) {
     return newChild;
   }
 
-
+  if ( newChild == NULL
+       || newChild->type == XML_ATTRIBUTE_NODE
+       || self->type == XML_ATTRIBUTE_NODE
+       || ( newChild->type == XML_DOCUMENT_FRAG_NODE 
+            && newChild->children == NULL ) 
+       ){
+    /* HIERARCHIY_REQUEST_ERR */
+    return NULL;
+  }
   if ( newChild->doc == self->doc ){
     newChild= domUnbindNode( newChild );
   }
   else {
+    /* WRONG_DOCUMENT_ERR - non conform implementation*/
     newChild= domImportNode( self->doc, newChild, 1 );
   }
-
-  /* fix the document if they are from different documents 
-   * actually this has to be done for ALL nodes in the subtree... 
-   **/
-  if ( self->doc != newChild->doc ) {
-    newChild->doc = self->doc;
-  }
   
   if ( self->children != NULL ) {
-    if ( newChild->type   == XML_TEXT_NODE && 
-	 self->last->type == XML_TEXT_NODE ) {
-      int len = xmlStrlen(newChild->content);
-      xmlNodeAddContentLen(self->last, newChild->content, len);
-      xmlFreeNode( newChild );
-      return self->last;
+    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;
     }
-    else {
-      self->last->next = newChild;
-      newChild->prev = self->last;
-      self->last = newChild;
-      newChild->parent= self;
-    }
+    cld->parent = self;
+    
+    newChild->children = NULL;
+    newChild->last = NULL;
+    cld = self->children;
   }
   else {
     self->children = newChild;
   return newChild;
 }
 
+
 xmlNodePtr
 domReplaceChild( xmlNodePtr self, xmlNodePtr new, xmlNodePtr old ) {
-  new = domIsNotParentOf( new, self );
+  if ( self== NULL ){
+    return NULL;
+  }
   if ( new == NULL ) {
     /* level2 sais nothing about this case :( */
     return domRemoveChild( self, old );
   }
 
-  if ( self== NULL ){
+  /* handle the different node types */
+  switch( new->type ) {
+  case XML_ATTRIBUTE_NODE:
+    return NULL;
+    break;
+  default:
+    break;
+  }
+
+  if( ( old != NULL 
+        && ( old->type == XML_ATTRIBUTE_NODE 
+             || old->type == XML_DOCUMENT_FRAG_NODE 
+             || old->parent != self ) )
+      || self->type== XML_ATTRIBUTE_NODE
+      || domIsNotParentOf( new, self ) == NULL 
+      || ( new->type == XML_DOCUMENT_FRAG_NODE && new->children == NULL ) ) { 
+
+    /* HIERARCHY_REQUEST_ERR */
     return NULL;
   }
 
   if ( new == old ) {
-    /* dom level 2 throw no exception if new and old are equal */ 
+    /* dom level 2 throws no exception if new and old are equal */ 
     return new;
   }
 
     domAppendChild( self, new );
     return old;
   }
-  if ( old->parent != self ) {
-    /* should not do this!!! */
-    return new;
-  }
 
   if ( new->doc == self->doc ) {
     new = domUnbindNode( new ) ;
   }
   else {
+    /* WRONG_DOCUMENT_ERR - non conform implementation */
     new = domImportNode( self->doc, new, 1 );
   }
-  new->parent = self;
   
-  /* this piece is quite important */
-  if ( new->doc != self->doc ) {
-    new->doc = self->doc;
+  if( old == self->children && old == self->last ) {
+    domRemoveChild( self, old );
+    domAppendChild( self, new );
+  }
+  else {
+    insert_node_to_nodelist( old->prev, new, old->next );
+    old->parent = NULL;
+    old->next   = NULL;
+    old->prev   = NULL;    
   }
 
-  if ( old->next != NULL ) 
-    old->next->prev = new;
-  if ( old->prev != NULL ) 
-    old->prev->next = new;
-  
-  new->next = old->next;
-  new->prev = old->prev;
-  
-  if ( old == self->children )
-    self->children = new;
-  if ( old == self->last )
-    self->last = new;
-  
-  old->parent = NULL;
-  old->next   = NULL;
-  old->prev   = NULL;
- 
   return old;
 }
 
 xmlNodePtr
 domRemoveChild( xmlNodePtr self, xmlNodePtr old ) {
-  if ( (self != NULL)  && (old!=NULL) && (self == old->parent ) ) {
-    domUnbindNode( old );
+  if ( (self != NULL)  
+       && (old!=NULL) 
+       && (self == old->parent )
+       && (old->type != XML_ATTRIBUTE_NODE) 
+       ) {
+    old = domUnbindNode( old );
   }
   return old ;
 }
                  xmlNodePtr newChild,
                  xmlNodePtr refChild ){
 
-  if ( self == NULL ) {
+  if ( self == NULL || newChild == NULL ) {
     return NULL;
   }
 
-  newChild = domIsNotParentOf( newChild, self );
+  if ( newChild != NULL && domIsNotParentOf( newChild, self ) == NULL ){
+    /* HIERARCHIY_REQUEST_ERR */
+    return NULL;
+  }
 
   if ( refChild == newChild ) {
     return newChild;
   }
-
-  if ( refChild == NULL && newChild != NULL ) {
-    /* insert newChild as first Child */
-    if ( self->children == NULL ) {
-      return domAppendChild( self, newChild );
-    }
-    
-    if ( self->doc == newChild->doc ){
-      newChild = domUnbindNode( newChild );
-    }
-    else {
-      newChild = domImportNode( self->doc, newChild, 1 );
-    }
-
-    newChild->next = self->children;
-    self->children->prev = newChild;
-   
-    self->children = newChild;
-
-    return newChild;
+  if( ( refChild != NULL 
+        && ( refChild->type == XML_ATTRIBUTE_NODE 
+             || refChild->type == XML_DOCUMENT_FRAG_NODE ) )
+      || ( newChild != NULL && ( newChild->type == XML_ATTRIBUTE_NODE
+                                 || ( newChild->type==XML_DOCUMENT_FRAG_NODE 
+                                      && newChild->children == NULL ) ) ) ) {
+    /* HIERARCHY_REQUEST_ERR */
+    /* this condition is true, because:
+     * case 1: if the reference is an attribute, it's not a child
+     * case 2: if the reference is a document_fragment, it's not part of the tree
+     * case 3: if the newchild is an attribute, it can't get inserted as a child
+     * case 4: if newchild is a document fragment and has no children, we can't
+     *         insert it
+     */
+    return NULL;
   }
 
-  if ( newChild != NULL && 
-       self == refChild->parent ) {
-    /* find the refchild, to avoid spoofed parents */
-    xmlNodePtr hn = self->children;
-    while ( hn ) {
-      if ( hn == refChild ) {
-        /* found refChild */
-        if ( self->doc == newChild->doc ){
-          newChild = domUnbindNode( newChild );
-        }
-        else {
-          newChild = domImportNode( self->doc, newChild, 1 );
-        }
 
-        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;
+  if ( self->doc == newChild->doc ){
+    newChild = domUnbindNode( newChild );
+  }
+  else {
+    newChild = domImportNode( self->doc, newChild, 1 );
+  }
+
+  if ( refChild == NULL ) {
+    if( self->children == NULL ){
+      newChild = domAppendChild( self, newChild );
+    } 
+    else {
+      newChild = insert_node_to_nodelist( NULL, newChild, self->children );
     }
   }
-  return NULL;
+
+  if ( self == refChild->parent ) {
+    newChild = insert_node_to_nodelist( refChild->prev, newChild, refChild );
+  }
+  else {
+    newChild = NULL;
+  }
+
+  return newChild;
 }
 
 xmlNodePtr
   if ( self == NULL ) {
     return NULL;
   }
-
+  
   newChild = domIsNotParentOf( newChild, self );
 
   if ( refChild == newChild ) {
     return domAppendChild( self, newChild );
   }
 
+  if( refChild->type == XML_ATTRIBUTE_NODE 
+      || refChild->type == XML_DOCUMENT_FRAG_NODE
+      || ( newChild != NULL && ( newChild->type == XML_ATTRIBUTE_NODE
+                                 || ( newChild->type==XML_DOCUMENT_FRAG_NODE 
+                                      && newChild->children == NULL ) ) ) ) {
+    /* HIERARCHY_REQUEST_ERR */
+    return NULL;
+  }
+
+
   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 */
-        if ( self->doc == newChild->doc ) {
-          newChild = domUnbindNode( newChild );
-        }
-        else {
-          newChild = domImportNode( self->doc , newChild, 1 );
-        }
 
-        newChild->parent = self;
-        newChild->prev = refChild;
-        newChild->next = refChild->next;
-        if ( refChild->next != NULL ) {
-          refChild->next->prev = newChild;
-        }
-        refChild->next = newChild;
+    if( newChild->doc == self->doc ) {
+      domUnbindNode( newChild );
+    }
+    else {
+      domImportNode( self->doc, newChild, 1 );
+    }
 
-        if ( refChild == self->last ) {
-          self->last = newChild;
-        }
-        return newChild;
+    newChild = insert_node_to_nodelist( refChild, newChild, refChild->next );
+  }
+  else {
+    newChild = NULL;
+  }
+  return newChild;
+}
+
+xmlNodePtr
+domReplaceNode( xmlNodePtr oldnode, xmlNodePtr newnode ){
+  xmlNodePtr prev, next, par;
+  if ( oldnode != NULL ) {
+    if( newnode == NULL ) {
+      domUnbindNode( oldnode );
+    }
+    else {
+      par  = oldnode->parent;
+      prev = oldnode->prev;
+      next = oldnode->next;
+      domUnbindNode( oldnode );
+      if( prev == NULL && next == NULL ) {
+        domAppendChild( par ,newnode ); 
       }
-      hn = hn->next;
+      else {
+        insert_node_to_nodelist( prev, newnode, next );
+      }
     }
   }
-  return NULL;
+  return oldnode;
 }
 
 void
 domSetNodeValue( xmlNodePtr n , xmlChar* val ){
+  char* ctnt = NULL; 
+
   if ( n == NULL ) 
     return;
 
-  if( n->content != NULL ) {
+  ctnt = xmlEncodeEntitiesReentrant( n->doc , val );
+  
+  if( n->type == XML_ATTRIBUTE_NODE ){
+    if ( n->children != NULL ) {
+      n->last = NULL;
+      xmlFreeNodeList( n->children );
+    }
+    n->children = xmlNewText( ctnt );
+    n->children->parent = n;
+    n->children->doc = n->doc;
+    n->last = n->children; 
+  }
+  else if( n->content != NULL ) {
     /* free old content */
     xmlFree( n->content );
+    n->content = xmlStrdup(ctnt);
   }
-
-  n->content = xmlStrdup( val );
 }
 
 
     case XML_DOCUMENT_NODE:
       name = "XML::LibXML::Document";
       break;
+    case XML_DOCUMENT_FRAG_NODE:
+      name = "XML::LibXML::DocumentFragment";
+      break;
     default:
       name = "XML::LibXML::Node";
       break;
  **/
 xmlNodePtr
 domSetDocumentElement( xmlDocPtr doc, xmlNodePtr newRoot ) { 
-  return domReplaceChild( (xmlNodePtr)doc->doc, 
+  return domReplaceChild( (xmlNodePtr)doc, 
 			  newRoot, 
 			  domDocumentElement( doc )) ;
 }
 
-
-xmlNodePtr
-domSetOwnerDocument( xmlNodePtr self, xmlDocPtr newDoc );
-
 xmlNodePtr
 domImportNode( xmlDocPtr doc, xmlNodePtr node, int move ) {
   xmlNodePtr return_node = node;
 		  xmlNodePtr newParent );
 xmlNodePtr
 domUnbindNode(  xmlNodePtr self );
-
 const char*
 domNodeTypeName( xmlNodePtr self );
+xmlNodePtr
+domReplaceNode( xmlNodePtr old, xmlNodePtr new );
 
 xmlNodePtr
 domIsNotParentOf( xmlNodePtr testNode, xmlNodePtr refNode );

example/libxml.xml

 	just one root element to contain the documents data.
 </method>
 
+<method name="doumentElement" 
+    synopsis="$root = $dom->documentElement;">
+    Alias for <b>getDocumentElement</b>.
+</method>
+
 <method name="setDocumentElement" 
 	synopsis="$dom->setDocumentElement( $root );"> 
 	This function enables you to set the root element for a
 
 <method name="createAttribute"
      synopsis="$attrnode = $doc->createAttribute($name [,$value]);">
-     Creates a new Attribute node. This function is rather useless at
-     the moment, since there is no setAttributeNode function defined
-     in <i>XML::LibXML::Element</i>, yet. 
+     Creates a new Attribute node. 
+</method>
+
+<method name="createDocumentFragment"
+    synopsis="$fragment = $doc->createDocumentFragment()">
+    This function creates a DocumentFragment. 
 </method>
 
 <method name="createAttributeNS"
   <item name="XML::LibXML::Text"/>
   <item name="XML::LibXML::Attr"/>
   <item name="XML::LibXML::Comment"/>
+  <item name="XML::LibXML::DocumentFragment"/>
 </also>
-<version>0.90_a</version>
+<version>0.95</version>
 </class>
 
 <class name="XML::LibXML::Node">
 	(<i>prefix:localname</i>)
 </method>
 
+<method name="nodeName"
+    synopsis="$name = $node->nodeName;">
+    Alias for <b>getName()</b>.
+</method>
+
 <method name="setName"
     synopsis="$node->setName( $newName );"> 
     In very limited situation it is usefull to change a nodes name. In
 	node</i>) it can get requested through this function.
 </method>
 
+<method name="nodeValue" synopsis="$content = $node->nodeValue;">
+    Alias for <b>getData</b>
+</method>
+
 <method name="getType" 
 	synopsis="$type = $node->getType();">
 	Retrun the node's type. The possible types are described in
     of perl ref function.
 </method>
 
+<method name="nodeType"
+    synopsis="$type = $node->nodeType;">
+    Alias for <b>getType</b>.
+</method>
+
 <method name="unbindNode" 
 	synopsis="$node->unbindNode()">
 	Unbinds the Node from its siblings and Parent, but not from the
 <method name="replaceChild" 
 	synopsis="$oldnode = $node->replaceChild( $newNode, $oldNode )">
 	Replaces the <i>$oldNode</i> with the <i>$newNode</i>. The
-	<i>$oldNode</i>	will be unbound from the Node
+	<i>$oldNode</i>	will be unbound from the Node. This function 
+    differs from the DOM L2 specification, in the case, if the new
+    node is not part of the document, the node will be imported 
+    first.
 </method>
 
 <method name="appendChild"
 	synopsis="$childnode = $node->appendChild( $childnode )">
 	The function will add the <i>$childnode</i> to the end of
 	<i>$node</i>'s children. The function should fail, if the new
-	childnode is allready a child of <i>$node</i>
+	childnode is allready a child of <i>$node</i>. This function 
+    differs from the DOM L2 specification, in the case, if the new
+    node is not part of the document, the node will be imported 
+    first.
 </method>
 
 <method name="cloneNode" 
 	well. If $deep is 0 only the current node will be copied.
 </method>
 
-<method name="getParentNode" synopsis="$parentnode = $node->getParentNode()">
+<method name="getParentNode" synopsis="$parentnode = $node->getParentNode();">
 	Returns simply the Parent Node of the current node. 
- 
- 	If this function is called on the root element, the document
- 	will be returned as a LibXML::Node element. So be carefull :-)
+</method>
+
+<method name="parentNode" synopsis="$parentnode = $node->parentNode;">
+   Alias for <b>getParentNode()</b>
 </method>
 
 <method name="getNextSibling" 
 	Returns the next sibling if any .
 </method>
 
+<method name="nextSibling" 	synopsis="$nextnode = $node->nextSibling()">
+   Alias for <b>getNextSibling()</b>
+</method>
+
 <method name="getPreviousSibling" 
 	synopsis="$nextnode = $node->getPreviousSibling()">
 	Analogous to <b>getNextSibling</b> the function returns the previous
 	sibling if any.
 </method>
 
+<method name="previousSibling" 	synopsis="$prevnode = $node->previousSibling()">
+   Alias for <b>getPreviousSibling()</b>
+</method>
+
 <method name="hasChildNodes"
     synopsis="$boolean = $node->hasChildNodes();"> 
     If the current node has Childnodes this function returns TRUE (1),
 	node in the childlist. 
 </method>
 
+<method name="firstChild" 	synopsis="$childnode = $node->firstChild;">
+   Alias for <b>getFirstChild()</b>
+</method>
+
+
 <method name="getLastChild" synopsis="$childnode = $node->getLastChild()">
 	If the <i>$node</i> has childnodes this function returns the
 	last child node. 
 </method>
 
+<method name="lastChild" synopsis="$childnode = $node->lastChild;">
+   Alias for <b>getLastChild()</b>
+</method>
+
 <method name="getOwnerDocument" synopsis="$dom = $node->getOwnerDocument()">
 	Through this function it is allway possible to access the
 	document the current node is bound to.
 </method>
 
+
+<method name="ownerDocument" synopsis="$documentnode = $node->ownerDocument;">
+   Alias for <b>getOwnerDocument()</b>
+</method>
+
+<method name="getOwner" synopsis="$node = $node->getOwner;">
+   This function returns the node the current node is associated
+   with. In the very most cases this will be a document node or a
+   document fragment node.
+</method>
+
 <method name="setOwnerDocument" 
     synopsis="$node->setOwnerDocument( $dom );">
 	This function binds a node to another DOM. This method unbinds the
 </method>
 
 <method name="insertBefore" 
-    synopsis="$node->insertBefore( $newNode, $refNode )">
+    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.
+    first child of the parent node.  This function differs from the
+    DOM L2 specification, in the case, if the new node is not part of
+    the document, the node will be imported first.
 </method>
 
 <method name="insertAfter" synopsis="$node->insertAfter( $newNode, $refNode )">
 <method name="getChildnodes" synopsis="@children = $node->getChildnodes();">
 	<b>getChildnodes</b> implements a more intuitive interface to the
 	childnodes of the current node. It enables you to pass all
-	children directly to a <i>map</i> or <i>grep</i>.
+	children directly to a <i>map</i> or <i>grep</i>. If this function is 
+    called in scalar context, the number of childnodes will be returned.
+</method>
+
+<method name="childNodes" synopsis="@childnodes = $node->childNodes;">
+   Alias for <b>getChildnodes()</b>
 </method>
 
 <method name="toString" synopsis="$xmlstring = $node->toString();">
     Returns the local name of a tag. This is the part behind the colon.
 </method>
 
+<method name="localname" synopsis="$localname = $node->localname;">
+   Alias for <b>getLocalName()</b>
+</method>
+
 <method name="getPrefix" 
     synopsis="$name = $node->getPrefix();">
     Returns the prefix of a tag. This is the part before the colon.
 </method>
 
+<method name="prefix" synopsis="$nameprefix = $node->prefix;">
+   Alias for <b>getPrefix()</b>
+</method>
+
 <method name="getNamespaceURI" synopsis="$uri = $node->getNamespaceURI()">
     returns the URI of the current namespace.
 </method>
+
+
+<method name="hasAttributes" synopsis="$boolean = $node->hasAttributes();">
+   returns 1 (TRUE) if the current node has any attributes set, otherwise
+   0 (FALSE) is returned.
+</method>
+
+
+<method name="getAttributes" synopsis="@attributelist = $node->getAttributes;">
+   returns all attribute nodes of the current node. 
+</method>
+
+<method name="attributes" synopsis="@attributelist = $node->attributes;">
+   Alias for <b>getAttributes()</b>
+</method>
+
+
+<method name="getAttributesNS" 
+    synopsis="@attributelist = $node->attributesNS( $URI );">
+   returns all attributes for the given namespace.
+</method>
+
+
+<method name="iterator" synopsis="$node->iterator( \&amp;nodehandler );">
+   This is little helper function, that lets one define a function, that
+   will be processed on the current node and all its children. The function
+   will recieve as its only parameter the node to proceed. The function uses
+   inorder proceeding to traverse the subtree. Therefore you can't reach the 
+   childnodes anymore, if the nodehandler removes childnodes. 
+
+<example>
+   $node->iterator( sub { print $_[0]->nodeName(), "\n"; } );    
+</example>
+
+   The example will print all node names in the current subtree.
+
+   The <b>iterator</b> function will return the return value of the
+   nodehandler while processing the last child of the current node.
+</method>
+
 </description>
 <also>
   <item name="XML::LibXML"/>
   <item name="XML::LibXML::Text"/>
   <item name="XML::LibXML::Comment"/>
   <item name="XML::LibXML::Attr"/>
+  <item name="XML::LibXML::DocumentFragment"/>
 </also>
-<version>0.93</version>
+<version>0.95</version>
 </class>