- xpath.c xpath.h xpathInternals.h: apply an XPath API cleanup
  patch from Thomas Broyer
Daniel
diff --git a/xpath.c b/xpath.c
index 910e2cc..cefe05f 100644
--- a/xpath.c
+++ b/xpath.c
@@ -2091,6 +2091,30 @@
 }
 
 /**
+ * xmlXPathWrapString:
+ * @val:  the xmlChar * value
+ *
+ * Wraps the @val string into an XPath object.
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathWrapString (xmlChar *val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathWrapString: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_STRING;
+    ret->stringval = val;
+    return(ret);
+}
+
+/**
  * xmlXPathNewCString:
  * @val:  the char * value
  *
@@ -2115,6 +2139,19 @@
 }
 
 /**
+ * xmlXPathWrapCString:
+ * @val:  the char * value
+ *
+ * Wraps a string into an XPath object.
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathWrapCString (char * val) {
+    return(xmlXPathWrapString((xmlChar *)(val)));
+}
+
+/**
  * xmlXPathObjectCopy:
  * @val:  the original object
  *
@@ -2208,6 +2245,439 @@
     xmlFree(obj);
 }
 
+
+/************************************************************************
+ *									*
+ *			Type Casting Routines				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPathCastBooleanToString:
+ * @val:  a boolean
+ *
+ * Converts a boolean to its string value.
+ *
+ * Returns a newly allocated string.
+ */
+xmlChar *
+xmlXPathCastBooleanToString (int val) {
+    xmlChar *ret;
+    if (val)
+	ret = xmlStrdup((const xmlChar *) "true");
+    else
+	ret = xmlStrdup((const xmlChar *) "false");
+    return(ret);
+}
+
+/**
+ * xmlXPathCastNumberToString:
+ * @val:  a number
+ *
+ * Converts a number to its string value.
+ *
+ * Returns a newly allocated string.
+ */
+xmlChar *
+xmlXPathCastNumberToString (double val) {
+    xmlChar *ret;
+    switch (isinf(val)) {
+    case 1:
+	ret = xmlStrdup((const xmlChar *) "+Infinity");
+	break;
+    case -1:
+	ret = xmlStrdup((const xmlChar *) "-Infinity");
+	break;
+    default:
+	if (isnan(val)) {
+	    ret = xmlStrdup((const xmlChar *) "NaN");
+	} else {
+	    /* could be improved */
+	    char buf[100];
+	    xmlXPathFormatNumber(val, buf, 100);
+	    ret = xmlStrdup((const xmlChar *) buf);
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathCastNodeToString:
+ * @node:  a node
+ *
+ * Converts a node to its string value.
+ *
+ * Returns a newly allocated string.
+ */
+xmlChar *
+xmlXPathCastNodeToString (xmlNodePtr node) {
+    return(xmlNodeGetContent(node));
+}
+
+/**
+ * xmlXPathCastNodeSetToString:
+ * @ns:  a node-set
+ *
+ * Converts a node-set to its string value.
+ *
+ * Returns a newly allocated string.
+ */
+xmlChar *
+xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
+    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
+	return(xmlStrdup((const xmlChar *) ""));
+
+    xmlXPathNodeSetSort(ns);
+    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
+}
+
+/**
+ * xmlXPathCastToString:
+ * @val:  an XPath object
+ *
+ * Converts an existing object to its string() equivalent
+ *
+ * Returns the string value of the object, NULL in case of error.
+ *         A new string is allocated only if needed (val isn't a
+ *         string object).
+ */
+xmlChar *
+xmlXPathCastToString(xmlXPathObjectPtr val) {
+    xmlChar *ret = NULL;
+
+    if (val == NULL)
+	return(xmlStrdup((const xmlChar *) ""));
+    switch (val->type) {
+	case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
+#endif
+	    ret = xmlStrdup((const xmlChar *) "");
+	    break;
+        case XPATH_XSLT_TREE:
+        case XPATH_NODESET:
+	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
+	    break;
+	case XPATH_STRING:
+	    return(val->stringval);
+        case XPATH_BOOLEAN:
+	    ret = xmlXPathCastBooleanToString(val->boolval);
+	    break;
+	case XPATH_NUMBER: {
+	    ret = xmlXPathCastNumberToString(val->floatval);
+	    break;
+	}
+	case XPATH_USERS:
+	case XPATH_POINT:
+	case XPATH_RANGE:
+	case XPATH_LOCATIONSET:
+	    TODO
+	    ret = xmlStrdup((const xmlChar *) "");
+	    break;
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathConvertString:
+ * @val:  an XPath object
+ *
+ * Converts an existing object to its string() equivalent
+ *
+ * Returns the new object, the old one is freed (or the operation
+ *         is done directly on @val)
+ */
+xmlXPathObjectPtr
+xmlXPathConvertString(xmlXPathObjectPtr val) {
+    xmlChar *res = NULL;
+
+    if (val == NULL)
+	return(xmlXPathNewCString(""));
+
+    switch (val->type) {
+    case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
+#endif
+	break;
+    case XPATH_XSLT_TREE:
+    case XPATH_NODESET:
+	res = xmlXPathCastNodeSetToString(val->nodesetval);
+	break;
+    case XPATH_STRING:
+	return(val);
+    case XPATH_BOOLEAN:
+	res = xmlXPathCastBooleanToString(val->boolval);
+	break;
+    case XPATH_NUMBER:
+	res = xmlXPathCastNumberToString(val->floatval);
+	break;
+    case XPATH_USERS:
+    case XPATH_POINT:
+    case XPATH_RANGE:
+    case XPATH_LOCATIONSET:
+	TODO;
+	break;
+    }
+    xmlXPathFreeObject(val);
+    if (res == NULL)
+	return(xmlXPathNewCString(""));
+    return(xmlXPathWrapString(res));
+}
+
+/**
+ * xmlXPathCastBooleanToNumber:
+ * @val:  a boolean
+ *
+ * Converts a boolean to its number value
+ *
+ * Returns the number value
+ */
+double
+xmlXPathCastBooleanToNumber(int val) {
+    if (val)
+	return(1.0);
+    return(0.0);
+}
+
+/**
+ * xmlXPathCastStringToNumber:
+ * @val:  a string
+ *
+ * Converts a string to its number value
+ *
+ * Returns the number value
+ */
+double
+xmlXPathCastStringToNumber(const xmlChar * val) {
+    return(xmlXPathStringEvalNumber(val));
+}
+
+/**
+ * xmlXPathCastNodeToNumber:
+ * @node:  a node
+ *
+ * Converts a node to its number value
+ *
+ * Returns the number value
+ */
+double
+xmlXPathCastNodeToNumber (xmlNodePtr node) {
+    xmlChar *strval;
+    double ret;
+
+    if (node == NULL)
+	return(xmlXPathNAN);
+    strval = xmlXPathCastNodeToString(node);
+    if (strval == NULL)
+	return(xmlXPathNAN);
+    ret = xmlXPathCastStringToNumber(strval);
+    xmlFree(strval);
+
+    return(ret);
+}
+
+/**
+ * xmlXPathCastNodeSetToNumber:
+ * @ns:  a node-set
+ *
+ * Converts a node-set to its number value
+ *
+ * Returns the number value
+ */
+double
+xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
+    xmlChar *str;
+    double ret;
+
+    if (ns == NULL)
+	return(xmlXPathNAN);
+    str = xmlXPathCastNodeSetToString(ns);
+    ret = xmlXPathCastStringToNumber(str);
+    xmlFree(str);
+    return(ret);
+}
+
+/**
+ * xmlXPathCastToNumber:
+ * @val:  an XPath object
+ *
+ * Converts an XPath object to its number value
+ *
+ * Returns the number value
+ */
+double
+xmlXPathCastToNumber(xmlXPathObjectPtr val) {
+    double ret = 0.0;
+
+    if (val == NULL)
+	return(xmlXPathNAN);
+    switch (val->type) {
+    case XPATH_UNDEFINED:
+#ifdef DEGUB_EXPR
+	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
+#endif
+	ret = xmlXPathNAN;
+	break;
+    case XPATH_XSLT_TREE:
+    case XPATH_NODESET:
+	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
+	break;
+    case XPATH_STRING:
+	ret = xmlXPathCastStringToNumber(val->stringval);
+	break;
+    case XPATH_NUMBER:
+	ret = val->floatval;
+	break;
+    case XPATH_BOOLEAN:
+	ret = xmlXPathCastBooleanToNumber(val->boolval);
+	break;
+    case XPATH_USERS:
+    case XPATH_POINT:
+    case XPATH_RANGE:
+    case XPATH_LOCATIONSET:
+	TODO;
+	ret = xmlXPathNAN;
+	break;
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathConvertNumber:
+ * @val:  an XPath object
+ *
+ * Converts an existing object to its number() equivalent
+ *
+ * Returns the new object, the old one is freed (or the operation
+ *         is done directly on @val)
+ */
+xmlXPathObjectPtr
+xmlXPathConvertNumber(xmlXPathObjectPtr val) {
+    xmlXPathObjectPtr ret;
+
+    if (val == NULL)
+	return(xmlXPathNewFloat(0.0));
+    if (val->type == XPATH_NUMBER)
+	return(val);
+    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
+    xmlXPathFreeObject(val);
+    return(ret);
+}
+
+/**
+ * xmlXPathCastNumberToBoolean:
+ * @val:  a number
+ *
+ * Converts a number to its boolean value
+ *
+ * Returns the boolean value
+ */
+int
+xmlXPathCastNumberToBoolean (double val) {
+     if (isnan(val) || (val == 0.0))
+	 return(0);
+     return(1);
+}
+
+/**
+ * xmlXPathCastStringToBoolean:
+ * @val:  a string
+ *
+ * Converts a string to its boolean value
+ *
+ * Returns the boolean value
+ */
+int
+xmlXPathCastStringToBoolean (const xmlChar *val) {
+    if ((val == NULL) || (xmlStrlen(val) == 0))
+	return(0);
+    return(1);
+}
+
+/**
+ * xmlXPathCastNodeSetToBoolean:
+ * @ns:  a node-set
+ *
+ * Converts a node-set to its boolean value
+ *
+ * Returns the boolean value
+ */
+int
+xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
+    if ((ns == NULL) || (ns->nodeNr == 0))
+	return(0);
+    return(1);
+}
+
+/**
+ * xmlXpathCastToBoolean:
+ * @val:  an XPath object
+ *
+ * Converts an XPath object to its boolean value
+ *
+ * Returns the boolean value
+ */
+int
+xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
+    int ret = 0;
+
+    if (val == NULL)
+	return(0);
+    switch (val->type) {
+    case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
+#endif
+	ret = 0;
+	break;
+    case XPATH_XSLT_TREE:
+    case XPATH_NODESET:
+	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
+	break;
+    case XPATH_STRING:
+	ret = xmlXPathCastStringToBoolean(val->stringval);
+	break;
+    case XPATH_NUMBER:
+	ret = xmlXPathCastNumberToBoolean(val->floatval);
+	break;
+    case XPATH_BOOLEAN:
+	ret = val->boolval;
+	break;
+    case XPATH_USERS:
+    case XPATH_POINT:
+    case XPATH_RANGE:
+    case XPATH_LOCATIONSET:
+	TODO;
+	ret = 0;
+	break;
+    }
+    return(ret);
+}
+
+
+/**
+ * xmlXPathConvertBoolean:
+ * @val:  an XPath object
+ *
+ * Converts an existing object to its boolean() equivalent
+ *
+ * Returns the new object, the old one is freed (or the operation
+ *         is done directly on @val)
+ */
+xmlXPathObjectPtr
+xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
+    xmlXPathObjectPtr ret;
+
+    if (val == NULL)
+	return(xmlXPathNewBoolean(0));
+    if (val->type == XPATH_BOOLEAN)
+	return(val);
+    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
+    xmlXPathFreeObject(val);
+    return(ret);
+}
+
 /************************************************************************
  *									*
  *		Routines to handle XPath contexts			*
@@ -2400,23 +2870,6 @@
  *									*
  ************************************************************************/
 
-/*
- * Auto-pop and cast to a number
- */
-void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
-
-
-#define POP_FLOAT						\
-    arg = valuePop(ctxt);					\
-    if (arg == NULL) {						\
-	XP_ERROR(XPATH_INVALID_OPERAND);				\
-    }								\
-    if (arg->type != XPATH_NUMBER) {				\
-        valuePush(ctxt, arg);					\
-        xmlXPathNumberFunction(ctxt, 1);			\
-	arg = valuePop(ctxt);					\
-    }
-
 /**
  * xmlXPathCompareNodeSetFloat:
  * @ctxt:  the XPath Parser context
@@ -2455,7 +2908,7 @@
     ns = arg->nodesetval;
     if (ns != NULL) {
 	for (i = 0;i < ns->nodeNr;i++) {
-	     str2 = xmlNodeGetContent(ns->nodeTab[i]);
+	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 	     if (str2 != NULL) {
 		 valuePush(ctxt,
 			   xmlXPathNewString(str2));
@@ -2510,7 +2963,7 @@
     ns = arg->nodesetval;
     if (ns != NULL) {
 	for (i = 0;i < ns->nodeNr;i++) {
-	     str2 = xmlNodeGetContent(ns->nodeTab[i]);
+	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
 	     if (str2 != NULL) {
 		 valuePush(ctxt,
 			   xmlXPathNewString(str2));
@@ -2529,7 +2982,7 @@
 
 /**
  * xmlXPathCompareNodeSets:
- * @op:  less than (-1), equal (0) or greater than (1)
+ * @inf:  less than (1) or greater than (0)
  * @strict:  is the comparison strict
  * @arg1:  the fist node set object
  * @arg2:  the second node set object
@@ -2562,7 +3015,6 @@
     double val1;
     double *values2;
     int ret = 0;
-    xmlChar *str;
     xmlNodeSetPtr ns1;
     xmlNodeSetPtr ns2;
 
@@ -2599,22 +3051,12 @@
 	return(0);
     }
     for (i = 0;i < ns1->nodeNr;i++) {
-	str = xmlNodeGetContent(ns1->nodeTab[i]);
-	if (str == NULL)
-	    continue;
-	val1 = xmlXPathStringEvalNumber(str);
-	xmlFree(str);
+	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
 	if (isnan(val1))
 	    continue;
 	for (j = 0;j < ns2->nodeNr;j++) {
 	    if (init == 0) {
-		str = xmlNodeGetContent(ns2->nodeTab[j]);
-		if (str == NULL) {
-		    values2[j] = xmlXPathNAN;
-		} else {
-		    values2[j] = xmlXPathStringEvalNumber(str);
-		    xmlFree(str);
-		}
+		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
 	    }
 	    if (isnan(values2[j]))
 		continue;
@@ -3133,11 +3575,9 @@
  */
 void
 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
-    xmlXPathObjectPtr arg;
-    
-    POP_FLOAT
-    arg->floatval = -arg->floatval;
-    valuePush(ctxt, arg);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+    ctxt->value->floatval = - ctxt->value->floatval;
 }
 
 /**
@@ -3153,13 +3593,15 @@
     xmlXPathObjectPtr arg;
     double val;
 
-    POP_FLOAT
-    val = arg->floatval;
+    arg = valuePop(ctxt);
+    if (arg == NULL)
+	XP_ERROR(XPATH_INVALID_OPERAND);
+    val = xmlXPathCastToNumber(arg);
     xmlXPathFreeObject(arg);
 
-    POP_FLOAT
-    arg->floatval += val;
-    valuePush(ctxt, arg);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+    ctxt->value->floatval += val;
 }
 
 /**
@@ -3175,13 +3617,15 @@
     xmlXPathObjectPtr arg;
     double val;
 
-    POP_FLOAT
-    val = arg->floatval;
+    arg = valuePop(ctxt);
+    if (arg == NULL)
+	XP_ERROR(XPATH_INVALID_OPERAND);
+    val = xmlXPathCastToNumber(arg);
     xmlXPathFreeObject(arg);
 
-    POP_FLOAT
-    arg->floatval -= val;
-    valuePush(ctxt, arg);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+    ctxt->value->floatval -= val;
 }
 
 /**
@@ -3197,13 +3641,15 @@
     xmlXPathObjectPtr arg;
     double val;
 
-    POP_FLOAT
-    val = arg->floatval;
+    arg = valuePop(ctxt);
+    if (arg == NULL)
+	XP_ERROR(XPATH_INVALID_OPERAND);
+    val = xmlXPathCastToNumber(arg);
     xmlXPathFreeObject(arg);
 
-    POP_FLOAT
-    arg->floatval *= val;
-    valuePush(ctxt, arg);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+    ctxt->value->floatval *= val;
 }
 
 /**
@@ -3219,13 +3665,15 @@
     xmlXPathObjectPtr arg;
     double val;
 
-    POP_FLOAT
-    val = arg->floatval;
+    arg = valuePop(ctxt);
+    if (arg == NULL)
+	XP_ERROR(XPATH_INVALID_OPERAND);
+    val = xmlXPathCastToNumber(arg);
     xmlXPathFreeObject(arg);
 
-    POP_FLOAT
-    arg->floatval /= val;
-    valuePush(ctxt, arg);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+    ctxt->value->floatval /= val;
 }
 
 /**
@@ -3241,14 +3689,16 @@
     xmlXPathObjectPtr arg;
     int arg1, arg2;
 
-    POP_FLOAT
-    arg2 = (int) arg->floatval;
+    arg = valuePop(ctxt);
+    if (arg == NULL)
+	XP_ERROR(XPATH_INVALID_OPERAND);
+    arg2 = (int) xmlXPathCastToNumber(arg);
     xmlXPathFreeObject(arg);
 
-    POP_FLOAT
-    arg1 = (int) arg->floatval;
-    arg->floatval = arg1 % arg2;
-    valuePush(ctxt, arg);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+    arg1 = (int) ctxt->value->floatval;
+    ctxt->value->floatval = arg1 % arg2;
 }
 
 /************************************************************************
@@ -3886,6 +4336,51 @@
 }
 
 /**
+ * xmlXPathGetElementsByIds:
+ * @doc:  the document
+ * @ids:  a whitespace separated list of IDs
+ *
+ * Selects elements by their unique ID.
+ *
+ * Returns a node-set of selected elements.
+ */
+static xmlNodeSetPtr
+xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
+    xmlNodeSetPtr ret;
+    const xmlChar *cur = ids;
+    xmlChar *ID;
+    xmlAttrPtr attr;
+    xmlNodePtr elem = NULL;
+
+    ret = xmlXPathNodeSetCreate(NULL);
+
+    while (IS_BLANK(*cur)) cur++;
+    while (*cur != 0) {
+	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+	       (*cur == '.') || (*cur == '-') ||
+	       (*cur == '_') || (*cur == ':') || 
+	       (IS_COMBINING(*cur)) ||
+	       (IS_EXTENDER(*cur)))
+	       cur++;
+
+	if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
+
+        ID = xmlStrndup(ids, cur - ids);
+	attr = xmlGetID(doc, ID);
+	if (attr != NULL) {
+	    elem = attr->parent;
+            xmlXPathNodeSetAdd(ret, elem);
+        }
+	if (ID != NULL)
+	    xmlFree(ID);
+
+	while (IS_BLANK(*cur)) cur++;
+	ids = cur;
+    }
+    return(ret);
+}
+
+/**
  * xmlXPathIdFunction:
  * @ctxt:  the XPath Parser context
  * @nargs:  the number of arguments
@@ -3905,82 +4400,40 @@
  */
 void
 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
-    const xmlChar *tokens;
-    const xmlChar *cur;
-    xmlChar *ID;
-    xmlAttrPtr attr;
-    xmlNodePtr elem = NULL;
-    xmlXPathObjectPtr ret, obj;
+    xmlChar *tokens;
+    xmlNodeSetPtr ret;
+    xmlXPathObjectPtr obj;
 
     CHECK_ARITY(1);
     obj = valuePop(ctxt);
     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
     if (obj->type == XPATH_NODESET) {
-	xmlXPathObjectPtr newobj;
+	xmlNodeSetPtr ns;
 	int i;
 
-	ret = xmlXPathNewNodeSet(NULL);
+	ret = xmlXPathNodeSetCreate(NULL);
 
 	if (obj->nodesetval != NULL) {
 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
-		valuePush(ctxt,
-			  xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
-		xmlXPathStringFunction(ctxt, 1);
-		xmlXPathIdFunction(ctxt, 1);
-		newobj = valuePop(ctxt);
-		ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
-						       newobj->nodesetval);
-		xmlXPathFreeObject(newobj);
+		tokens =
+		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
+		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
+		ret = xmlXPathNodeSetMerge(ret, ns);
+		xmlXPathFreeNodeSet(ns);
+		if (tokens != NULL)
+		    xmlFree(tokens);
 	    }
 	}
 
 	xmlXPathFreeObject(obj);
-	valuePush(ctxt, ret);
+	valuePush(ctxt, xmlXPathWrapNodeSet(ret));
 	return;
     }
-    if (obj->type != XPATH_STRING) {
-        valuePush(ctxt, obj);
-	xmlXPathStringFunction(ctxt, 1);
-	obj = valuePop(ctxt);
-	if (obj->type != XPATH_STRING) {
-	    xmlXPathFreeObject(obj);
-	    return;
-	}
-    }
-    tokens = obj->stringval;
+    obj = xmlXPathConvertString(obj);
 
-    ret = xmlXPathNewNodeSet(NULL);
-    valuePush(ctxt, ret);
-    if (tokens == NULL) {
-	xmlXPathFreeObject(obj);
-        return;
-    }
+    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
+    valuePush(ctxt, xmlXPathWrapNodeSet(ret));
 
-    cur = tokens;
-    
-    while (IS_BLANK(*cur)) cur++;
-    while (*cur != 0) {
-	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
-	       (*cur == '.') || (*cur == '-') ||
-	       (*cur == '_') || (*cur == ':') || 
-	       (IS_COMBINING(*cur)) ||
-	       (IS_EXTENDER(*cur)))
-	       cur++;
-
-	if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
-
-        ID = xmlStrndup(tokens, cur - tokens);
-	attr = xmlGetID(ctxt->context->doc, ID);
-	if (attr != NULL) {
-	    elem = attr->parent;
-            xmlXPathNodeSetAdd(ret->nodesetval, elem);
-        }
-	if (ID != NULL)
-	    xmlFree(ID);
-
-	while (IS_BLANK(*cur)) cur++;
-	tokens = cur;
-    }
     xmlXPathFreeObject(obj);
     return;
 }
@@ -4155,68 +4608,6 @@
 
 
 /**
- * xmlXPathConvertString:
- * @val:  an XPath object
- *
- * Converts an existing object to its string() equivalent
- *
- * Returns the new object, the old one is freed (or the operation
- *         is done directly on @val)
- */
-xmlXPathObjectPtr
-xmlXPathConvertString(xmlXPathObjectPtr val) {
-    xmlXPathObjectPtr ret = NULL;
-
-    if (val == NULL)
-	return(xmlXPathNewCString(""));
-    switch (val->type) {
-	case XPATH_UNDEFINED:
-#ifdef DEBUG_EXPR
-	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
-#endif
-	    ret = xmlXPathNewCString("");
-	    break;
-        case XPATH_XSLT_TREE:
-        case XPATH_NODESET:
-	    if ((val->nodesetval == NULL) || (val->nodesetval->nodeNr == 0)) {
-		ret = xmlXPathNewCString("");
-	    } else {
-		xmlChar *res;
-
-		xmlXPathNodeSetSort(val->nodesetval);
-		res = xmlNodeGetContent(val->nodesetval->nodeTab[0]);
-		/* TODO: avoid allocating res to free it */
-		ret = xmlXPathNewString(res);
-		if (res != NULL)
-		    xmlFree(res);
-	    }
-	    break;
-	case XPATH_STRING:
-	    return(val);
-        case XPATH_BOOLEAN:
-	    if (val->boolval) ret = xmlXPathNewCString("true");
-	    else ret = xmlXPathNewCString("false");
-	    break;
-	case XPATH_NUMBER: {
-	    char buf[100];
-
-	    xmlXPathFormatNumber(val->floatval, buf, sizeof(buf));
-	    ret = xmlXPathNewCString(buf);
-	    break;
-	}
-	case XPATH_USERS:
-	case XPATH_POINT:
-	case XPATH_RANGE:
-	case XPATH_LOCATIONSET:
-	    TODO
-	    ret = xmlXPathNewCString("");
-	    break;
-    }
-    xmlXPathFreeObject(val);
-    return(ret);
-}
-
-/**
  * xmlXPathStringFunction:
  * @ctxt:  the XPath Parser context
  * @nargs:  the number of arguments
@@ -4257,8 +4648,10 @@
     xmlXPathObjectPtr cur;
 
     if (nargs == 0) {
-	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
-	nargs = 1;
+	valuePush(ctxt,
+		  xmlXPathWrapString(
+			xmlXPathCastNodeToString(ctxt->context->node)));
+	return;
     }
 
     CHECK_ARITY(1);
@@ -4290,7 +4683,7 @@
 	} else {
 	    xmlChar *content;
 
-	    content = xmlNodeGetContent(ctxt->context->node);
+	    content = xmlXPathCastNodeToString(ctxt->context->node);
 	    valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
 	    xmlFree(content);
 	}
@@ -4621,8 +5014,9 @@
   
   if (nargs == 0) {
     /* Use current context node */
-    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
-    xmlXPathStringFunction(ctxt, 1);
+    valuePush(ctxt,
+	      xmlXPathWrapString(
+		  xmlXPathCastNodeToString(ctxt->context->node)));
     nargs = 1;
   }
 
@@ -4724,47 +5118,6 @@
 }
 
 /**
- * xmlXPathConvertBoolean:
- * @val:  an XPath object
- *
- * Converts an existing object to its boolean() equivalent
- *
- * Returns the new object, the old one is freed (or the operation
- *         is done directly on @val)
- */
-xmlXPathObjectPtr
-xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
-    int res = 0;
-
-    if (val == NULL)
-	return(NULL);
-    switch (val->type) {
-        case XPATH_NODESET:
-        case XPATH_XSLT_TREE:
-	    if ((val->nodesetval == NULL) ||
-	        (val->nodesetval->nodeNr == 0)) res = 0;
-	    else 
-	        res = 1;
-	    break;
-	case XPATH_STRING:
-	    if ((val->stringval == NULL) ||
-	        (val->stringval[0] == 0)) res = 0;
-	    else 
-	        res = 1;
-	    break;
-        case XPATH_BOOLEAN:
-	    return(val);
-	case XPATH_NUMBER:
-	    if (val->floatval) res = 1;
-	    break;
-	default:
-	    STRANGE
-    }
-    xmlXPathFreeObject(val);
-    return(xmlXPathNewBoolean(res));
-}
-
-/**
  * xmlXPathBooleanFunction:
  * @ctxt:  the XPath Parser context
  * @nargs:  the number of arguments
@@ -4881,55 +5234,6 @@
 }
 
 /**
- * xmlXPathConvertNumber:
- * @val:  an XPath object
- *
- * Converts an existing object to its number() equivalent
- *
- * Returns the new object, the old one is freed (or the operation
- *         is done directly on @val)
- */
-xmlXPathObjectPtr
-xmlXPathConvertNumber(xmlXPathObjectPtr val) {
-    xmlXPathObjectPtr ret = NULL;
-    double res;
-
-    if (val == NULL)
-	return(xmlXPathNewFloat(0.0));
-    switch (val->type) {
-	case XPATH_UNDEFINED:
-#ifdef DEBUG_EXPR
-	    xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
-#endif
-	    ret = xmlXPathNewFloat(0.0);
-	    break;
-        case XPATH_XSLT_TREE:
-        case XPATH_NODESET:
-	    val = xmlXPathConvertString(val);
-	    /* no break on purpose */
-	case XPATH_STRING:
-	    res = xmlXPathStringEvalNumber(val->stringval);
-	    ret = xmlXPathNewFloat(res);
-	    break;
-        case XPATH_BOOLEAN:
-	    if (val->boolval) ret = xmlXPathNewFloat(1.0);
-	    else ret = xmlXPathNewFloat(0.0);
-	    break;
-	case XPATH_NUMBER:
-	    return(val);
-	case XPATH_USERS:
-	case XPATH_POINT:
-	case XPATH_RANGE:
-	case XPATH_LOCATIONSET:
-	    TODO
-	    ret = xmlXPathNewFloat(0.0);
-	    break;
-    }
-    xmlXPathFreeObject(val);
-    return(ret);
-}
-
-/**
  * xmlXPathNumberFunction:
  * @ctxt:  the XPath Parser context
  * @nargs:  the number of arguments
@@ -4975,6 +5279,7 @@
 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     xmlXPathObjectPtr cur;
     int i;
+    double res = 0.0;
 
     CHECK_ARITY(1);
     if ((ctxt->value == NULL) || 
@@ -4986,14 +5291,10 @@
     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
 	valuePush(ctxt, xmlXPathNewFloat(0.0));
     } else {
-	valuePush(ctxt,
-		  xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
-	xmlXPathNumberFunction(ctxt, 1);
-	for (i = 1; i < cur->nodesetval->nodeNr; i++) {
-	    valuePush(ctxt,
-		      xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
-	    xmlXPathAddValues(ctxt);
+	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
+	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
 	}
+	valuePush(ctxt, xmlXPathNewFloat(res));
     }
     xmlXPathFreeObject(cur);
 }
@@ -7195,10 +7496,8 @@
 	    else if (op->value == 1) xmlXPathAddValues(ctxt);
 	    else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
 	    else if (op->value == 3) {
-		xmlXPathObjectPtr arg;
-		
-		POP_FLOAT
-		valuePush(ctxt, arg);
+		CAST_TO_NUMBER;
+		CHECK_TYPE(XPATH_NUMBER);
 	    }
 	    return;
 	case XPATH_OP_MULT: