Added xmlXPathCompiledEvalToBoolean() to the API and adjusted/added

* xpath.c: Added xmlXPathCompiledEvalToBoolean() to the API and
  adjusted/added xmlXPathRunEval(), xmlXPathRunStreamEval(),
  xmlXPathCompOpEvalToBoolean(), xmlXPathNodeCollectAndTest()
  to be aware of a boolean result request. The new function
  is now used to evaluate predicates.
diff --git a/xpath.c b/xpath.c
index ce46c49..80c1685 100644
--- a/xpath.c
+++ b/xpath.c
@@ -65,18 +65,6 @@
             __FILE__, __LINE__);
 
 /*
-* XP_PATTERN_TO_ANY_NODE_ENABLED: when an XPath expression can be
-*   evaluated using the streaming mode (pattern.c) then this is used to
-*   enable resolution to nodes of type text-node, cdata-section-node,
-*   comment-node and pi-node. The only known scenario where this is
-*   needed is an expression like "foo//.", "//.", etc.; i.e. an expression
-*   where the final node to be selected can be of any type.
-*   Disabling this #define will result in an incorrect evaluation to
-*   only element-nodes and the document node.
-*/
-#define XP_PATTERN_TO_ANY_NODE_ENABLED
-
-/*
 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
 * If defined, this will use xmlXPathCmpNodesExt() instead of
 * xmlXPathCmpNodes(). The new function is optimized comparison of
@@ -109,15 +97,6 @@
  */
 
 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
-/************************************************************************
- * 									*
- * 			Forward declarations				*
- * 									*
- ************************************************************************/
-static void
-xmlXPathFreeValueTree(xmlNodeSetPtr obj);
-static void
-xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
 
 /************************************************************************
  * 									*
@@ -608,6 +587,22 @@
 
 /************************************************************************
  * 									*
+ * 			Forward declarations				*
+ * 									*
+ ************************************************************************/
+static void
+xmlXPathFreeValueTree(xmlNodeSetPtr obj);
+static void
+xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
+static int
+xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
+                        xmlXPathStepOpPtr op, xmlNodePtr *first);
+static int
+xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
+			    xmlXPathStepOpPtr op);
+
+/************************************************************************
+ * 									*
  * 			Parser Type functions 				*
  * 									*
  ************************************************************************/
@@ -2328,22 +2323,20 @@
     if (val == NULL)
 	return(NULL);
 
-    switch (val->type) {
-	case XPATH_NODESET:
-	    if (XP_HAS_CACHE(ctxt))
+    if (XP_HAS_CACHE(ctxt)) {
+	switch (val->type) {
+	    case XPATH_NODESET:
 		return(xmlXPathCacheWrapNodeSet(ctxt,
 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
-	case XPATH_STRING:
-	    if (XP_HAS_CACHE(ctxt))
+	    case XPATH_STRING:
 		return(xmlXPathCacheNewString(ctxt, val->stringval));
-	case XPATH_BOOLEAN:
-	    if (XP_HAS_CACHE(ctxt))
+	    case XPATH_BOOLEAN:
 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
-	case XPATH_NUMBER:
-	    if (XP_HAS_CACHE(ctxt))
-		return(xmlXPathCacheNewFloat(ctxt, val->floatval));	
-	default:
-	    break;
+	    case XPATH_NUMBER:
+		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
+	    default:
+		break;
+	}
     }
     return(xmlXPathObjectCopy(val));
 }
@@ -6037,6 +6030,17 @@
 	return(NULL);							\
     }									\
 
+#define CHECK_CTXT_NEG(ctxt)						\
+    if (ctxt == NULL) { 						\
+	__xmlRaiseError(NULL, NULL, NULL,				\
+		NULL, NULL, XML_FROM_XPATH,				\
+		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
+		__FILE__, __LINE__,					\
+		NULL, NULL, NULL, 0, 0,					\
+		"NULL context pointer\n");				\
+	return(-1);							\
+    }									\
+
 
 #define CHECK_CONTEXT(ctxt)						\
     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
@@ -10851,7 +10855,19 @@
     SKIP_BLANKS;
 
     ctxt->comp->last = -1;
-    xmlXPathCompileExpr(ctxt, 1);
+    /*
+    * This call to xmlXPathCompileExpr() will deactivate sorting
+    * of the predicate result.
+    * TODO: Sorting is still activated for filters, since I'm not
+    *  sure if needed. Normally sorting should not be needed, since
+    *  a filter can only diminish the number of items in a sequence,
+    *  but won't change its order; so if the initial sequence is sorted,
+    *  subsequent sorting is not needed.
+    */
+    if (! filter)
+	xmlXPathCompileExpr(ctxt, 0);
+    else
+	xmlXPathCompileExpr(ctxt, 1);
     CHECK_ERROR;
 
     if (CUR != ']') {
@@ -11456,7 +11472,7 @@
 	xmlXPathContextPtr xpctxt = ctxt->context;
 	xmlNodePtr contextNode, oldContextNode;
 	xmlDocPtr oldContextDoc;
-	int i, contextPos = 0, newContextSize;
+	int i, res, contextPos = 0, newContextSize;
 	xmlXPathStepOpPtr exprOp;
 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
 
@@ -11525,28 +11541,21 @@
 		    contextNode);
 
 	    valuePush(ctxt, contextObj);
-	    xmlXPathCompOpEval(ctxt, exprOp);
 
-	    if (ctxt->error != XPATH_EXPRESSION_OK)
+	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp);
+
+	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
 		goto evaluation_error;
-	    
-	    exprRes = valuePop(ctxt);
-	    /*
-	    * This checks if the result of the evaluation is 'true'.
-	    */
-	    if (! xmlXPathEvaluatePredicateResult(ctxt, exprRes)) {
+
+	    if (res != 0) {
+		newContextSize++;
+	    } else {
 		/*
 		* Remove the entry from the initial node set.
 		*/
 		set->nodeTab[i] = NULL;
 		if (contextNode->type == XML_NAMESPACE_DECL)
 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
-	    } else
-		newContextSize++;
-
-	    if (exprRes != NULL) {
-		xmlXPathReleaseObject(ctxt->context, exprRes);
-		exprRes = NULL;
 	    }
 	    if (ctxt->value == contextObj) {
 		/*
@@ -11627,7 +11636,7 @@
 	return (contextSize);
     } else {
 	xmlDocPtr oldContextDoc;
-	int i, pos = 0, newContextSize = 0, contextPos = 0, isTrue;
+	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
 	xmlXPathStepOpPtr exprOp;
 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
 	xmlNodePtr oldContextNode, contextNode = NULL;
@@ -11679,24 +11688,15 @@
 		    contextNode);
 
 	    valuePush(ctxt, contextObj);
-	    xmlXPathCompOpEval(ctxt, exprOp);
-
-	    if (ctxt->error != XPATH_EXPRESSION_OK)
+	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp);
+	    
+	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
 		goto evaluation_error;
-	    /*
-	    * The result of the evaluation needs to be tested to
-	    * decide whether the filter succeeded or not
-	    */
-	    exprRes = valuePop(ctxt);
-	    /*
-	    * This checks if the result of the evaluate is 'true'.
-	    */
-	    if (xmlXPathEvaluatePredicateResult(ctxt, exprRes)) {
+
+	    if (res)
 		pos++;
-		isTrue =  1;
-	    } else
-		isTrue = 0;
-	    if (isTrue && (pos >= minPos) && (pos <= maxPos)) {
+
+	    if (res && (pos >= minPos) && (pos <= maxPos)) {
 		/*
 		* Fits in the requested range.
 		*/
@@ -11836,7 +11836,8 @@
 static int
 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
                            xmlXPathStepOpPtr op,
-			   xmlNodePtr * first, xmlNodePtr * last)
+			   xmlNodePtr * first, xmlNodePtr * last,
+			   int toBool)
 {
 
 #define XP_TEST_HIT \
@@ -11844,7 +11845,9 @@
 	if (++pos == maxPos) { \
 	    addNode(seq, cur); \
 	goto axis_range_end; } \
-    } else addNode(seq, cur);
+    } else { \
+	addNode(seq, cur); \
+	if (breakOnFirstHit) goto first_hit; }
 
 #define XP_TEST_HIT_NS \
     if (hasAxisRange != 0) { \
@@ -11855,7 +11858,8 @@
     } else { \
 	hasNsNodes = 1; \
 	xmlXPathNodeSetAddNs(seq, \
-	    xpctxt->node, (xmlNsPtr) cur); }
+	xpctxt->node, (xmlNsPtr) cur); \
+	if (breakOnFirstHit) goto first_hit; }
 
     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
@@ -11888,6 +11892,7 @@
     xmlXPathStepOpPtr predOp;
     int maxPos; /* The requested position() (when a "[n]" predicate) */
     int hasPredicateRange, hasAxisRange, pos, size, newSize;
+    int breakOnFirstHit;
 
     xmlXPathTraversalFunction next = NULL;
     /* compound axis traversal */
@@ -12060,6 +12065,7 @@
 	    }	    
 	}
     }
+    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
     /*
     * Axis traversal -----------------------------------------------------
     */
@@ -12125,25 +12131,23 @@
 	    /*
 	    * QUESTION TODO: What does the "first" and "last" stuff do?
 	    */
-            if (first != NULL) {
+            if ((first != NULL) && (*first != NULL)) {
 		if (*first == cur)
 		    break;
-		if ((*first != NULL) &&
-		    ((total % 256) == 0) &&	        
+		if (((total % 256) == 0) &&
 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
 #else
-		    (xmlXPathCmpNodes(*first, cur) >= 0))		
+		    (xmlXPathCmpNodes(*first, cur) >= 0))
 #endif
 		{
 		    break;
 		}
 	    }
-	    if (last != NULL) {
+	    if ((last != NULL) && (*last != NULL)) {
 		if (*last == cur)
 		    break;
-		if ((*last != NULL) &&
-		    ((total % 256) == 0) &&		 
+		if (((total % 256) == 0) &&
 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
 #else
@@ -12292,8 +12296,7 @@
 
 	goto apply_predicates;
 
-axis_range_end: /* ----------------------------------------------------- */
-	
+axis_range_end: /* ----------------------------------------------------- */	
 	/*
 	* We have a "/foo[n]", and position() = n was reached.
 	* Note that we can have as well "/foo/::parent::foo[1]", so
@@ -12304,9 +12307,26 @@
 	    outSeq = seq;
 	    seq = NULL;
 	} else
-	    outSeq = mergeAndClear(outSeq, seq, 0);	
+	    outSeq = mergeAndClear(outSeq, seq, 0);
+	/*
+	* Break if only a true/false result was requested.
+	*/
+	if (toBool)
+	    break;
 	continue;
 
+first_hit: /* ---------------------------------------------------------- */
+	/*
+	* Break if only a true/false result was requested and
+	* no predicates existed and a node test succeeded.
+	*/
+	if (outSeq == NULL) {
+	    outSeq = seq;
+	    seq = NULL;
+	} else
+	    outSeq = mergeAndClear(outSeq, seq, 0);
+	break;
+
 #ifdef DEBUG_STEP
 	if (seq != NULL)
 	    nbMatches += seq->nodeNr;
@@ -12383,6 +12403,11 @@
 		} else
 		    outSeq = mergeAndClear(outSeq, seq,
 			(size != newSize) ? 1: 0);
+		/*
+		* Break if only a true/false result was requested.
+		*/
+		if (toBool)
+		    break;
 	    }
         } else if (seq->nodeNr > 0) {
 	    /*
@@ -12540,7 +12565,7 @@
                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 		CHECK_ERROR0;
 
-                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
+                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
                 return (total);
             }
         case XPATH_OP_VALUE:
@@ -12675,7 +12700,7 @@
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 		CHECK_ERROR0;
 
-                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
+                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
                 return (total);
             }
         case XPATH_OP_VALUE:
@@ -13210,7 +13235,7 @@
                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
 		CHECK_ERROR0;
 
-                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
+                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
                 return (total);
             }
         case XPATH_OP_VALUE:
@@ -13867,6 +13892,95 @@
     return (total);
 }
 
+/**
+ * xmlXPathCompOpEvalToBoolean:
+ * @ctxt:  the XPath parser context
+ *
+ * Evaluates if the expression evaluates to true.
+ *
+ * Returns 1 if true, 0 if false and -1 on API or internal errors.
+ */
+static int
+xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
+			    xmlXPathStepOpPtr op)
+{
+
+start:
+    /* comp = ctxt->comp; */
+    switch (op->op) {
+        case XPATH_OP_END:
+            return (0);
+	case XPATH_OP_VALUE:
+	    if (xmlXPathEvaluatePredicateResult(ctxt,
+		    (xmlXPathObjectPtr) op->value4))
+		{
+		    return(1);
+		} else
+		    return(0);
+	case XPATH_OP_SORT:
+	    /*
+	    * We don't need sorting for boolean results. Skip this one.
+	    */
+            if (op->ch1 != -1) {
+		op = &ctxt->comp->steps[op->ch1];
+		goto start;
+	    }
+	    return(0);
+	case XPATH_OP_COLLECT: {
+	    xmlXPathObjectPtr resObj;
+
+	    if (op->ch1 == -1)
+		return(0);
+
+            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
+	    if (ctxt->error != XPATH_EXPRESSION_OK)
+		return(-1);
+
+            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
+	    if (ctxt->error != XPATH_EXPRESSION_OK)
+		return(-1);
+
+	    resObj = valuePop(ctxt);
+	    if (resObj == NULL)
+		return(-1);
+
+	    if (xmlXPathEvaluatePredicateResult(ctxt, resObj)) {
+		xmlXPathReleaseObject(ctxt->context, resObj);
+		return(1);
+	    } else {
+		xmlXPathReleaseObject(ctxt->context, resObj);
+		return(0);
+	    }            
+	}
+	break;
+	default: {
+	    xmlXPathObjectPtr resObj;
+
+	    /*
+	    * Fallback to call xmlXPathCompOpEval().
+	    */
+	    xmlXPathCompOpEval(ctxt, op);
+	    if (ctxt->error != XPATH_EXPRESSION_OK)
+		return(-1);
+	    
+	    resObj = valuePop(ctxt);
+	    if (resObj == NULL)
+		return(-1);
+	    /*
+	    * This checks if the result of the evaluation is 'true'.
+	    */
+	    if (xmlXPathEvaluatePredicateResult(ctxt, resObj)) {
+		xmlXPathReleaseObject(ctxt->context, resObj);
+		return(1);
+	    } else {
+		xmlXPathReleaseObject(ctxt->context, resObj);
+		return(0);
+	    }
+	}
+    }
+    return(0);
+}
+
 #ifdef XPATH_STREAMING
 /**
  * xmlXPathRunStreamEval:
@@ -13874,53 +13988,61 @@
  *
  * Evaluate the Precompiled Streamable XPath expression in the given context.
  */
-static xmlXPathObjectPtr
-xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
+static int
+xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
+		      xmlXPathObjectPtr *resultSeq, int toBool)
+{
     int max_depth, min_depth;
     int from_root;    
     int ret, depth;
-#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
     int eval_all_nodes;
-#endif
     xmlNodePtr cur = NULL, limit = NULL;
-    xmlXPathObjectPtr retval;
     xmlStreamCtxtPtr patstream;
     
     int nb_nodes = 0;    
 
     if ((ctxt == NULL) || (comp == NULL))
-        return(NULL);
+        return(-1);
     max_depth = xmlPatternMaxDepth(comp);
     if (max_depth == -1)
-        return(NULL);
+        return(-1);
     if (max_depth == -2)
         max_depth = 10000;
     min_depth = xmlPatternMinDepth(comp);
     if (min_depth == -1)
-        return(NULL);
+        return(-1);
     from_root = xmlPatternFromRoot(comp);
     if (from_root < 0)
-        return(NULL);
+        return(-1);
 #if 0
     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
 #endif
 
-    retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
-    if (retval == NULL)
-        return(NULL);
+    if (! toBool) {
+	if (resultSeq == NULL)
+	    return(-1);
+	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
+	if (*resultSeq == NULL)
+	    return(-1);
+    }
     
     /*
      * handle the special cases of / amd . being matched
      */
     if (min_depth == 0) {
 	if (from_root) {
-	    xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
+	    if (toBool)
+		return(1);
+	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
+		(xmlNodePtr) ctxt->doc);
 	} else {
-	    xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
+	    if (toBool)
+		return(1);
+	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
 	}
     }
     if (max_depth == 0) {
-	return(retval);
+	return(0);
     }
 
     if (from_root) {
@@ -13956,23 +14078,27 @@
 	}
 	limit = cur;
     }
-    if (cur == NULL)
-        return(retval);
+    if (cur == NULL) {
+        return(0);
+    }
 
     patstream = xmlPatternGetStreamCtxt(comp);
     if (patstream == NULL) {
-        return(retval);
+	/*
+	* QUESTION TODO: Is this an error?
+	*/
+	return(0);
     }
 
-#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
-#endif
 
     if (from_root) {
 	ret = xmlStreamPush(patstream, NULL, NULL);
 	if (ret < 0) {
 	} else if (ret == 1) {
-	    xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
+	    if (toBool)
+		return(1);
+	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
 	}
     }
     depth = 0;
@@ -13983,27 +14109,24 @@
 
 	switch (cur->type) {
 	    case XML_ELEMENT_NODE:
-#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
 	    case XML_TEXT_NODE:
 	    case XML_CDATA_SECTION_NODE:
 	    case XML_COMMENT_NODE:
-	    case XML_PI_NODE:		
-#endif	    
+	    case XML_PI_NODE:
 		if (cur->type == XML_ELEMENT_NODE) {
 		    ret = xmlStreamPush(patstream, cur->name,
 				(cur->ns ? cur->ns->href : NULL));
-		}
-#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
-		else if (eval_all_nodes)		    
+		} else if (eval_all_nodes)
 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
 		else
 		    break;
-#endif
 		
 		if (ret < 0) {
 		    /* NOP. */
 		} else if (ret == 1) {
-		    xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
+		    if (toBool)
+			return(1);
+		    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
 		}
 		if ((cur->children == NULL) || (depth >= max_depth)) {
 		    ret = xmlStreamPop(patstream);
@@ -14016,8 +14139,8 @@
 		}
 	    default:
 		break;
-	}	    	
-        
+	}
+
 scan_children:
 	if ((cur->children != NULL) && (depth < max_depth)) {
 	    /*
@@ -14051,9 +14174,7 @@
 	        goto done;
 	    if (cur->type == XML_ELEMENT_NODE) {
 		ret = xmlStreamPop(patstream);
-	    }
-#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
-	    else if ((eval_all_nodes) &&
+	    } else if ((eval_all_nodes) &&
 		((cur->type == XML_TEXT_NODE) ||
 		 (cur->type == XML_CDATA_SECTION_NODE) ||
 		 (cur->type == XML_COMMENT_NODE) ||
@@ -14061,7 +14182,6 @@
 	    {
 		ret = xmlStreamPop(patstream);
 	    }
-#endif
 	    if (cur->next != NULL) {
 		cur = cur->next;
 		break;
@@ -14069,28 +14189,33 @@
 	} while (cur != NULL);
 
     } while ((cur != NULL) && (depth >= 0));
+
 done:
+
 #if 0
     printf("stream eval: checked %d nodes selected %d\n",
-           nb_nodes, retval->nodesetval->nodeNr);
+           nb_nodes, retObj->nodesetval->nodeNr);
 #endif
+
     xmlFreeStreamCtxt(patstream);
-    return(retval);
+    return(0);
 }
 #endif /* XPATH_STREAMING */
 
 /**
  * xmlXPathRunEval:
  * @ctxt:  the XPath parser context with the compiled expression
+ * @toBool:  evaluate to a boolean result
  *
  * Evaluate the Precompiled XPath expression in the given context.
  */
-static void
-xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
+static int
+xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
+{
     xmlXPathCompExprPtr comp;
 
     if ((ctxt == NULL) || (ctxt->comp == NULL))
-	return;
+	return(-1);
 
     if (ctxt->valueTab == NULL) {
 	/* Allocate the value stack */
@@ -14106,21 +14231,50 @@
     }
 #ifdef XPATH_STREAMING
     if (ctxt->comp->stream) {
-        xmlXPathObjectPtr ret;
-        ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
-	if (ret != NULL) {
-	    valuePush(ctxt, ret);
-	    return;
+	int res;
+
+	if (toBool) {
+	    /*
+	    * Evaluation to boolean result.
+	    */
+	    res = xmlXPathRunStreamEval(ctxt->context,
+		ctxt->comp->stream, NULL, 1);
+	    if (res != -1)
+		return(res);
+	} else {
+	    xmlXPathObjectPtr resObj = NULL;	
+
+	    /*
+	    * Evaluation to a sequence.
+	    */
+	    res = xmlXPathRunStreamEval(ctxt->context,
+		ctxt->comp->stream, &resObj, 0);
+
+	    if ((res != -1) && (resObj != NULL)) {
+		valuePush(ctxt, resObj);
+		return(0);
+	    }
+	    if (resObj != NULL)
+		xmlXPathReleaseObject(ctxt->context, resObj);	
 	}
+	/*
+	* QUESTION TODO: This falls back to normal XPath evaluation
+	* if res == -1. Is this intended?
+	*/
     }
 #endif
     comp = ctxt->comp;
-    if(comp->last < 0) {
+    if (comp->last < 0) {
 	xmlGenericError(xmlGenericErrorContext,
 	    "xmlXPathRunEval: last is less than zero\n");
-	return;
+	return(-1);
     }
-    xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
+    if (toBool)
+	return(xmlXPathCompOpEvalToBoolean(ctxt, &comp->steps[comp->last]));
+    else
+	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
+
+    return(0);
 }
 
 /************************************************************************
@@ -14203,8 +14357,7 @@
 		return(0);
 	    return(res->nodesetval->nodeNr != 0);
         case XPATH_STRING:
-	    return((res->stringval != NULL) &&
-	           (xmlStrlen(res->stringval) != 0));
+	    return((res->stringval != NULL) && (res->stringval[0] != 0));
 #ifdef LIBXML_XPTR_ENABLED
 	case XPATH_LOCATIONSET:{
 	    xmlLocationSetPtr ptr = res->user;
@@ -14400,12 +14553,13 @@
 	pctxt->comp = NULL;
     }
     xmlXPathFreeParserContext(pctxt);
+
     if (comp != NULL) {
 	comp->expr = xmlStrdup(str);
 #ifdef DEBUG_EVAL_COUNTS
 	comp->string = xmlStrdup(str);
 	comp->nb = 0;
-#endif
+#endif  
 	if ((comp->expr != NULL) &&
 	    (comp->nbStep > 2) &&
 	    (comp->last >= 0) &&
@@ -14432,28 +14586,34 @@
 }
 
 /**
- * xmlXPathCompiledEval:
+ * xmlXPathCompiledEvalInternal:
  * @comp:  the compiled XPath expression
- * @ctx:  the XPath context
+ * @ctxt:  the XPath context
+ * @resObj: the resulting XPath object or NULL
+ * @toBool: 1 if only a boolean result is requested
  *
  * Evaluate the Precompiled XPath expression in the given context.
+ * The caller has to free @resObj.
  *
  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  *         the caller has to free the object.
  */
-xmlXPathObjectPtr
-xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
-    xmlXPathParserContextPtr ctxt;
-    xmlXPathObjectPtr res, tmp, init = NULL;
-    int stack = 0;
+static int
+xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
+			     xmlXPathContextPtr ctxt,
+			     xmlXPathObjectPtr *resObj,
+			     int toBool)
+{
+    xmlXPathParserContextPtr pctxt;    
 #ifndef LIBXML_THREAD_ENABLED
     static int reentance = 0;
 #endif
+    int res;
 
-    CHECK_CTXT(ctx)
+    CHECK_CTXT_NEG(ctxt)
 
     if (comp == NULL)
-	return(NULL);
+	return(-1);
     xmlXPathInit();
 
 #ifndef LIBXML_THREAD_ENABLED
@@ -14469,44 +14629,94 @@
 	comp->nb = 0;
     }
 #endif
-    ctxt = xmlXPathCompParserContext(comp, ctx);
-    xmlXPathRunEval(ctxt);
+    pctxt = xmlXPathCompParserContext(comp, ctxt);
+    res = xmlXPathRunEval(pctxt, toBool);
 
-    if (ctxt->value == NULL) {
-	xmlGenericError(xmlGenericErrorContext,
+    if (resObj) {
+	if (pctxt->value == NULL) {	    
+	    xmlGenericError(xmlGenericErrorContext,
 		"xmlXPathCompiledEval: evaluation failed\n");
-	res = NULL;
-    } else {
-	res = valuePop(ctxt);
+	    *resObj = NULL;	    
+	} else {
+	    *resObj = valuePop(pctxt);
+	}
     }
-
     
-    do {
-        tmp = valuePop(ctxt);
-	if (tmp != NULL) {
-	    if (tmp != init)
-		stack++; 
-	    xmlXPathReleaseObject(ctx, tmp);
-        }
-    } while (tmp != NULL);
-    if ((stack != 0) && (res != NULL)) {
-	xmlGenericError(xmlGenericErrorContext,
-		"xmlXPathCompiledEval: %d object left on the stack\n",
-	        stack);
+    /*
+    * Pop all remaining objects from the stack.
+    */
+    if (pctxt->valueNr > 0) {
+	xmlXPathObjectPtr tmp;
+	int stack = 0;
+
+	do {
+	    tmp = valuePop(pctxt);
+	    if (tmp != NULL) {
+		if (tmp != NULL)
+		    stack++; 
+		xmlXPathReleaseObject(ctxt, tmp);
+	    }
+	} while (tmp != NULL);
+	if ((stack != 0) &&
+	    ((toBool) || ((resObj) && (*resObj))))
+	{
+	    xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathCompiledEval: %d objects left on the stack.\n",
+		stack);
+	}
     }
-    if (ctxt->error != XPATH_EXPRESSION_OK) {
-	xmlXPathFreeObject(res);
-	res = NULL;
+    
+    if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
+	xmlXPathFreeObject(*resObj);
+	*resObj = NULL;
     }        
-    ctxt->comp = NULL;
-    xmlXPathFreeParserContext(ctxt);
+    pctxt->comp = NULL;
+    xmlXPathFreeParserContext(pctxt);
 #ifndef LIBXML_THREAD_ENABLED
     reentance--;
 #endif
+
     return(res);
 }
 
 /**
+ * xmlXPathCompiledEval:
+ * @comp:  the compiled XPath expression
+ * @ctx:  the XPath context
+ *
+ * Evaluate the Precompiled XPath expression in the given context.
+ *
+ * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
+ *         the caller has to free the object.
+ */
+xmlXPathObjectPtr
+xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
+{
+    xmlXPathObjectPtr res = NULL;
+
+    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
+    return(res);
+}
+
+/**
+ * xmlXPathCompiledEvalToBoolean:
+ * @comp:  the compiled XPath expression
+ * @ctxt:  the XPath context
+ *
+ * Applies the XPath boolean() function on the result of the given
+ * compiled expression.
+ *
+ * Returns 1 if the expression evaluated to true, 0 if to false and
+ *         -1 in API and internal errors.
+ */
+int
+xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
+			      xmlXPathContextPtr ctxt)
+{
+    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
+}
+
+/**
  * xmlXPathEvalExpr:
  * @ctxt:  the XPath Parser context
  *
@@ -14548,7 +14758,7 @@
 	}
     }
     CHECK_ERROR;
-    xmlXPathRunEval(ctxt);    
+    xmlXPathRunEval(ctxt, 0);    
 }
 
 /**