summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@src.gnome.org>1999-08-15 23:32:28 +0000
committerDaniel Veillard <veillard@src.gnome.org>1999-08-15 23:32:28 +0000
commit991e63d9cb0e9a4f65950ec67f56091a14289404 (patch)
treefc5b5698c2b2c2149294d599cfb1b1ef53e0b1d5
parentb556eb58649b0f59d55acd6a99e56ed1bf4c97e5 (diff)
downloadlibxml2-991e63d9cb0e9a4f65950ec67f56091a14289404.tar.gz
More validity stuff (ID) and corrct version of equal and compare for XPath, Daniel
-rw-r--r--ChangeLog6
-rw-r--r--include/libxml/tree.h12
-rw-r--r--include/libxml/valid.h20
-rw-r--r--tree.h12
-rw-r--r--valid.c194
-rw-r--r--valid.h20
-rw-r--r--xpath.c364
7 files changed, 581 insertions, 47 deletions
diff --git a/ChangeLog b/ChangeLog
index 1b4b8ebd..66303d09 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Mon Aug 16 03:27:38 CEST 1999
+
+ * tree.h, valid.c, valid.h: more work on validity, IDs
+ * xpath.c: added/fixed comparidon and equlity, added a new isinf
+ definition for AIX
+
Sun Aug 15 21:15:17 CEST 1999 Daniel Veillard <Daniel.Veillard@w3.org>
* Makefile.am libxml.spec.in: corrected missing xmlConf.sh in
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index a627d921..fa70ba37 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -197,6 +197,17 @@ typedef struct xmlAttr {
typedef xmlAttr *xmlAttrPtr;
/*
+ * An XML ID instance.
+ */
+
+typedef struct xmlID {
+ struct xmlID *next; /* next ID */
+ const CHAR *value; /* The ID name */
+ xmlAttrPtr attr; /* The attribut holding it */
+} xmlID;
+typedef xmlID *xmlIDPtr;
+
+/*
* A node in an XML tree.
*/
typedef struct xmlNode {
@@ -238,6 +249,7 @@ typedef struct xmlDoc {
struct xmlDtd *extSubset; /* the document external subset */
struct xmlNs *oldNs; /* Global namespace, the old way */
struct xmlNode *root; /* the document tree */
+ void *ids; /* Hash table for ID attributes if any */
} _xmlDoc;
typedef _xmlDoc xmlDoc;
typedef xmlDoc *xmlDocPtr;
diff --git a/include/libxml/valid.h b/include/libxml/valid.h
index 7d58459e..9afb2a0e 100644
--- a/include/libxml/valid.h
+++ b/include/libxml/valid.h
@@ -69,6 +69,20 @@ typedef struct xmlAttributeTable {
} xmlAttributeTable;
typedef xmlAttributeTable *xmlAttributeTablePtr;
+/*
+ * ALl IDs attributes are stored in a table
+ * there is one table per document
+ */
+
+#define XML_MIN_ID_TABLE 32
+
+typedef struct xmlIDTable {
+ int nb_ids; /* number of ids stored */
+ int max_ids; /* maximum number of ids */
+ xmlIDPtr *table; /* the table of ids */
+} xmlIDTable;
+typedef xmlIDTable *xmlIDTablePtr;
+
/* Notation */
xmlNotationPtr xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
const CHAR *name, const CHAR *PublicID, const CHAR *SystemID);
@@ -101,6 +115,12 @@ xmlAttributeTablePtr xmlCopyAttributeTable(xmlAttributeTablePtr table);
void xmlFreeAttributeTable(xmlAttributeTablePtr table);
void xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table);
+/* IDs */
+xmlIDPtr xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+ const CHAR *value, xmlAttrPtr attr);
+xmlIDTablePtr xmlCopyIDTable(xmlIDTablePtr table);
+void xmlFreeIDTable(xmlIDTablePtr table);
+
/**
* The public function calls related to validity checking
*/
diff --git a/tree.h b/tree.h
index a627d921..fa70ba37 100644
--- a/tree.h
+++ b/tree.h
@@ -197,6 +197,17 @@ typedef struct xmlAttr {
typedef xmlAttr *xmlAttrPtr;
/*
+ * An XML ID instance.
+ */
+
+typedef struct xmlID {
+ struct xmlID *next; /* next ID */
+ const CHAR *value; /* The ID name */
+ xmlAttrPtr attr; /* The attribut holding it */
+} xmlID;
+typedef xmlID *xmlIDPtr;
+
+/*
* A node in an XML tree.
*/
typedef struct xmlNode {
@@ -238,6 +249,7 @@ typedef struct xmlDoc {
struct xmlDtd *extSubset; /* the document external subset */
struct xmlNs *oldNs; /* Global namespace, the old way */
struct xmlNode *root; /* the document tree */
+ void *ids; /* Hash table for ID attributes if any */
} _xmlDoc;
typedef _xmlDoc xmlDoc;
typedef xmlDoc *xmlDocPtr;
diff --git a/valid.c b/valid.c
index b23824f3..25ad9d53 100644
--- a/valid.c
+++ b/valid.c
@@ -1306,6 +1306,200 @@ xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
/************************************************************************
* *
+ * NOTATIONs *
+ * *
+ ************************************************************************/
+/**
+ * xmlCreateIDTable:
+ *
+ * create and initialize an empty id hash table.
+ *
+ * Returns the xmlIDTablePtr just created or NULL in case
+ * of error.
+ */
+xmlIDTablePtr
+xmlCreateIDTable(void) {
+ xmlIDTablePtr ret;
+
+ ret = (xmlIDTablePtr)
+ malloc(sizeof(xmlIDTable));
+ if (ret == NULL) {
+ fprintf(stderr, "xmlCreateIDTable : malloc(%ld) failed\n",
+ (long)sizeof(xmlIDTable));
+ return(NULL);
+ }
+ ret->max_ids = XML_MIN_NOTATION_TABLE;
+ ret->nb_ids = 0;
+ ret->table = (xmlIDPtr *)
+ malloc(ret->max_ids * sizeof(xmlIDPtr));
+ if (ret == NULL) {
+ fprintf(stderr, "xmlCreateIDTable : malloc(%ld) failed\n",
+ ret->max_ids * (long)sizeof(xmlID));
+ free(ret);
+ return(NULL);
+ }
+ return(ret);
+}
+
+
+/**
+ * xmlAddID:
+ * @ctxt: the validation context
+ * @doc: pointer to the document
+ * @value: the value name
+ * @attr: the attribute holding the ID
+ *
+ * Register a new id declaration
+ *
+ * Returns NULL if not, othervise the new xmlIDPtr
+ */
+xmlIDPtr
+xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
+ xmlAttrPtr attr) {
+ xmlIDPtr ret, cur;
+ xmlIDTablePtr table;
+ int i;
+
+ if (doc == NULL) {
+ fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
+ return(NULL);
+ }
+ if (value == NULL) {
+ fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
+ return(NULL);
+ }
+ if (attr == NULL) {
+ fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
+ return(NULL);
+ }
+
+ /*
+ * Create the ID table if needed.
+ */
+ table = doc->ids;
+ if (table == NULL)
+ table = doc->ids = xmlCreateIDTable();
+ if (table == NULL) {
+ fprintf(stderr, "xmlAddID: Table creation failed!\n");
+ return(NULL);
+ }
+
+ /*
+ * Validity Check:
+ * Search the DTD for previous declarations of the ATTLIST
+ */
+ for (i = 0;i < table->nb_ids;i++) {
+ cur = table->table[i];
+ if (!xmlStrcmp(cur->value, value)) {
+ /*
+ * The id is already defined in this Dtd.
+ */
+ VERROR(ctxt->userData, "ID %s already defined\n", value);
+ return(NULL);
+ }
+ }
+
+ /*
+ * Grow the table, if needed.
+ */
+ if (table->nb_ids >= table->max_ids) {
+ /*
+ * need more ids.
+ */
+ table->max_ids *= 2;
+ table->table = (xmlIDPtr *)
+ realloc(table->table, table->max_ids *
+ sizeof(xmlIDPtr));
+ if (table->table == NULL) {
+ fprintf(stderr, "xmlAddID: out of memory\n");
+ return(NULL);
+ }
+ }
+ ret = (xmlIDPtr) malloc(sizeof(xmlID));
+ if (ret == NULL) {
+ fprintf(stderr, "xmlAddID: out of memory\n");
+ return(NULL);
+ }
+ table->table[table->nb_ids] = ret;
+
+ /*
+ * fill the structure.
+ */
+ ret->value = xmlStrdup(value);
+ ret->attr = attr;
+ table->nb_ids++;
+
+ return(ret);
+}
+
+/**
+ * xmlFreeID:
+ * @not: A id
+ *
+ * Deallocate the memory used by an id definition
+ */
+void
+xmlFreeID(xmlIDPtr id) {
+ if (id == NULL) return;
+ if (id->value != NULL)
+ free((CHAR *) id->value);
+ memset(id, -1, sizeof(xmlID));
+ free(id);
+}
+
+/**
+ * xmlFreeIDTable:
+ * @table: An id table
+ *
+ * Deallocate the memory used by an ID hash table.
+ */
+void
+xmlFreeIDTable(xmlIDTablePtr table) {
+ int i;
+
+ if (table == NULL) return;
+
+ for (i = 0;i < table->nb_ids;i++) {
+ xmlFreeID(table->table[i]);
+ }
+ free(table->table);
+ free(table);
+}
+
+/**
+ * xmlIsID
+ * @doc: the document
+ * @elem: the element carrying the attribute
+ * @attr: the attribute
+ *
+ * Determine whether an attribute is of type ID. In case we have Dtd(s)
+ * then this is simple, otherwise we use an heuristic: name ID (upper
+ * or lowercase).
+ *
+ * Returns 0 or 1 depending on the lookup result
+ */
+int
+xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
+ if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
+ if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
+ ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
+ (attr->name[2] == 0)) return(1);
+ } else {
+ xmlAttributePtr attrDecl;
+
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
+ attr->name);
+
+ if ((attrDecl == NULL) || (attrDecl->type == XML_ATTRIBUTE_ID))
+ return(1);
+ }
+ return(0);
+}
+
+/************************************************************************
+ * *
* Routines for validity checking *
* *
************************************************************************/
diff --git a/valid.h b/valid.h
index 7d58459e..9afb2a0e 100644
--- a/valid.h
+++ b/valid.h
@@ -69,6 +69,20 @@ typedef struct xmlAttributeTable {
} xmlAttributeTable;
typedef xmlAttributeTable *xmlAttributeTablePtr;
+/*
+ * ALl IDs attributes are stored in a table
+ * there is one table per document
+ */
+
+#define XML_MIN_ID_TABLE 32
+
+typedef struct xmlIDTable {
+ int nb_ids; /* number of ids stored */
+ int max_ids; /* maximum number of ids */
+ xmlIDPtr *table; /* the table of ids */
+} xmlIDTable;
+typedef xmlIDTable *xmlIDTablePtr;
+
/* Notation */
xmlNotationPtr xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
const CHAR *name, const CHAR *PublicID, const CHAR *SystemID);
@@ -101,6 +115,12 @@ xmlAttributeTablePtr xmlCopyAttributeTable(xmlAttributeTablePtr table);
void xmlFreeAttributeTable(xmlAttributeTablePtr table);
void xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table);
+/* IDs */
+xmlIDPtr xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+ const CHAR *value, xmlAttrPtr attr);
+xmlIDTablePtr xmlCopyIDTable(xmlIDTablePtr table);
+void xmlFreeIDTable(xmlIDTablePtr table);
+
/**
* The public function calls related to validity checking
*/
diff --git a/xpath.c b/xpath.c
index 172dd5c4..cff0e82b 100644
--- a/xpath.c
+++ b/xpath.c
@@ -34,6 +34,7 @@
/*
* Setup stuff for floating point
+ * The lack of portability of this section of the libc is annoying !
*/
double xmlXPathNAN = 0;
double xmlXPathPINF = 1;
@@ -88,7 +89,16 @@ int isinf(double d) {
}
#elif defined(finite) || defined(HAVE_FINITE)
int isinf(double x) { return !finite(x) && x==x; }
-#endif /* ! HAVE_FPCLASS */
+#elif defined(HUGE_VAL)
+static int isinf(double x)
+{
+ if (x == HUGE_VAL)
+ return(1);
+ if (x == -HUGE_VAL)
+ return(-1);
+ return(0);
+}
+#endif
#endif /* ! HAVE_ISINF */
#endif /* ! defined(isinf) */
@@ -310,6 +320,10 @@ xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
{ xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
ctxt->error = (X); return; }
+#define ERROR0(X) \
+ { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
+ ctxt->error = (X); return(0); }
+
#define CHECK_TYPE(typeval) \
if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
ERROR(XPATH_INVALID_TYPE) \
@@ -875,69 +889,272 @@ void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
}
/**
+ * xmlXPathEqualNodeSetString
+ * @arg: the nodeset object argument
+ * @str: the string to compare to.
+ *
+ * Implement the equal operation on XPath objects content: @arg1 == @arg2
+ * If one object to be compared is a node-set and the other is a string,
+ * then the comparison will be true if and only if there is a node in
+ * the node-set such that the result of performing the comparison on the
+ * string-value of the node and the other string is true.
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const CHAR *str) {
+ int i;
+ xmlNodeSetPtr ns;
+ CHAR *str2;
+
+ if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
+ return(0);
+ ns = arg->nodesetval;
+ for (i = 0;i < ns->nodeNr;i++) {
+ str2 = xmlNodeGetContent(ns->nodeTab[i]);
+ if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
+ free(str2);
+ return(1);
+ }
+ free(str2);
+ }
+ return(0);
+}
+
+/**
+ * xmlXPathEqualNodeSetFloat
+ * @arg: the nodeset object argument
+ * @f: the float to compare to
+ *
+ * Implement the equal operation on XPath objects content: @arg1 == @arg2
+ * If one object to be compared is a node-set and the other is a number,
+ * then the comparison will be true if and only if there is a node in
+ * the node-set such that the result of performing the comparison on the
+ * number to be compared and on the result of converting the string-value
+ * of that node to a number using the number function is true.
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
+ CHAR buf[100] = "";
+
+ if ((arg == NULL) || (arg->type != XPATH_NODESET))
+ return(0);
+
+ if (isnan(f))
+ sprintf(buf, "NaN");
+ else if (isinf(f) > 0)
+ sprintf(buf, "+Infinity");
+ else if (isinf(f) < 0)
+ sprintf(buf, "-Infinity");
+ else
+ sprintf(buf, "%0g", f);
+
+ return(xmlXPathEqualNodeSetString(arg, buf));
+}
+
+
+/**
+ * xmlXPathEqualNodeSets
+ * @arg1: first nodeset object argument
+ * @arg2: second nodeset object argument
+ *
+ * Implement the equal operation on XPath nodesets: @arg1 == @arg2
+ * If both objects to be compared are node-sets, then the comparison
+ * will be true if and only if there is a node in the first node-set and
+ * a node in the second node-set such that the result of performing the
+ * comparison on the string-values of the two nodes is true.
+ *
+ * (needless to say, this is a costly operation)
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
+ int i;
+ xmlNodeSetPtr ns;
+ CHAR *str;
+
+ if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
+ return(0);
+ if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
+ return(0);
+
+ ns = arg1->nodesetval;
+ for (i = 0;i < ns->nodeNr;i++) {
+ str = xmlNodeGetContent(ns->nodeTab[i]);
+ if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
+ free(str);
+ return(1);
+ }
+ free(str);
+ }
+ return(0);
+}
+
+/**
* xmlXPathEqualValues:
- * @arg1: first XPath object argument
- * @arg2: second XPath object argument
+ * @ctxt: the XPath Parser context
*
* Implement the equal operation on XPath objects content: @arg1 == @arg2
*
* Returns 0 or 1 depending on the results of the test.
- * TODO: rewrite using the stack for evaluation
*/
int
-xmlXPathEqualValues(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
+xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr arg1, arg2;
+ int ret = 0;
+
+ arg1 = valuePop(ctxt);
+ if (arg1 == NULL)
+ ERROR0(XPATH_INVALID_OPERAND);
+
+ arg2 = valuePop(ctxt);
+ if (arg2 == NULL) {
+ xmlXPathFreeObject(arg1);
+ ERROR0(XPATH_INVALID_OPERAND);
+ }
+
if (arg1 == arg2) {
#ifdef DEBUG_EXPR
fprintf(xmlXPathDebug, "Equal: by pointer\n");
#endif
return(1);
}
- if ((arg1 == NULL) || (arg2 == NULL)) {
-#ifdef DEBUG_EXPR
- fprintf(xmlXPathDebug, "Equal: arg NULL\n");
-#endif
- return(0);
- }
- if (arg1->type != arg2->type) {
- /* TODO : see 4.3 Boolean section !!!!!!!!!!! */
-#ifdef DEBUG_EXPR
- fprintf(xmlXPathDebug, "Equal: distinct types\n");
-#endif
- return(0);
- }
+
switch (arg1->type) {
case XPATH_UNDEFINED:
#ifdef DEBUG_EXPR
fprintf(xmlXPathDebug, "Equal: undefined\n");
#endif
- return(0);
+ break;
case XPATH_NODESET:
- TODO /* compare nodesets */
+ switch (arg2->type) {
+ case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+ fprintf(xmlXPathDebug, "Equal: undefined\n");
+#endif
+ break;
+ case XPATH_NODESET:
+ ret = xmlXPathEqualNodeSets(arg1, arg2);
+ break;
+ case XPATH_BOOLEAN:
+ if ((arg1->nodesetval == NULL) ||
+ (arg1->nodesetval->nodeNr == 0)) ret = 0;
+ else
+ ret = 1;
+ ret = (ret == arg2->boolval);
+ break;
+ case XPATH_NUMBER:
+ ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
+ break;
+ case XPATH_STRING:
+ ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
+ break;
+ }
break;
case XPATH_BOOLEAN:
+ switch (arg2->type) {
+ case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+ fprintf(xmlXPathDebug, "Equal: undefined\n");
+#endif
+ break;
+ case XPATH_NODESET:
+ if ((arg2->nodesetval == NULL) ||
+ (arg2->nodesetval->nodeNr == 0)) ret = 0;
+ else
+ ret = 1;
+ break;
+ case XPATH_BOOLEAN:
#ifdef DEBUG_EXPR
- fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
- arg1->boolval, arg2->boolval);
+ fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
+ arg1->boolval, arg2->boolval);
#endif
- return(arg1->boolval == arg2->boolval);
+ ret = (arg1->boolval == arg2->boolval);
+ break;
+ case XPATH_NUMBER:
+ if (arg2->floatval) ret = 1;
+ else ret = 0;
+ ret = (arg1->boolval == ret);
+ break;
+ case XPATH_STRING:
+ if ((arg2->stringval == NULL) ||
+ (arg2->stringval[0] == 0)) ret = 0;
+ else
+ ret = 1;
+ ret = (arg1->boolval == ret);
+ break;
+ }
+ break;
case XPATH_NUMBER:
+ switch (arg2->type) {
+ case XPATH_UNDEFINED:
#ifdef DEBUG_EXPR
- fprintf(xmlXPathDebug, "Equal: %f number %f \n",
- arg1->floatval, arg2->floatval);
+ fprintf(xmlXPathDebug, "Equal: undefined\n");
#endif
- return(arg1->floatval == arg2->floatval);
+ break;
+ case XPATH_NODESET:
+ ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
+ break;
+ case XPATH_BOOLEAN:
+ if (arg1->floatval) ret = 1;
+ else ret = 0;
+ ret = (arg2->boolval == ret);
+ break;
+ case XPATH_STRING:
+ valuePush(ctxt, arg2);
+ xmlXPathNumberFunction(ctxt, 1);
+ arg2 = valuePop(ctxt);
+ /* no break on purpose */
+ case XPATH_NUMBER:
+ ret = (arg1->floatval == arg2->floatval);
+ break;
+ }
+ break;
case XPATH_STRING:
+ switch (arg2->type) {
+ case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+ fprintf(xmlXPathDebug, "Equal: undefined\n");
+#endif
+ break;
+ case XPATH_NODESET:
+ ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
+ break;
+ case XPATH_BOOLEAN:
+ if ((arg1->stringval == NULL) ||
+ (arg1->stringval[0] == 0)) ret = 0;
+ else
+ ret = 1;
+ ret = (arg2->boolval == ret);
+ break;
+ case XPATH_STRING:
+ ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
+ break;
+ case XPATH_NUMBER:
+ valuePush(ctxt, arg1);
+ xmlXPathNumberFunction(ctxt, 1);
+ arg1 = valuePop(ctxt);
+ ret = (arg1->floatval == arg2->floatval);
+ break;
+ }
+ break;
#ifdef DEBUG_EXPR
fprintf(xmlXPathDebug, "Equal: %s string %s \n",
arg1->stringval, arg2->stringval);
#endif
- return(!xmlStrcmp(arg1->stringval, arg2->stringval));
+ ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
}
- return(1);
+ xmlXPathFreeObject(arg1);
+ xmlXPathFreeObject(arg2);
+ return(ret);
}
/**
* xmlXPathCompareValues:
+ * @ctxt: the XPath Parser context
* @inf: less than (1) or greater than (2)
* @strict: is the comparison strict
*
@@ -947,11 +1164,71 @@ xmlXPathEqualValues(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
* @arg1 > @arg2 (0, 1, ...
* @arg1 >= @arg2 (0, 0, ...
*
+ * When neither object to be compared is a node-set and the operator is
+ * <=, <, >=, >, then the objects are compared by converted both objects
+ * to numbers and comparing the numbers according to IEEE 754. The <
+ * comparison will be true if and only if the first number is less than the
+ * second number. The <= comparison will be true if and only if the first
+ * number is less than or equal to the second number. The > comparison
+ * will be true if and only if the first number is greater than the second
+ * number. The >= comparison will be true if and only if the first number
+ * is greater than or equal to the second number.
*/
int
-xmlXPathCompareValues(int inf, int strict) {
- TODO /* compare */
- return(0);
+xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
+ int ret = 0;
+ xmlXPathObjectPtr arg1, arg2;
+
+ arg2 = valuePop(ctxt);
+ if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
+ if (arg2 != NULL)
+ xmlXPathFreeObject(arg2);
+ ERROR0(XPATH_INVALID_OPERAND);
+ }
+
+ arg1 = valuePop(ctxt);
+ if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
+ if (arg1 != NULL)
+ xmlXPathFreeObject(arg1);
+ xmlXPathFreeObject(arg2);
+ ERROR0(XPATH_INVALID_OPERAND);
+ }
+
+ if (arg1->type != XPATH_NUMBER) {
+ valuePush(ctxt, arg1);
+ xmlXPathNumberFunction(ctxt, 1);
+ arg1 = valuePop(ctxt);
+ }
+ if (arg1->type != XPATH_NUMBER) {
+ xmlXPathFreeObject(arg1);
+ xmlXPathFreeObject(arg2);
+ ERROR0(XPATH_INVALID_OPERAND);
+ }
+ if (arg2->type != XPATH_NUMBER) {
+ valuePush(ctxt, arg2);
+ xmlXPathNumberFunction(ctxt, 1);
+ arg2 = valuePop(ctxt);
+ }
+ if (arg2->type != XPATH_NUMBER) {
+ xmlXPathFreeObject(arg1);
+ xmlXPathFreeObject(arg2);
+ ERROR0(XPATH_INVALID_OPERAND);
+ }
+ /*
+ * Add tests for infinity and nan
+ * => feedback on 3.4 for Inf and NaN
+ */
+ if (inf && strict)
+ ret = (arg1->floatval < arg2->floatval);
+ else if (inf && !strict)
+ ret = (arg1->floatval <= arg2->floatval);
+ else if (!inf && strict)
+ ret = (arg1->floatval > arg2->floatval);
+ else if (!inf && !strict)
+ ret = (arg1->floatval >= arg2->floatval);
+ xmlXPathFreeObject(arg1);
+ xmlXPathFreeObject(arg2);
+ return(ret);
}
/**
@@ -1416,8 +1693,11 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
*/
xmlAttrPtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
- if (cur == NULL)
+ if (cur == NULL) {
+ if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
+ return(NULL);
return(ctxt->context->node->properties);
+ }
return(cur->next);
}
@@ -3005,13 +3285,6 @@ xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
CHECK_TYPE(XPATH_NODESET);
- /******
- TODO: transition from PathExpr to Expr using paths ...
- arg = valuePop(ctxt);
- oldset = ctxt->context->nodeset;
- ctxt->context->nodeset = arg->nodesetval;
- ******/
-
while (CUR == '[') {
xmlXPathEvalPredicate(ctxt);
}
@@ -3230,7 +3503,7 @@ xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
(CUR == '>') ||
((CUR == '<') && (NXT(1) == '=')) ||
((CUR == '>') && (NXT(1) == '='))) {
- int inf, strict;
+ int inf, strict, ret;
if (CUR == '<') inf = 1;
else inf = 0;
@@ -3240,7 +3513,8 @@ xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
if (!strict) NEXT;
xmlXPathEvalAdditiveExpr(ctxt);
CHECK_ERROR;
- xmlXPathCompareValues(inf, strict);
+ ret = xmlXPathCompareValues(ctxt, inf, strict);
+ valuePush(ctxt, xmlXPathNewBoolean(ret));
}
}
@@ -3265,7 +3539,7 @@ xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathEvalRelationalExpr(ctxt);
CHECK_ERROR;
while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
- xmlXPathObjectPtr arg1, arg2, res;
+ xmlXPathObjectPtr res;
int eq, equal;
if (CUR == '=') eq = 1;
@@ -3274,14 +3548,10 @@ xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
if (!eq) NEXT;
xmlXPathEvalRelationalExpr(ctxt);
CHECK_ERROR;
- arg2 = valuePop(ctxt);
- arg1 = valuePop(ctxt);
- equal = xmlXPathEqualValues(arg1, arg2);
+ equal = xmlXPathEqualValues(ctxt);
if (eq) res = xmlXPathNewBoolean(equal);
else res = xmlXPathNewBoolean(!equal);
valuePush(ctxt, res);
- xmlXPathFreeObject(arg1);
- xmlXPathFreeObject(arg2);
}
}