Bundled lookup of attr-nodes and retrieving their values into the

* tree.c: Bundled lookup of attr-nodes and retrieving their
  values into the functions xmlGetPropNodeInternal() and
  xmlGetPropNodeValueInternal(). Changed relevant code
  to use those functions.
diff --git a/tree.c b/tree.c
index 661545f..82b9014 100644
--- a/tree.c
+++ b/tree.c
@@ -5960,6 +5960,154 @@
 }
 #endif /* LIBXML_TREE_ENABLED */
 
+static xmlAttrPtr
+xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
+		       const xmlChar *nsName, int useDTD)
+{
+    xmlAttrPtr prop;
+
+    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
+	return(NULL);
+
+    if (node->properties != NULL) {
+	prop = node->properties;
+	if (nsName == NULL) {
+	    /*
+	    * We want the attr to be in no namespace.
+	    */
+	    do {
+		if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
+		    return(prop);
+		}
+		prop = prop->next;
+	    } while (prop != NULL);
+	} else {
+	    /*
+	    * We want the attr to be in the specified namespace.
+	    */
+	    do {
+		if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
+		    ((prop->ns->href == nsName) ||
+		     xmlStrEqual(prop->ns->href, nsName)))
+		{
+		    return(prop);
+		}
+		prop = prop->next;
+	    } while (prop != NULL);
+	}
+    }
+
+#ifdef LIBXML_TREE_ENABLED
+    if (! useDTD)
+	return(NULL);
+    /*
+     * Check if there is a default/fixed attribute declaration in
+     * the internal or external subset.
+     */    
+    if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
+	xmlDocPtr doc = node->doc;
+	xmlAttributePtr attrDecl = NULL;
+	xmlChar *elemQName, *tmpstr = NULL;
+
+	/*
+	* We need the QName of the element for the DTD-lookup.	
+	*/
+	if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
+	    tmpstr = xmlStrdup(node->ns->prefix);
+	    tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
+	    tmpstr = xmlStrcat(tmpstr, node->name);
+	    if (tmpstr == NULL)
+		return(NULL);
+	    elemQName = tmpstr;
+	} else
+	    elemQName = (xmlChar *) node->name;
+	if (nsName == NULL) {
+	    /*
+	    * The common and nice case: Attr in no namespace.
+	    */
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
+		elemQName, name, NULL);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
+		    elemQName, name, NULL);
+	    }
+	} else {
+	    xmlNsPtr *nsList, *cur;
+
+	    /*
+	    * The ugly case: Search using the prefixes of in-scope
+	    * ns-decls corresponding to @nsName.
+	    */
+	    nsList = xmlGetNsList(node->doc, node);
+	    if (nsList == NULL) {
+		if (tmpstr != NULL)
+		    xmlFree(tmpstr);
+		return(NULL);
+	    }
+	    cur = nsList;
+	    while (*cur != NULL) {
+		if (xmlStrEqual((*cur)->href, nsName)) {
+		    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
+			name, (*cur)->prefix);
+		    if (attrDecl)
+			break;
+		    if (doc->extSubset != NULL) {
+			attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
+			    name, (*cur)->prefix);
+			if (attrDecl)
+			    break;
+		    }
+		}
+		cur++;
+	    }
+	    xmlFree(nsList);
+	}	
+	if (tmpstr != NULL)
+	    xmlFree(tmpstr);
+	/*
+	* Only default/fixed attrs are relevant.
+	*/
+	if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
+	    return((xmlAttrPtr) attrDecl);
+    }
+#endif /* LIBXML_TREE_ENABLED */
+    return(NULL);
+}
+
+static xmlChar*
+xmlGetPropNodeValueInternal(xmlAttrPtr prop)
+{
+    if (prop == NULL)
+	return(NULL);
+    if (prop->type == XML_ATTRIBUTE_NODE) {
+	/*
+	* Note that we return at least the empty string.
+	*   TODO: Do we really always want that?
+	*/
+	if (prop->children != NULL) {
+	    if ((prop->children == prop->last) &&
+		((prop->children->type == XML_TEXT_NODE) ||
+		(prop->children->type == XML_CDATA_SECTION_NODE)))
+	    {
+		/*
+		* Optimization for the common case: only 1 text node.
+		*/
+		return(xmlStrdup(prop->children->content));
+	    } else {
+		xmlChar *ret;
+
+		ret = xmlNodeListGetString(prop->doc, prop->children, 1);
+		if (ret != NULL)
+		    return(ret);
+	    }
+	}
+	return(xmlStrdup((xmlChar *)""));
+    } else if (prop->type == XML_ATTRIBUTE_DECL) {
+	return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
+    }
+    return(NULL); 
+}
+
 /**
  * xmlHasProp:
  * @node:  the node
@@ -6029,86 +6177,8 @@
  */
 xmlAttrPtr
 xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
-    xmlAttrPtr prop;
-#ifdef LIBXML_TREE_ENABLED
-    xmlDocPtr doc;
-#endif /* LIBXML_TREE_ENABLED */
 
-    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
-	return(NULL);
-
-    prop = node->properties;
-    while (prop != NULL) {
-	/*
-	 * One need to have
-	 *   - same attribute names
-	 *   - and the attribute carrying that namespace
-	 */
-        if (xmlStrEqual(prop->name, name)) {
-	    if (((prop->ns != NULL) &&
-	    	 (xmlStrEqual(prop->ns->href, nameSpace))) ||
-		((prop->ns == NULL) && (nameSpace == NULL))) {
-		return(prop);
-	    }
-        }
-	prop = prop->next;
-    }
-    if (!xmlCheckDTD) return(NULL);
-
-#ifdef LIBXML_TREE_ENABLED
-    /*
-     * 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 = NULL;
-	    xmlNsPtr *nsList, *cur;
-	    xmlChar *ename;
-
-	    nsList = xmlGetNsList(node->doc, node);
-	    if (nsList == NULL)
-		return(NULL);
-	    if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
-		ename = xmlStrdup(node->ns->prefix);
-		ename = xmlStrcat(ename, BAD_CAST ":");
-		ename = xmlStrcat(ename, node->name);
-	    } else {
-		ename = xmlStrdup(node->name);
-	    }
-	    if (ename == NULL) {
-		xmlFree(nsList);
-		return(NULL);
-	    }
-
-	    if (nameSpace == NULL) {
-	        attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
-					      name, NULL);
-		if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
-		    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
-		    				  name, NULL);
-		}
-	    } else {
-		cur = nsList;
-		while (*cur != NULL) {
-		    if (xmlStrEqual((*cur)->href, nameSpace)) {
-			attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
-						      name, (*cur)->prefix);
-			if ((attrDecl == NULL) && (doc->extSubset != NULL))
-			    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
-							  name, (*cur)->prefix);
-		    }
-		    cur++;
-		}
-	    }
-	    xmlFree(nsList);
-	    xmlFree(ename);
-	    return((xmlAttrPtr) attrDecl);
-	}
-    }
-#endif /* LIBXML_TREE_ENABLED */
-    return(NULL);
+    return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
 }
 
 /**
@@ -6129,46 +6199,12 @@
  */
 xmlChar *
 xmlGetProp(xmlNodePtr node, const xmlChar *name) {
-    xmlAttrPtr prop;
-    xmlDocPtr doc;
+    xmlAttrPtr prop;    
 
-    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
-        return(NULL);
-
-    /*
-     * Check on the properties attached to the node
-     */
-    prop = node->properties;
-    while (prop != NULL) {
-        if (xmlStrEqual(prop->name, name))  {
-	    xmlChar *ret;
-
-	    ret = xmlNodeListGetString(node->doc, prop->children, 1);
-	    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
-	    return(ret);
-        }
-	prop = prop->next;
-    }
-    if (!xmlCheckDTD) return(NULL);
-
-    /*
-     * Check if there is a default declaration in the internal
-     * or external subsets
-     */
-    doc =  node->doc;
-    if (doc != NULL) {
-        xmlAttributePtr attrDecl;
-        if (doc->intSubset != NULL) {
-	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
-	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
-            if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
-              /* return attribute declaration only if a default value is given
-                 (that includes #FIXED declarations) */
-		return(xmlStrdup(attrDecl->defaultValue));
-	}
-    }
-    return(NULL);
+    prop = xmlHasProp(node, name);
+    if (prop == NULL)
+	return(NULL);
+    return(xmlGetPropNodeValueInternal(prop));     
 }
 
 /**
@@ -6189,44 +6225,11 @@
 xmlChar *
 xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
     xmlAttrPtr prop;
-    xmlDocPtr doc;
-
-    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
+    
+    prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
+    if (prop == NULL)
 	return(NULL);
-    /*
-     * Check on the properties attached to the node
-     */
-    prop = node->properties;
-    while (prop != NULL) {
-        if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name)))  {
-	    xmlChar *ret;
-
-	    ret = xmlNodeListGetString(node->doc, prop->children, 1);
-	    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
-	    return(ret);
-        }
-	prop = prop->next;
-    }
-    if (!xmlCheckDTD) return(NULL);
-
-    /*
-     * Check if there is a default declaration in the internal
-     * or external subsets
-     */
-    doc =  node->doc;
-    if (doc != NULL) {
-        xmlAttributePtr attrDecl;
-        if (doc->intSubset != NULL) {
-	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
-	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
-            if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
-              /* return attribute declaration only if a default value is given
-                 (that includes #FIXED declarations) */
-		return(xmlStrdup(attrDecl->defaultValue));
-	}
-    }
-    return(NULL);
+    return(xmlGetPropNodeValueInternal(prop));
 }
 
 /**
@@ -6247,58 +6250,11 @@
 xmlChar *
 xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
     xmlAttrPtr prop;
-    xmlDocPtr doc;
-    xmlNsPtr ns;
 
-    if ((node == NULL) || (node->type != XML_ELEMENT_NODE))
+    prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
+    if (prop == NULL)
 	return(NULL);
-
-    prop = node->properties;
-    if (nameSpace == NULL)
-	return(xmlGetNoNsProp(node, name));
-    while (prop != NULL) {
-	/*
-	 * One need to have
-	 *   - same attribute names
-	 *   - and the attribute carrying that namespace
-	 */
-        if ((xmlStrEqual(prop->name, name)) &&
-	    ((prop->ns != NULL) &&
-	     (xmlStrEqual(prop->ns->href, nameSpace)))) {
-	    xmlChar *ret;
-
-	    ret = xmlNodeListGetString(node->doc, prop->children, 1);
-	    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
-	    return(ret);
-        }
-	prop = prop->next;
-    }
-    if (!xmlCheckDTD) return(NULL);
-
-    /*
-     * 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(xmlStrdup(attrDecl->defaultValue));
-	    }
-	}
-    }
-    return(NULL);
+    return(xmlGetPropNodeValueInternal(prop));
 }
 
 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
@@ -6308,25 +6264,19 @@
  * @name:  the attribute name
  *
  * Remove an attribute carried by a node.
+ * This handles only attributes in no namespace.
  * Returns 0 if successful, -1 if not found
  */
 int
 xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
     xmlAttrPtr prop;
 
-    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
+    prop = xmlGetPropNodeInternal(node, name, NULL, 0);
+    if (prop == NULL)
 	return(-1);
-    prop = node->properties;
-    while (prop != NULL) {
-        if ((xmlStrEqual(prop->name, name)) &&
-	    (prop->ns == NULL)) {
-		xmlUnlinkNode((xmlNodePtr) prop);
-	    xmlFreeProp(prop);
-	    return(0);
-	}
-	prop = prop->next;
-    }
-    return(-1);
+    xmlUnlinkNode((xmlNodePtr) prop);
+    xmlFreeProp(prop);
+    return(0);
 }
 
 /**
@@ -6341,24 +6291,13 @@
 int
 xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
     xmlAttrPtr prop;
-
-    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
+    
+    prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
+    if (prop == NULL)
 	return(-1);
-    prop = node->properties;
-    if (ns == NULL)
-	return(xmlUnsetProp(node, name));
-    if (ns->href == NULL)
-	return(-1);
-    while (prop != NULL) {
-        if ((xmlStrEqual(prop->name, name)) &&
-	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
-	    xmlUnlinkNode((xmlNodePtr) prop);
-	    xmlFreeProp(prop);
-	    return(0);
-	}
-	prop = prop->next;
-    }
-    return(-1);
+    xmlUnlinkNode((xmlNodePtr) prop);
+    xmlFreeProp(prop);
+    return(0);
 }
 #endif
 
@@ -6366,16 +6305,19 @@
 /**
  * xmlSetProp:
  * @node:  the node
- * @name:  the attribute name
+ * @name:  the attribute name (a QName)
  * @value:  the attribute value
  *
  * Set (or reset) an attribute carried by a node.
+ * If @name has a prefix, then the corresponding
+ * namespace-binding will be used, if in scope; it is an
+ * error it there's no such ns-binding for the prefix in
+ * scope.
  * Returns the attribute pointer.
+ * 
  */
 xmlAttrPtr
 xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
-    xmlAttrPtr prop;
-    xmlDocPtr doc;
     int len;
     const xmlChar *nqname;
 
@@ -6394,49 +6336,15 @@
 	    xmlFree(prefix);
 	if (ns != NULL)
 	    return(xmlSetNsProp(node, ns, nqname, value));
+	/*
+	* If we get a QName and the prefix has no namespace-
+	* binding in scope, then this is an error.
+	* TODO: Previously this falled-back to non-ns handling.
+	*   Should we revert this?
+	*/
+	return(NULL);
     }
-
-    doc = node->doc;
-    prop = node->properties;
-    while (prop != NULL) {
-        if ((xmlStrEqual(prop->name, name)) &&
-	    (prop->ns == NULL)){
-	    int id = 0;
-	    xmlNodePtr oldprop = prop->children;
-	    if (prop->atype == XML_ATTRIBUTE_ID) {
-	        id = 1;
-	        xmlRemoveID(node->doc, prop);
-	    }
-	    prop->children = NULL;
-	    prop->last = NULL;
-	    if (value != NULL) {
-	        xmlChar *buffer;
-		xmlNodePtr tmp;
-
-		buffer = xmlEncodeEntitiesReentrant(node->doc, value);
-		prop->children = xmlStringGetNodeList(node->doc, buffer);
-		prop->last = NULL;
-		prop->doc = doc;
-		tmp = prop->children;
-		while (tmp != NULL) {
-		    tmp->parent = (xmlNodePtr) prop;
-		    tmp->doc = doc;
-		    if (tmp->next == NULL)
-			prop->last = tmp;
-		    tmp = tmp->next;
-		}
-		xmlFree(buffer);
-	    }
-	    if (oldprop != NULL) 
-	        xmlFreeNodeList(oldprop);
-	    if (id)
-	        xmlAddID(NULL, node->doc, value, prop);
-	    return(prop);
-	}
-	prop = prop->next;
-    }
-    prop = xmlNewProp(node, name, value);
-    return(prop);
+    return(xmlSetNsProp(node, NULL, name, value));
 }
 
 /**
@@ -6447,66 +6355,56 @@
  * @value:  the attribute value
  *
  * Set (or reset) an attribute carried by a node.
- * The ns structure must be in scope, this is not checked.
+ * The ns structure must be in scope, this is not checked
  *
  * Returns the attribute pointer.
  */
 xmlAttrPtr
 xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
-	     const xmlChar *value) {
+	     const xmlChar *value)
+{
     xmlAttrPtr prop;
     
-    if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
+    if (ns && (ns->href == NULL))
 	return(NULL);
-
-    if (ns == NULL)
-	return(xmlSetProp(node, name, value));
-    if (ns->href == NULL)
-	return(NULL);
-    prop = node->properties;
-
-    while (prop != NULL) {
+    prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
+    if (prop != NULL) {
 	/*
-	 * One need to have
-	 *   - same attribute names
-	 *   - and the attribute carrying that namespace
-	 */
-        if ((xmlStrEqual(prop->name, name)) &&
-	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
-	    int id = 0;
-	    if (prop->atype == XML_ATTRIBUTE_ID) {
-	        id = 1;
-	        xmlRemoveID(node->doc, prop);
-	    }
-	    if (prop->children != NULL) 
-	        xmlFreeNodeList(prop->children);
-	    prop->children = NULL;
+	* Modify the attribute's value.
+	*/
+	if (prop->atype == XML_ATTRIBUTE_ID) {
+	    xmlRemoveID(node->doc, prop);
+	    prop->atype = XML_ATTRIBUTE_ID;
+	}
+	if (prop->children != NULL) 
+	    xmlFreeNodeList(prop->children);
+	prop->children = NULL;
+	prop->last = NULL;
+	prop->ns = ns;
+	if (value != NULL) {
+	    xmlChar *buffer;
+	    xmlNodePtr tmp;
+	    
+	    buffer = xmlEncodeEntitiesReentrant(node->doc, value);
+	    prop->children = xmlStringGetNodeList(node->doc, buffer);
 	    prop->last = NULL;
-	    prop->ns = ns;
-	    if (value != NULL) {
-	        xmlChar *buffer;
-		xmlNodePtr tmp;
-
-		buffer = xmlEncodeEntitiesReentrant(node->doc, value);
-		prop->children = xmlStringGetNodeList(node->doc, buffer);
-		prop->last = NULL;
-		tmp = prop->children;
-		while (tmp != NULL) {
-		    tmp->parent = (xmlNodePtr) prop;
-		    if (tmp->next == NULL)
-			prop->last = tmp;
-		    tmp = tmp->next;
-		}
-		xmlFree(buffer);
-	    }	
-	    if (id)
-	        xmlAddID(NULL, node->doc, value, prop);
-	    return(prop);
-        }
-	prop = prop->next;
+	    tmp = prop->children;
+	    while (tmp != NULL) {
+		tmp->parent = (xmlNodePtr) prop;
+		if (tmp->next == NULL)
+		    prop->last = tmp;
+		tmp = tmp->next;
+	    }
+	    xmlFree(buffer);
+	}
+	if (prop->atype == XML_ATTRIBUTE_ID)
+	    xmlAddID(NULL, node->doc, value, prop);
+	return(prop);
     }
-    prop = xmlNewNsProp(node, ns, name, value);
-    return(prop);
+    /*
+    * No equal attr found; create a new one.
+    */
+    return(xmlNewPropInternal(node, ns, name, value, 0));
 }
 
 #endif /* LIBXML_TREE_ENABLED */
@@ -9393,6 +9291,5 @@
 }
 
 
-
 #define bottom_tree
 #include "elfgcchack.h"