Commits

Anonymous committed 42f0be6

Modified Files:
LibXML.pm
+ iterator function

LibXML.xs dom.c dom.h
+ fixed namespace functions (originally by steve tinney)
+ XML::LibXML::Attr
+ new
+ getValue
+ setValue
+ getOwnerElement
+ createAttribute in XML::LibXML::Document
+ encoding in domSetNodeValue (e.g. in text nodes)

example/libxml.xml
+ some docu for namespaces and attribute nodes

t/06nodetypes.t
+ attribute tests

t/08findnodes.t
+ iterator test

  • Participants
  • Parent commits d947fec

Comments (0)

Files changed (7)

 bootstrap XML::LibXML $VERSION;
 
 @EXPORT = qw( XML_ELEMENT_NODE 
-	      XML_ATTRIBUTE_NODE
-	      XML_TEXT_NODE
-	      XML_CDATA_SECTION_NODE
-	      XML_ENTITY_REF_NODE
-	      XML_ENTITY_NODE
-	      XML_PI_NODE
-	      XML_COMMENT_NODE
-	      XML_DOCUMENT_NODE
-	      XML_DOCUMENT_TYPE_NODE
-	      XML_DOCUMENT_FRAG_NODE
-	      XML_NOTATION_NODE
-	      XML_HTML_DOCUMENT_NODE
-	      XML_DTD_NODE
-	      XML_ELEMENT_DECL
-	      XML_ATTRIBUTE_DECL
-	      XML_ENTITY_DECL
-	      XML_NAMESPACE_DECL
-	      XML_XINCLUDE_START
-	      XML_XINCLUDE_END );
+              XML_ATTRIBUTE_NODE
+              XML_TEXT_NODE
+              XML_CDATA_SECTION_NODE
+              XML_ENTITY_REF_NODE
+              XML_ENTITY_NODE
+              XML_PI_NODE
+              XML_COMMENT_NODE
+              XML_DOCUMENT_NODE
+              XML_DOCUMENT_TYPE_NODE
+              XML_DOCUMENT_FRAG_NODE
+              XML_NOTATION_NODE
+              XML_HTML_DOCUMENT_NODE
+              XML_DTD_NODE
+              XML_ELEMENT_DECL
+              XML_ATTRIBUTE_DECL
+              XML_ENTITY_DECL
+              XML_NAMESPACE_DECL
+              XML_XINCLUDE_START
+              XML_XINCLUDE_END );
 
 
 sub new {
 @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::NoGCDocument::ISA = 'XML::LibXML::Document';
+@XML::LibXML::Attr::ISA         = 'XML::LibXML::Node';
 
 sub XML::LibXML::NoGCDocument::DESTROY () { }
 
+sub XML::LibXML::Node::iterator {
+    my $self = shift;
+    my $funcref = shift;
+    my $child = undef;
+
+    my $rv = $funcref->( $self );
+    $child = $self->getFirstChild();
+    while ( $child ) {
+        $rv = $child->iterator( $funcref );
+        $child = $child->getNextSibling();
+    }
+    return $rv;
+}
+
 1;
 __END__
 
 #include <libxml/debugXML.h>
 #include <libxml/xmlerror.h>
 #include <libxml/xinclude.h>
+#include <libxml/valid.h>
 
 #include "dom.h"
 #include "xpath.h"
             xmlDocDumpMemory(self, &result, &len);
         }
         else {
+            int t_indent_var = xmlIndentTreeOutput;
+            xmlIndentTreeOutput = 1;
             xmlDocDumpFormatMemory( self, &result, &len, format ); 
+            xmlIndentTreeOutput = t_indent_var;
         }
     	if (result == NULL) {
 	        croak("Failed to convert doc to string");
             RETVAL = newSVpvn((char *)result, (STRLEN)len);
 	        xmlFree(result);
 	    }
+        xmlReconciliateNs(self,xmlDocGetRootElement(self));
     OUTPUT:
         RETVAL
 
         RETVAL
 
 ProxyObject *
+createElementNS( dom, nsURI, qname)
+         SV * dom
+         char *nsURI
+         char* qname 
+     PREINIT:
+         char * CLASS = "XML::LibXML::Element";
+         xmlNodePtr newNode;
+         xmlChar *prefix;
+         xmlChar *lname;
+         xmlNsPtr ns;
+     CODE:
+         lname = xmlSplitQName2(qname, &prefix);
+         ns = domNewNs (0 , prefix , nsURI);
+         newNode = xmlNewNode( ns , lname );
+         newNode->doc = (xmlDocPtr)SvIV((SV*)SvRV(dom));
+         RETVAL = make_proxy_node(newNode);
+         RETVAL->extra = dom;
+         SvREFCNT_inc(dom);
+     OUTPUT:
+         RETVAL
+
+ProxyObject *
 createTextNode( dom, content )
         SV * dom
         char * content
     OUTPUT:
         RETVAL
 
+ProxyObject *
+createAttribute( dom, name , value="" )
+        SV * dom
+        char * name
+        char * value
+    PREINIT:
+        const char* CLASS = "XML::LibXML::Attr";
+        xmlNodePtr newNode;
+    CODE:
+        newNode = (xmlNodePtr)xmlNewProp(NULL, name , value );
+        newNode->doc = (xmlDocPtr)SvIV((SV*)SvRV(dom));
+        if ( newNode->children!=NULL ) {
+            newNode->children->doc = (xmlDocPtr)SvIV((SV*)SvRV(dom));
+        }
+        RETVAL = make_proxy_node(newNode);
+        RETVAL->extra = dom;
+        SvREFCNT_inc(dom);    
+    OUTPUT:
+        RETVAL
+
 void 
 setDocumentElement( dom , proxy )
         SV * dom
     OUTPUT:
         RETVAL
 
+SV*
+getLocalName( node )
+        xmlNodePtr node
+    PREINIT:
+        const char * lname;
+    CODE:
+        if( node != NULL ) {
+            lname =  node->name;
+        }
+        RETVAL = newSVpvn( (char *)lname, xmlStrlen( lname ) );
+    OUTPUT:
+        RETVAL
+
+SV*
+getPrefix( node )
+        xmlNodePtr node
+    PREINIT:
+        const char * prefix;
+    CODE:
+        if( node != NULL 
+            && node->ns != NULL
+            && node->ns->prefix != NULL ) {
+            prefix =  node->ns->prefix;
+            RETVAL = newSVpvn( (char *)prefix, xmlStrlen( prefix ) );
+        } else {
+            RETVAL = NULL;
+        }
+    OUTPUT:
+        RETVAL
+
+SV*
+getNamespaceURI( node )
+        xmlNodePtr node
+    PREINIT:
+        const char * nsURI;
+    CODE:
+        if( node != NULL
+            && node->ns != NULL
+            && node->ns->href != NULL ) {
+            nsURI =  node->ns->href;
+            RETVAL = newSVpvn( (char *)nsURI, xmlStrlen( nsURI ) );
+        } else {
+            RETVAL = NULL;
+        }
+    OUTPUT:
+        RETVAL
 
 MODULE = XML::LibXML         PACKAGE = XML::LibXML::Element
 
     CODE:
         xmlSetProp( elem, name, value );
 
+void
+setAttributeNS( elem, nsURI, qname, value )
+        xmlNodePtr elem
+        char * nsURI
+        char * qname
+        char * value
+    PREINIT:
+        xmlNsPtr ns;
+        xmlChar *prefix;
+        xmlChar *lname;
+    CODE:
+        lname = xmlSplitQName2(qname, &prefix);
+        ns = domNewNs (elem , prefix , nsURI);
+        xmlSetNsProp( elem, ns, lname, value );
+
+ProxyObject *
+setAttributeNode( elem, attrnode ) 
+        xmlNodePtr elem
+        xmlNodePtr attrnode 
+    PREINIT:
+        const char * CLASS = "XML::LibXML::Attr";
+    CODE:
+    OUTPUT:
+        RETVAL
+
 int 
 hasAttribute( elem, name ) 
         xmlNodePtr elem
     OUTPUT:
         RETVAL
 
+int 
+hasAttributeNS( elem, nsURI, name ) 
+        xmlNodePtr elem
+        char * nsURI
+        char * name
+    PREINIT:
+        xmlAttrPtr att;
+    CODE:
+        /**
+         * domHasNsProp() returns the attribute node, which is not exactly what 
+         * we want as a boolean value 
+         **/
+        att = domHasNsProp( elem, name, nsURI );
+        RETVAL = att == NULL ? 0 : 1 ;
+    OUTPUT:
+        RETVAL
+
 SV*
 getAttribute( elem, name ) 
         xmlNodePtr elem
             RETVAL  = newSVpvn( content, xmlStrlen( content ) );
         }
         else {
-            RETVAL = NULL;
+            RETVAL = &PL_sv_undef;
+        }
+    OUTPUT:
+        RETVAL
+
+SV*
+getAttributeNS( elem, nsURI ,name ) 
+        xmlNodePtr elem
+        char * nsURI
+        char * name 
+    PREINIT:
+        xmlAttrPtr att;
+	    char * content;
+    CODE:
+        att = domHasNsProp( elem, name, nsURI );
+        if ( att != NULL && att->children != NULL ) {
+            content = att->children->content;
+        }
+        if ( content != NULL ) {
+            RETVAL  = newSVpvn( content, xmlStrlen( content ) );
+        }
+        else {
+            RETVAL = &PL_sv_undef;
+        }
+    OUTPUT:
+        RETVAL
+
+
+ProxyObject *
+getAttributeNode( elemobj, name )
+        ProxyObject* elemobj 
+        char * name
+    PREINIT:
+        const char * CLASS = "XML::LibXML::Attr";
+        xmlNodePtr elem = (xmlNodePtr) elemobj->object;
+        xmlAttrPtr attrnode;
+    CODE:
+        attrnode = xmlHasProp( elem, name );
+        if ( attrnode != NULL ) {
+            RETVAL = make_proxy_node((xmlNodePtr)attrnode);
+            RETVAL->extra = elemobj->extra;
+            SvREFCNT_inc(elemobj->extra);
         }
     OUTPUT:
         RETVAL
     CODE:
         xmlRemoveProp( xmlHasProp( elem, name ) );	
 
+void
+removeAttributeNS( elem, nsURI, name )
+        xmlNodePtr elem
+        char * nsURI
+        char * name
+    PREINIT:
+        xmlChar *prefix;
+        xmlChar *lname;
+        xmlNsPtr ns;
+    CODE:
+        lname = xmlSplitQName2(name, &prefix);
+        if (lname == NULL) /* as it is supposed to be */
+            lname = name;
+        /* ignore the given prefix if any, and use whatever
+           is defined in scope for this nsURI */
+        ns = xmlSearchNsByHref(elem->doc, elem, nsURI);
+        xmlUnsetNsProp( elem, ns, lname );
+
 SV*
 getElementsByTagName( elem, name )
         xmlNodePtr elem
         }
         XSRETURN(len);
 
+SV*
+getElementsByTagNameNS( node, nsURI, name )
+        xmlNodePtr node
+        char * nsURI
+        char * name 
+    PREINIT:
+        xmlNodeSetPtr nodelist;
+        SV * element;
+        int len;
+    PPCODE:
+        len = 0;
+        nodelist = domGetElementsByTagNameNS( node , nsURI , name );
+        if ( nodelist && nodelist->nodeNr > 0 ) {
+            int i = 0 ;
+            const char * cls = "XML::LibXML::Node";
+            xmlNodePtr tnode;
+            ProxyObject * proxy;
+
+            len = nodelist->nodeNr;
+         
+            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();
+                
+                proxy = make_proxy_node(tnode);
+
+                cls = domNodeTypeName( tnode );
+                XPUSHs( sv_setref_pv( element, (char *)cls, (void*)proxy ) );
+            }
+ 
+            xmlXPathFreeNodeSet( nodelist );
+        }
+        XSRETURN(len);
+
+
 void
 appendWellBalancedChunk( self, chunk )
         xmlNodePtr self
     OUTPUT:
         RETVAL
 
+MODULE = XML::LibXML         PACKAGE = XML::LibXML::Attr
+
+ProxyObject *
+new( CLASS , name="", value="" )
+        char * CLASS
+        char * name
+        char * value
+    PREINIT:
+        xmlNodePtr attr;
+    CODE:
+        attr = (xmlNodePtr)xmlNewProp( NULL, name, value );
+        if ( attr ) {
+            RETVAL = make_proxy_node( attr );
+        }
+    OUTPUT:
+        RETVAL
+
+SV*
+getValue( attr )
+        xmlNodePtr attr;
+    PREINIT:
+        xmlBufferPtr buffer;
+        xmlNodePtr doc;
+    CODE:
+        if ( attr != NULL && attr->children != NULL ) {
+            if ( attr->doc == NULL ) {
+                RETVAL = newSVpvn( attr->children->content, 
+                                   xmlStrlen( attr->children->content )  );
+            }
+            else {
+                # we have to decode the string!
+                xmlBufferPtr in  = xmlBufferCreate();
+                xmlBufferPtr out = xmlBufferCreate();                
+                xmlCharEncodingHandlerPtr handler;
+                int len = -1;
+                handler = xmlGetCharEncodingHandler( xmlParseCharEncoding(attr->doc->encoding) );
+                if( handler != NULL ) {
+                    xmlBufferCat( in, attr->children->content ) ;
+                
+                    xmlCharEncOutFunc( handler, out, NULL );
+                    len = xmlCharEncOutFunc( handler, out, in );
+                    if ( len >= 0 ) {
+                        RETVAL =  newSVpvn( out->content, 
+                                        out->use );
+                    }
+                    else {
+                        RETVAL = &PL_sv_undef;
+                    }                
+                }
+                else {
+                    croak("handler error" );
+                }
+            }
+        }
+    OUTPUT:
+        RETVAL
+
+void
+setValue( attr, value )
+        xmlNodePtr attr 
+        char * value
+    CODE:
+        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" );
+            }
+        }
+
+ProxyObject *
+getOwnerElement( attrnode ) 
+        ProxyObject * attrnode 
+    PREINIT:
+        const char * CLASS = "XML::LibXML::Node";
+        xmlNodePtr attr;
+        xmlNodePtr parent;
+    CODE:
+        attr   = (xmlNodePtr) attrnode->object;
+        parent = attr->parent;
+        if ( parent ) {
+            CLASS  = domNodeTypeName( parent );
+            RETVAL = make_proxy_node(parent);
+            if ( attrnode->extra != NULL ) {
+                RETVAL->extra = attrnode->extra;
+                SvREFCNT_inc(attrnode->extra); 
+            }
+        }
+    OUTPUT:
+        RETVAL
 
 void
 domSetNodeValue( xmlNodePtr n , xmlChar* val ){
+  xmlDocPtr doc = n->doc;
+  
   if ( n == NULL ) 
     return;
   if( n->content != NULL ) {
     xmlFree( n->content );
   }
-  n->content = xmlStrdup( val );
+
+  if ( doc != NULL ){
+    xmlCharEncodingHandlerPtr handler = xmlGetCharEncodingHandler( xmlParseCharEncoding(doc->encoding) );
+
+    if ( handler != NULL ){
+       xmlBufferPtr in  = xmlBufferCreate();
+       xmlBufferPtr out = xmlBufferCreate();   
+       int len=-1;
+
+       xmlBufferCat( in, val );
+       len = xmlCharEncInFunc( handler, out, in );
+
+       if ( len >= 0 ) {
+         n->content = xmlStrdup( out->content );
+       }
+       else {
+         printf( "\nencoding error %d \n", len );
+         n->content = xmlStrdup( "" );
+       }
+    }
+    else {
+      n->content = xmlStrdup( "" );
+    }
+  }
+  else {    
+    n->content = xmlStrdup( val );
+  }
 }
 
 
     case XML_CDATA_SECTION_NODE:
       name = "XML::LibXML::CDATASection";
       break;
+    case XML_ATTRIBUTE_NODE:
+      name = "XML::LibXML::Attr"; 
+      break;
     default:
       name = "XML::LibXML::Node";
       break;
 
   if ( n != NULL && name != NULL ) {
     cld = n->children;
-    while ( cld ) {
+    while ( cld != NULL ) {
       if ( xmlStrcmp( name, cld->name ) == 0 ){
         if ( rv == NULL ) {
           rv = xmlXPathNodeSetCreate( cld ) ;
   return rv;
 }
 
+
+xmlNodeSetPtr
+domGetElementsByTagNameNS( xmlNodePtr n, xmlChar* nsURI, xmlChar* name ){
+  xmlNodeSetPtr rv = NULL;
+
+  if ( nsURI == NULL ) {
+    return domGetElementsByTagName( n, name );
+  }
+  
+  if ( n != NULL && name != NULL  ) {
+    xmlNodePtr cld = n->children;
+    while ( cld != NULL ) {
+      if ( xmlStrcmp( name, cld->name ) == 0 
+           && cld->ns != NULL
+           && xmlStrcmp( nsURI, cld->ns->href ) == 0  ){
+        if ( rv == NULL ) {
+          rv = xmlXPathNodeSetCreate( cld ) ;
+        }
+        else {
+          xmlXPathNodeSetAdd( rv, cld );
+        }
+      }
+      cld = cld->next;
+    }
+  }
+  
+  return rv;
+}
+
 xmlNodePtr
 domSetOwnerDocument( xmlNodePtr self, xmlDocPtr newDoc ) {
     if ( newDoc == NULL ) {
 
     return self;
 }
+
+xmlNsPtr
+domNewNs ( xmlNodePtr elem , xmlChar *prefix, xmlChar *href ) {
+  xmlNsPtr ns = NULL;
+  
+  if (elem != NULL) {
+    ns = xmlSearchNs( elem->doc, elem, prefix );
+  }
+  /* prefix is not in use */
+  if (ns == NULL) {
+    ns = xmlNewNs( elem , href , prefix );
+  } else {
+    /* prefix is in use; if it has same URI, let it go, otherwise it's
+       an error */
+    if (!xmlStrEqual(href, ns->href)) {
+      ns = NULL;
+    }
+  }
+  return ns;
+}
+
+/* This routine may or may not make it into libxml2; Matt wanted it in
+   here to be nice to those with older libxml2 installations.
+   This instance is renamed from xmlHasNsProp to domHasNsProp. */
+/**
+ * xmlHasNsProp:
+ * @node:  the node
+ * @name:  the attribute name
+ * @namespace:  the URI of the namespace
+ *
+ * Search for an attribute associated to a node
+ * This attribute has to be anchored in the namespace specified.
+ * This does the entity substitution.
+ * This function looks in DTD attribute declaration for #FIXED or
+ * default declaration values unless DTD use has been turned off.
+ *
+ * Returns the attribute or the attribute declaration or NULL
+ *     if neither was found.
+ */
+xmlAttrPtr
+domHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
+  xmlAttrPtr prop;
+  xmlDocPtr doc;
+  xmlNsPtr ns;
+  
+  if (node == NULL)
+ 	return(NULL);
+  
+  prop = node->properties;
+  if (namespace == NULL)
+    return(xmlHasProp(node, name));
+  while (prop != NULL) {
+    /*
+     * One need to have
+     *   - same attribute names
+     *   - and the attribute carrying that namespace
+ 	 *         or
+     
+     SJT: This following condition is wrong IMHO; I reported it as a bug on libxml2
+     
+	 *         no namespace on the attribute and the element carrying it
+	 */
+    if ((xmlStrEqual(prop->name, name)) &&
+        (/* ((prop->ns == NULL) && (node->ns != NULL) &&
+            (xmlStrEqual(node->ns->href, namespace))) || */
+         ((prop->ns != NULL) &&
+          (xmlStrEqual(prop->ns->href, namespace))))) {
+      return(prop);
+    }
+    prop = prop->next;
+  }
+  
+#if 0
+  /* xmlCheckDTD is static in libxml/tree.c; it is set there to 1
+     and never changed, so commenting this out doesn't change the
+     behaviour */
+  if (!xmlCheckDTD) return(NULL);
+#endif
+  
+  /*
+   * Check if there is a default declaration in the internal
+   * or external subsets
+   */
+  doc =  node->doc;
+  if (doc != NULL) {
+    if (doc->intSubset != NULL) {
+      xmlAttributePtr attrDecl;
+      
+      attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
+      if ((attrDecl == NULL) && (doc->extSubset != NULL))
+        attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
+      
+      if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
+        /*
+         * The DTD declaration only allows a prefix search
+         */
+        ns = xmlSearchNs(doc, node, attrDecl->prefix);
+        if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
+          return((xmlAttrPtr) attrDecl);
+      }
+    }
+  }
+  return(NULL);
+}
 xmlNodeSetPtr
 domGetElementsByTagName( xmlNodePtr self, xmlChar* name );
 
+xmlNodeSetPtr
+domGetElementsByTagNameNS( xmlNodePtr self, xmlChar* nsURI, xmlChar* name );
+
 xmlNodePtr
 domSetOwnerDocument( xmlNodePtr self, xmlDocPtr doc );
 
+xmlNsPtr
+domNewNs ( xmlNodePtr elem , xmlChar *prefix, xmlChar *href );
+
+xmlAttrPtr
+domHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace);
 #endif

File example/libxml.xml

 	the name <i>$nodename</i>.
 </method>
 
+<method name="createElementNS" 
+	synopsis="$element = $dom->createElement( $nsURI, $nodename );">
+    Namespace version of <i>createElement</i>
+</method>
+
 <method name="createTextNode" 
 	synopsis="$text = $dom->createTextNode( $content_text );">
 	As an equivalent of <b>createElement</b>, but it creates a
 	<b>Comment Node</b> bound to the DOM.
 </method>
 
+<method name="createAttribute"
+     synopsis="$doc->createAttribute($name [,$value]);">
+     Creates a new Attribute node.  
+</method>
+
 <method name="createCDATASection" synopsis="$cdata = $dom->create( $cdata_content );">
 	Similar to createTextNode and createComment, this function creates a CDataSection 
 	bound to the current DOM.
 </method>
 
+<method name="importNode"
+    synopsis="$document->importNode( $node [, $move] );">
+
+    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. 
+    (<i>$node->cloneNode(1)</i> will get called implicitly). 
+
+    Sometimes it is nessecary to <i>move</i> a node between
+    documents. In such a case the node will not be copied, but removed
+    from the original document.
+</method>
+
 </description>
 <also>
   <item name="XML::LibXML"/>
   <item name="XML::LibXML::Element"/>
   <item name="XML::LibXML::Text"/>
+  <item name="XML::LibXML::Attr"/>
   <item name="XML::LibXML::Comment"/>
 </also>
 <version>0.90_a</version>
 	output.
 </method>
 
-<method name="importNode"
-    synopsis="$document->importNode( $node [, $move] );">
-    <b>THIS FUNCTION IS NOT IMPLEMENTED YET</b>
-
-    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. 
-    (<i>$node->cloneNode(1)</i> will get called implicitly). 
-
-    Sometimes it is nessecary to <i>move</i> a node between
-    documents. In such a case the node will not be copied, but removed
-    from the original document.
+<method name="getLocalName" 
+    synopsis="$name = $node->getLocalName();">
+    Returns the local name of a tag. This is the part behind the colon.
 </method>
 
+<method name="getPrefix" 
+    synopsis="$name = $node->getPrefix();">
+    Returns the prefix of a tag. This is the part before the colon.
+</method>
+
+<method name="getNamespaceURI" synopsis="$uri = $node->getNamespaceURI()">
+    returns the URI of the current namespace.
+</method>
 </description>
 <also>
   <item name="XML::LibXML"/>
   <item name="XML::LibXML::Element"/>
   <item name="XML::LibXML::Text"/>
   <item name="XML::LibXML::Comment"/>
+  <item name="XML::LibXML::Attr"/>
 </also>
 <version>0.90_a</version>
 </class>
 	<i>$aname</i> to the value <i>$avalue</i>
 </method>
 
+<method name="setAttributeNS" synopsis="$node->setAttributeNS( $nsURI, $aname, $avalue );">
+	Namespaceversion of <i>setAttribute</i>.
+</method>
+
 <method name="getAttribute" 
     synopsis="$avalue = $node->getAttribute( $aname );">
 	If <i>$node</i> has an attribute with the name <i>$aname</i>,
 	the value of this attribute will get returned.
 </method>
 
+<method name="getAttributeNS" synopsis="$avalue = $node->setAttributeNS( $nsURI, $aname );">
+	Namespaceversion of <i>getAttribute</i>.
+</method>
+
 <method name="removeAttribute" synopsis="$node->removeAttribute( $aname );">
 	The method removes the attribute <i>$aname</i> from the node's
 	attribute list, if the attribute can be found.
 </method>
 
+<method name="removeAttributeNS" synopsis="$node->removeAttributeNS( $nsURI, $aname );">
+    Namespace version of <i>removeAttribute</i>
+</method>
+
+<method name="hasAttribute" synopsis="$boolean = $node->hasAttribute( $aname );">
+    This funcion tests if the named attribute is set for the node. If
+    the attrbute is specified, TRUE (1) will be returned, otherwise
+    the returnvalue is FALSE (0).
+</method>
+
+<method name="hasAttributeNS" synopsis="$boolean = $node->hasAttributeNS( $nsURI, $aname );">
+    namespace version of <i>hasAttribute</i>
+</method>
+
 <method name="getElementsByTagName" 
     synopsis="@nodes = $node->getElementsByTagName($tagname);">
 	The function gives direct access to all childnodes of the current
 	need to handle big datasets.
 </method>
 
+<method name="getElementsByTagNameNS" 
+    synopsis="@nodes = $node->getElementsByTagNameNS($nsURI,$tagname);">
+    Namespace version of <i>getElementsByTagName</i>.
+</method>
+
 <method name="appendWellBalancedChunk" 
 	synopsis="$node->appendWellBalancedChunk( $chunk )">
 	Sometimes it is nessecary to append a string coded XML Tree to 
   <item name="XML::LibXML"/>
   <item name="XML::LibXML::Node"/>
   <item name="XML::LibXML::Document"/>
+  <item name="XML::LibXML::Attr"/>
   <item name="XML::LibXML::Text"/>
   <item name="XML::LibXML::Comment"/>
 </also>
 <version>0.90_a</version>
 </class>
 
+<class name="XML::LibXML::Attr">
+<short>The DOM Attribute Class</short>
+<description>
+    This is the interface to handle Attributes like ordinary
+    nodes. The naming of the class relies on the W3C DOM
+    documentation.
+
+<method name="new" synopsis="$attr = XML::LibXML::Attr->new($name [,$value]);">
+    Class constructor. If you need to work with iso encoded strings,
+    you should <b>allways</b> use the <i>createAttrbute</i> of
+    <b>XML::LibXML::Document</b>.
+</method>
+
+<method name="getValue" synopsis="$string = $attr->getValue();">
+    Returns the value stored for the attribute. If undef is returned,
+    the attribute has no value, which is different of being <i>not
+    specified</i>.
+</method>
+
+<method name="setValue" synopsis="$attr->setValue( $string );">
+    This is needed to set a new attributevalue. If iso encoded strings
+    are passed as parameter, the node has to be bound to a document,
+    otherwise the encoding might be wrong done.
+</method>
+
+<method name="getOwnerElement" synopsis="$node = $attr->getOwnerDocument();">
+    returns the node the attribute belongs to. If the attribute is not
+    bound to a node, undef will be returned.
+</method>
+
+</description>
+<also>
+  <item name="XML::LibXML"/>
+  <item name="XML::LibXML::Node"/>
+  <item name="XML::LibXML::Element"/>
+  <item name="XML::LibXML::Document"/>
+</also>
+<version>0.92</version>
+</class>
+
 </module>

File t/06nodetypes.t

 
 use Test;
 
-BEGIN { plan tests=>38; }
+BEGIN { plan tests=>42; }
 END {ok(0) unless $loaded;}
 use XML::LibXML;
 $loaded = 1;
   # in the first version it cause a method not found ... 
   ok( $estr eq $te->toString() );
 
+  # attribute tests
 
   $elem1->setAttribute( $aname, $bvalue );
   ok( $elem1->getAttribute( $aname ) eq $bvalue );
   $elem1->removeAttribute( $aname );
   ok( not $elem1->hasAttribute( $aname ) );
 
+    my $attr = XML::LibXML::Attr->new( 'test', 'value' );
+    ok( defined $attr && 
+        $attr->getName() eq 'test' &&
+        $attr->getValue() eq 'value' );
+
+    $attr->setValue( 'other' );
+    ok( $attr->getValue() eq 'other' );
+
+    my $attr2 = $dom->createAttribute( "deutsch", "�berflieger" );
+    ok( defined $attr2 &&
+        $attr2->getName() eq "deutsch" &&
+        $attr2->getValue() eq "�berflieger" );
+
+    $attr2->setValue( "dr�ckeberger" );
+    ok( $attr2->getValue() eq "dr�ckeberger" );
+     
   # child node functions:
   my $text = $dom->createTextNode( $testtxt );
   ok( defined $text && $text->getType == XML_TEXT_NODE );
       $elem3->hasChildNodes() && 
       $elem3->getFirstChild()->getType() == XML_CDATA_SECTION_NODE && 
       $elem3->getFirstChild()->getData() eq $cdata );
+  
 }
 
+
 # node creation 2 (unbound element)
 #
 # NOTE!
   }
 
  }
+
 }

File t/08findnodes.t

 use Test;
-BEGIN { plan tests=>5; }
+BEGIN { plan tests=>8; }
 END {ok(0) unless $loaded;}
 use XML::LibXML;
 $loaded = 1;
 # everywhere. Since I use only the 
 
 my $file    = "example/dromeds.xml";
+$itervar    = undef;
+
 
 # init the file parser
 my $parser = XML::LibXML->new();
 $dom    = $parser->parse_file( $file );
 
 if ( defined $dom ) {
-  # get the root document
-  $elem   = $dom->getDocumentElement();
+    # get the root document
+    $elem   = $dom->getDocumentElement();
   
-  # first very simple path starting at root
-  my @list   = $elem->findnodes( "species" );
-  ok( scalar(@list) == 3 );
+    # first very simple path starting at root
+    my @list   = $elem->findnodes( "species" );
+    ok( scalar(@list) == 3 );
 
-  # a simple query starting somewhere ...
-  my $node = $list[0];
-  my @slist = $node->findnodes( "humps" );
-  ok( scalar(@slist) == 1 );
+    # a simple query starting somewhere ...
+    my $node = $list[0];
+    my @slist = $node->findnodes( "humps" );
+    ok( scalar(@slist) == 1 );
 
-  # find a single node
-  @list   = $elem->findnodes( "species[\@name='Llama']" );
-  ok( scalar( @list ) == 1 );
+    # find a single node
+    @list   = $elem->findnodes( "species[\@name='Llama']" );
+    ok( scalar( @list ) == 1 );
   
-  # find with not conditions
-  @list   = $elem->findnodes( "species[\@name!='Llama']/disposition" );
-  ok( scalar(@list) == 2 );
+    # find with not conditions
+    @list   = $elem->findnodes( "species[\@name!='Llama']/disposition" );
+    ok( scalar(@list) == 2 );
+
+
+    @list   = $elem->findnodes( 'species/@name' );
+    ok( scalar @list && $list[0]->toString() eq $list[0]->getData() );
+
+    my $x = XML::LibXML::Text->new( 1234 );
+    if( defined $x ) {
+        ok( $x->getData() eq "1234" );
+    }
+    
+    my $telem = $dom->createElement('test');
+    $telem->appendWellBalancedChunk('<b>c</b>');
+
+    $telem->iterator( sub { $itervar.=$_[0]->getName(); } );
+    ok( $itervar eq 'testbtext' );
+
 }