1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-07-30 22:43:14 +03:00

- xpath.c xpathInternals.h: applied a large cleaning patch

from TOM <ptittom@free.fr>, it also add namespace support
  for function and variables registration.
Daniel
This commit is contained in:
Daniel Veillard
2000-10-29 18:06:06 +00:00
parent bd20df7951
commit a5db68a39b
4 changed files with 259 additions and 61 deletions

View File

@ -1,3 +1,9 @@
Sun Oct 29 19:03:11 CET 2000 Daniel Veillard <Daniel.Veillard@w3.org>
* xpath.c xpathInternals.h: applied a large cleaning patch
from TOM <ptittom@free.fr>, it also add namespace support
for function and variables registration.
Sun Oct 29 18:51:46 CET 2000 Daniel Veillard <Daniel.Veillard@w3.org> Sun Oct 29 18:51:46 CET 2000 Daniel Veillard <Daniel.Veillard@w3.org>
* uri.c: Wayne Davison's patch fixing xmlBuildURI() * uri.c: Wayne Davison's patch fixing xmlBuildURI()

View File

@ -38,12 +38,23 @@ extern "C" {
#define CHECK_TYPE(typeval) \ #define CHECK_TYPE(typeval) \
if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
XP_ERROR(XPATH_INVALID_TYPE) \ XP_ERROR(XPATH_INVALID_TYPE)
#define CHECK_ARITY(x) \ #define CHECK_ARITY(x) \
if (nargs != (x)) { \ if (nargs != (x)) \
XP_ERROR(XPATH_INVALID_ARITY); \ XP_ERROR(XPATH_INVALID_ARITY);
} \
#define CAST_TO_STRING \
if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) \
xmlXPathStringFunction(ctxt, 1);
#define CAST_TO_NUMBER \
if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) \
xmlXPathNumberFunction(ctxt, 1);
#define CAST_TO_BOOLEAN \
if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)) \
xmlXPathBooleanFunction(ctxt, 1);
void xmlXPatherror (xmlXPathParserContextPtr ctxt, void xmlXPatherror (xmlXPathParserContextPtr ctxt,
const char *file, const char *file,
@ -60,14 +71,28 @@ void xmlXPathDebugDumpObject (FILE *output,
int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt,
const xmlChar *name, const xmlChar *name,
xmlXPathFunction f); xmlXPathFunction f);
int xmlXPathRegisterFuncNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri,
xmlXPathFunction f);
int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt,
const xmlChar *name, const xmlChar *name,
xmlXPathObjectPtr value); xmlXPathObjectPtr value);
int xmlXPathRegisterVariableNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri,
xmlXPathObjectPtr value);
xmlXPathFunction xmlXPathFunctionLookup (xmlXPathContextPtr ctxt, xmlXPathFunction xmlXPathFunctionLookup (xmlXPathContextPtr ctxt,
const xmlChar *name); const xmlChar *name);
xmlXPathFunction xmlXPathFunctionLookupNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri);
void xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt); void xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt);
xmlXPathObjectPtr xmlXPathVariableLookup (xmlXPathContextPtr ctxt, xmlXPathObjectPtr xmlXPathVariableLookup (xmlXPathContextPtr ctxt,
const xmlChar *name); const xmlChar *name);
xmlXPathObjectPtr xmlXPathVariableLookupNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri);
void xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt); void xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt);
/** /**

248
xpath.c
View File

@ -840,6 +840,23 @@ xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
int int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
xmlXPathFunction f) { xmlXPathFunction f) {
return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
}
/**
* xmlXPathRegisterFuncNS:
* @ctxt: the XPath context
* @name: the function name
* @ns_uri: the function namespace URI
* @f: the function implementation or NULL
*
* Register a new function. If @f is NULL it unregisters the function
*
* Returns 0 in case of success, -1 in case of error
*/
int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri, xmlXPathFunction f) {
if (ctxt == NULL) if (ctxt == NULL)
return(-1); return(-1);
if (name == NULL) if (name == NULL)
@ -849,7 +866,7 @@ xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
ctxt->funcHash = xmlHashCreate(0); ctxt->funcHash = xmlHashCreate(0);
if (ctxt->funcHash == NULL) if (ctxt->funcHash == NULL)
return(-1); return(-1);
return(xmlHashAddEntry(ctxt->funcHash, name, (void *) f)); return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
} }
/** /**
@ -864,6 +881,23 @@ xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
*/ */
xmlXPathFunction xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
}
/**
* xmlXPathFunctionLookupNS:
* @ctxt: the XPath context
* @name: the function name
* @ns_uri: the function namespace URI
*
* Search in the Function array of the context for the given
* function.
*
* Returns the xmlXPathFunction or NULL if not found
*/
xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri) {
if (ctxt == NULL) if (ctxt == NULL)
return(NULL); return(NULL);
if (ctxt->funcHash == NULL) if (ctxt->funcHash == NULL)
@ -871,7 +905,7 @@ xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
if (name == NULL) if (name == NULL)
return(NULL); return(NULL);
return((xmlXPathFunction) xmlHashLookup(ctxt->funcHash, name)); return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
} }
/** /**
@ -909,6 +943,25 @@ xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
int int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
xmlXPathObjectPtr value) { xmlXPathObjectPtr value) {
return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
}
/**
* xmlXPathRegisterVariableNS:
* @ctxt: the XPath context
* @name: the variable name
* @ns_uri: the variable namespace URI
* @value: the variable value or NULL
*
* Register a new variable value. If @value is NULL it unregisters
* the variable
*
* Returns 0 in case of success, -1 in case of error
*/
int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri,
xmlXPathObjectPtr value) {
if (ctxt == NULL) if (ctxt == NULL)
return(-1); return(-1);
if (name == NULL) if (name == NULL)
@ -918,8 +971,9 @@ xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
ctxt->varHash = xmlHashCreate(0); ctxt->varHash = xmlHashCreate(0);
if (ctxt->varHash == NULL) if (ctxt->varHash == NULL)
return(-1); return(-1);
return(xmlHashUpdateEntry(ctxt->varHash, name, (void *) value, return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
(xmlHashDeallocator)xmlXPathFreeObject)); (void *) value,
(xmlHashDeallocator)xmlXPathFreeObject));
} }
/** /**
@ -934,6 +988,23 @@ xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
*/ */
xmlXPathObjectPtr xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
return(xmlXPathVariableLookupNS(ctxt, name, NULL));
}
/**
* xmlXPathVariableLookupNS:
* @ctxt: the XPath context
* @name: the variable name
* @ns_uri: the variable namespace URI
*
* Search in the Variable array of the context for the given
* variable value.
*
* Returns the value or NULL if not found
*/
xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri) {
if (ctxt == NULL) if (ctxt == NULL)
return(NULL); return(NULL);
if (ctxt->varHash == NULL) if (ctxt->varHash == NULL)
@ -941,7 +1012,7 @@ xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
if (name == NULL) if (name == NULL)
return(NULL); return(NULL);
return((xmlXPathObjectPtr) xmlHashLookup(ctxt->varHash, name)); return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
} }
/** /**
@ -2648,6 +2719,7 @@ xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the position() XPath function * Implement the position() XPath function
* number position()
* The position function returns the position of the context node in the * The position function returns the position of the context node in the
* context node list. The first position is 1, and so the last positionr * context node list. The first position is 1, and so the last positionr
* will be equal to last(). * will be equal to last().
@ -2672,6 +2744,7 @@ xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the count() XPath function * Implement the count() XPath function
* number count(node-set)
*/ */
void void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
@ -2690,6 +2763,7 @@ xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the id() XPath function * Implement the id() XPath function
* node-set id(object)
* The id function selects elements by their unique ID * The id function selects elements by their unique ID
* (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
* then the result is the union of the result of applying id to the * then the result is the union of the result of applying id to the
@ -2786,6 +2860,7 @@ xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the local-name() XPath function * Implement the local-name() XPath function
* string local-name(node-set?)
* The local-name function returns a string containing the local part * The local-name function returns a string containing the local part
* of the name of the node in the argument node-set that is first in * of the name of the node in the argument node-set that is first in
* document order. If the node-set is empty or the first node has no * document order. If the node-set is empty or the first node has no
@ -2809,7 +2884,16 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
valuePush(ctxt, xmlXPathNewCString("")); valuePush(ctxt, xmlXPathNewCString(""));
} else { } else {
int i = 0; /* Should be first in document order !!!!! */ int i = 0; /* Should be first in document order !!!!! */
valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name)); switch (cur->nodesetval->nodeTab[i]->type) {
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
case XML_PI_NODE:
valuePush(ctxt,
xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
break;
default:
valuePush(ctxt, xmlXPathNewCString(""));
}
} }
xmlXPathFreeObject(cur); xmlXPathFreeObject(cur);
} }
@ -2819,6 +2903,7 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the namespace-uri() XPath function * Implement the namespace-uri() XPath function
* string namespace-uri(node-set?)
* The namespace-uri function returns a string containing the * The namespace-uri function returns a string containing the
* namespace URI of the expanded name of the node in the argument * namespace URI of the expanded name of the node in the argument
* node-set that is first in document order. If the node-set is empty, * node-set that is first in document order. If the node-set is empty,
@ -2842,12 +2927,18 @@ xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
valuePush(ctxt, xmlXPathNewCString("")); valuePush(ctxt, xmlXPathNewCString(""));
} else { } else {
int i = 0; /* Should be first in document order !!!!! */ int i = 0; /* Should be first in document order !!!!! */
switch (cur->nodesetval->nodeTab[i]->type) {
if (cur->nodesetval->nodeTab[i]->ns == NULL) case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
if (cur->nodesetval->nodeTab[i]->ns == NULL)
valuePush(ctxt, xmlXPathNewCString(""));
else
valuePush(ctxt, xmlXPathNewString(
cur->nodesetval->nodeTab[i]->ns->href));
break;
default:
valuePush(ctxt, xmlXPathNewCString("")); valuePush(ctxt, xmlXPathNewCString(""));
else }
valuePush(ctxt, xmlXPathNewString(
cur->nodesetval->nodeTab[i]->ns->href));
} }
xmlXPathFreeObject(cur); xmlXPathFreeObject(cur);
} }
@ -2857,6 +2948,7 @@ xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the name() XPath function * Implement the name() XPath function
* string name(node-set?)
* The name function returns a string containing a QName representing * The name function returns a string containing a QName representing
* the name of the node in the argument node-set that is first in documenti * the name of the node in the argument node-set that is first in documenti
* order. The QName must represent the name with respect to the namespace * order. The QName must represent the name with respect to the namespace
@ -2890,24 +2982,33 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
} else { } else {
int i = 0; /* Should be first in document order !!!!! */ int i = 0; /* Should be first in document order !!!!! */
if (cur->nodesetval->nodeTab[i]->ns == NULL) switch (cur->nodesetval->nodeTab[i]->type) {
valuePush(ctxt, xmlXPathNewString( case XML_ELEMENT_NODE:
cur->nodesetval->nodeTab[i]->name)); case XML_ATTRIBUTE_NODE:
if (cur->nodesetval->nodeTab[i]->ns == NULL)
valuePush(ctxt, xmlXPathNewString(
cur->nodesetval->nodeTab[i]->name));
else { else {
char name[2000]; char name[2000];
#ifdef HAVE_SNPRINTF #ifdef HAVE_SNPRINTF
snprintf(name, sizeof(name), "%s:%s", snprintf(name, sizeof(name), "%s:%s",
(char *) cur->nodesetval->nodeTab[i]->ns->prefix, (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
(char *) cur->nodesetval->nodeTab[i]->name); (char *) cur->nodesetval->nodeTab[i]->name);
#else #else
sprintf(name, "%s:%s", sprintf(name, "%s:%s",
(char *) cur->nodesetval->nodeTab[i]->ns->prefix, (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
(char *) cur->nodesetval->nodeTab[i]->name); (char *) cur->nodesetval->nodeTab[i]->name);
#endif #endif
name[sizeof(name) - 1] = 0; name[sizeof(name) - 1] = 0;
valuePush(ctxt, xmlXPathNewCString(name)); valuePush(ctxt, xmlXPathNewCString(name));
} }
break;
default:
valuePush(ctxt,
xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
xmlXPathLocalNameFunction(ctxt, 1);
}
} }
xmlXPathFreeObject(cur); xmlXPathFreeObject(cur);
} }
@ -2917,6 +3018,7 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the string() XPath function * Implement the string() XPath function
* string string(object?)
* he string function converts an object to a string as follows: * he string function converts an object to a string as follows:
* - A node-set is converted to a string by returning the value of * - A node-set is converted to a string by returning the value of
* the node in the node-set that is first in document order. * the node in the node-set that is first in document order.
@ -3016,6 +3118,7 @@ xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the string-length() XPath function * Implement the string-length() XPath function
* number string-length(string?)
* The string-length returns the number of characters in the string * The string-length returns the number of characters in the string
* (see [3.6 Strings]). If the argument is omitted, it defaults to * (see [3.6 Strings]). If the argument is omitted, it defaults to
* the context node converted to a string, in other words the value * the context node converted to a string, in other words the value
@ -3038,6 +3141,7 @@ xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
return; return;
} }
CHECK_ARITY(1); CHECK_ARITY(1);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING); CHECK_TYPE(XPATH_STRING);
cur = valuePop(ctxt); cur = valuePop(ctxt);
valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval))); valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
@ -3049,6 +3153,7 @@ xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the concat() XPath function * Implement the concat() XPath function
* string concat(string, string, string*)
* The concat function returns the concatenation of its arguments. * The concat function returns the concatenation of its arguments.
*/ */
void void
@ -3060,6 +3165,7 @@ xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(2); CHECK_ARITY(2);
} }
CAST_TO_STRING;
cur = valuePop(ctxt); cur = valuePop(ctxt);
if ((cur == NULL) || (cur->type != XPATH_STRING)) { if ((cur == NULL) || (cur->type != XPATH_STRING)) {
xmlXPathFreeObject(cur); xmlXPathFreeObject(cur);
@ -3068,6 +3174,7 @@ xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
nargs--; nargs--;
while (nargs > 0) { while (nargs > 0) {
CAST_TO_STRING;
newobj = valuePop(ctxt); newobj = valuePop(ctxt);
if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
xmlXPathFreeObject(newobj); xmlXPathFreeObject(newobj);
@ -3089,6 +3196,7 @@ xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the contains() XPath function * Implement the contains() XPath function
* boolean contains(string, string)
* The contains function returns true if the first argument string * The contains function returns true if the first argument string
* contains the second argument string, and otherwise returns false. * contains the second argument string, and otherwise returns false.
*/ */
@ -3097,8 +3205,10 @@ xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr hay, needle; xmlXPathObjectPtr hay, needle;
CHECK_ARITY(2); CHECK_ARITY(2);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING); CHECK_TYPE(XPATH_STRING);
needle = valuePop(ctxt); needle = valuePop(ctxt);
CAST_TO_STRING;
hay = valuePop(ctxt); hay = valuePop(ctxt);
if ((hay == NULL) || (hay->type != XPATH_STRING)) { if ((hay == NULL) || (hay->type != XPATH_STRING)) {
xmlXPathFreeObject(hay); xmlXPathFreeObject(hay);
@ -3118,6 +3228,7 @@ xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the starts-with() XPath function * Implement the starts-with() XPath function
* boolean starts-with(string, string)
* The starts-with function returns true if the first argument string * The starts-with function returns true if the first argument string
* starts with the second argument string, and otherwise returns false. * starts with the second argument string, and otherwise returns false.
*/ */
@ -3127,8 +3238,10 @@ xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
int n; int n;
CHECK_ARITY(2); CHECK_ARITY(2);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING); CHECK_TYPE(XPATH_STRING);
needle = valuePop(ctxt); needle = valuePop(ctxt);
CAST_TO_STRING;
hay = valuePop(ctxt); hay = valuePop(ctxt);
if ((hay == NULL) || (hay->type != XPATH_STRING)) { if ((hay == NULL) || (hay->type != XPATH_STRING)) {
xmlXPathFreeObject(hay); xmlXPathFreeObject(hay);
@ -3149,6 +3262,7 @@ xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the substring() XPath function * Implement the substring() XPath function
* string substring(string, number, number?)
* The substring function returns the substring of the first argument * The substring function returns the substring of the first argument
* starting at the position specified in the second argument with * starting at the position specified in the second argument with
* length specified in the third argument. For example, * length specified in the third argument. For example,
@ -3187,6 +3301,7 @@ xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(3); CHECK_ARITY(3);
} }
if (nargs == 3) { if (nargs == 3) {
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER); CHECK_TYPE(XPATH_NUMBER);
len = valuePop(ctxt); len = valuePop(ctxt);
le = len->floatval; le = len->floatval;
@ -3194,10 +3309,12 @@ xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
} else { } else {
le = 2000000000; le = 2000000000;
} }
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER); CHECK_TYPE(XPATH_NUMBER);
start = valuePop(ctxt); start = valuePop(ctxt);
in = start->floatval; in = start->floatval;
xmlXPathFreeObject(start); xmlXPathFreeObject(start);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING); CHECK_TYPE(XPATH_STRING);
str = valuePop(ctxt); str = valuePop(ctxt);
le += in; le += in;
@ -3240,6 +3357,7 @@ xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the substring-before() XPath function * Implement the substring-before() XPath function
* string substring-before(string, string)
* The substring-before function returns the substring of the first * The substring-before function returns the substring of the first
* argument string that precedes the first occurrence of the second * argument string that precedes the first occurrence of the second
* argument string in the first argument string, or the empty string * argument string in the first argument string, or the empty string
@ -3255,7 +3373,9 @@ xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
int offset; int offset;
CHECK_ARITY(2); CHECK_ARITY(2);
CAST_TO_STRING;
find = valuePop(ctxt); find = valuePop(ctxt);
CAST_TO_STRING;
str = valuePop(ctxt); str = valuePop(ctxt);
target = xmlBufferCreate(); target = xmlBufferCreate();
@ -3278,6 +3398,7 @@ xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the substring-after() XPath function * Implement the substring-after() XPath function
* string substring-after(string, string)
* The substring-after function returns the substring of the first * The substring-after function returns the substring of the first
* argument string that follows the first occurrence of the second * argument string that follows the first occurrence of the second
* argument string in the first argument string, or the empty stringi * argument string in the first argument string, or the empty stringi
@ -3294,7 +3415,9 @@ xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
int offset; int offset;
CHECK_ARITY(2); CHECK_ARITY(2);
CAST_TO_STRING;
find = valuePop(ctxt); find = valuePop(ctxt);
CAST_TO_STRING;
str = valuePop(ctxt); str = valuePop(ctxt);
target = xmlBufferCreate(); target = xmlBufferCreate();
@ -3318,6 +3441,7 @@ xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the normalize-space() XPath function * Implement the normalize-space() XPath function
* string normalize-space(string?)
* The normalize-space function returns the argument string with white * The normalize-space function returns the argument string with white
* space normalized by stripping leading and trailing whitespace * space normalized by stripping leading and trailing whitespace
* and replacing sequences of whitespace characters by a single * and replacing sequences of whitespace characters by a single
@ -3340,6 +3464,7 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
} }
CHECK_ARITY(1); CHECK_ARITY(1);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING); CHECK_TYPE(XPATH_STRING);
obj = valuePop(ctxt); obj = valuePop(ctxt);
source = obj->stringval; source = obj->stringval;
@ -3377,6 +3502,7 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the translate() XPath function * Implement the translate() XPath function
* string translate(string, string, string)
* The translate function returns the first argument string with * The translate function returns the first argument string with
* occurrences of characters in the second argument string replaced * occurrences of characters in the second argument string replaced
* by the character at the corresponding position in the third argument * by the character at the corresponding position in the third argument
@ -3403,8 +3529,11 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(3); CHECK_ARITY(3);
CAST_TO_STRING;
to = valuePop(ctxt); to = valuePop(ctxt);
CAST_TO_STRING;
from = valuePop(ctxt); from = valuePop(ctxt);
CAST_TO_STRING;
str = valuePop(ctxt); str = valuePop(ctxt);
target = xmlBufferCreate(); target = xmlBufferCreate();
@ -3433,6 +3562,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the boolean() XPath function * Implement the boolean() XPath function
* boolean boolean(object)
* he boolean function converts its argument to a boolean as follows: * he boolean function converts its argument to a boolean as follows:
* - a number is true if and only if it is neither positive or * - a number is true if and only if it is neither positive or
* negative zero nor NaN * negative zero nor NaN
@ -3478,12 +3608,14 @@ xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the not() XPath function * Implement the not() XPath function
* boolean not(boolean)
* The not function returns true if its argument is false, * The not function returns true if its argument is false,
* and false otherwise. * and false otherwise.
*/ */
void void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(1); CHECK_ARITY(1);
CAST_TO_BOOLEAN;
CHECK_TYPE(XPATH_BOOLEAN); CHECK_TYPE(XPATH_BOOLEAN);
ctxt->value->boolval = ! ctxt->value->boolval; ctxt->value->boolval = ! ctxt->value->boolval;
} }
@ -3493,6 +3625,7 @@ xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the true() XPath function * Implement the true() XPath function
* boolean true()
*/ */
void void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
@ -3505,6 +3638,7 @@ xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the false() XPath function * Implement the false() XPath function
* boolean false()
*/ */
void void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
@ -3517,6 +3651,7 @@ xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the lang() XPath function * Implement the lang() XPath function
* boolean lang(string)
* The lang function returns true or false depending on whether the * The lang function returns true or false depending on whether the
* language of the context node as specified by xml:lang attributes * language of the context node as specified by xml:lang attributes
* is the same as or is a sublanguage of the language specified by * is the same as or is a sublanguage of the language specified by
@ -3540,6 +3675,7 @@ xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
int i; int i;
CHECK_ARITY(1); CHECK_ARITY(1);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING); CHECK_TYPE(XPATH_STRING);
val = valuePop(ctxt); val = valuePop(ctxt);
lang = val->stringval; lang = val->stringval;
@ -3560,7 +3696,7 @@ not_equal:
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the number() XPath function * Implement the number() XPath function
* * number number(object?)
*/ */
void void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
@ -3622,6 +3758,7 @@ xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the sum() XPath function * Implement the sum() XPath function
* number sum(node-set)
* The sum function returns the sum of the values of the nodes in * The sum function returns the sum of the values of the nodes in
* the argument node-set. * the argument node-set.
*/ */
@ -3654,12 +3791,14 @@ xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the floor() XPath function * Implement the floor() XPath function
* number floor(number)
* The floor function returns the largest (closest to positive infinity) * The floor function returns the largest (closest to positive infinity)
* number that is not greater than the argument and that is an integer. * number that is not greater than the argument and that is an integer.
*/ */
void void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(1); CHECK_ARITY(1);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER); CHECK_TYPE(XPATH_NUMBER);
#if 0 #if 0
ctxt->value->floatval = floor(ctxt->value->floatval); ctxt->value->floatval = floor(ctxt->value->floatval);
@ -3674,6 +3813,7 @@ xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the ceiling() XPath function * Implement the ceiling() XPath function
* number ceiling(number)
* The ceiling function returns the smallest (closest to negative infinity) * The ceiling function returns the smallest (closest to negative infinity)
* number that is not less than the argument and that is an integer. * number that is not less than the argument and that is an integer.
*/ */
@ -3682,6 +3822,7 @@ xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
double f; double f;
CHECK_ARITY(1); CHECK_ARITY(1);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER); CHECK_TYPE(XPATH_NUMBER);
#if 0 #if 0
@ -3698,6 +3839,7 @@ xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
* *
* Implement the round() XPath function * Implement the round() XPath function
* number round(number)
* The round function returns the number that is closest to the * The round function returns the number that is closest to the
* argument and that is an integer. If there are two such numbers, * argument and that is an integer. If there are two such numbers,
* then the one that is even is returned. * then the one that is even is returned.
@ -3707,6 +3849,7 @@ xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
double f; double f;
CHECK_ARITY(1); CHECK_ARITY(1);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER); CHECK_TYPE(XPATH_NUMBER);
if ((ctxt->value->floatval == xmlXPathNAN) || if ((ctxt->value->floatval == xmlXPathNAN) ||
@ -3999,22 +4142,29 @@ xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
void void
xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) { xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
xmlChar *name; xmlChar *name;
xmlChar *prefix;
xmlXPathObjectPtr value; xmlXPathObjectPtr value;
SKIP_BLANKS; SKIP_BLANKS;
if (CUR != '$') { if (CUR != '$') {
XP_ERROR(XPATH_VARIABLE_REF_ERROR); XP_ERROR(XPATH_VARIABLE_REF_ERROR);
} }
name = xmlXPathParseName(ctxt); name = xmlXPathParseQName(ctxt, &prefix);
if (name == NULL) { if (name == NULL) {
XP_ERROR(XPATH_VARIABLE_REF_ERROR); XP_ERROR(XPATH_VARIABLE_REF_ERROR);
} }
value = xmlXPathVariableLookup(ctxt->context, name); if (prefix == NULL) {
value = xmlXPathVariableLookup(ctxt->context, name);
} else {
TODO;
value = NULL;
}
xmlFree(name);
if (prefix != NULL) xmlFree(prefix);
if (value == NULL) { if (value == NULL) {
XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
} }
valuePush(ctxt, value); valuePush(ctxt, value);
xmlFree(name);
SKIP_BLANKS; SKIP_BLANKS;
} }
@ -4048,25 +4198,6 @@ xmlXPathIsNodeType(const xmlChar *name) {
return(0); return(0);
} }
/**
* xmlXPathIsFunction:
* @ctxt: the XPath Parser context
* @name: a name string
*
* Search for a function of the given name
*
* [35] FunctionName ::= QName - NodeType
*
* TODO: for the moment the function list is hardcoded from the spec !!!!
*
* Returns the xmlXPathFunction if found, or NULL otherwise
*/
xmlXPathFunction
xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
return((xmlXPathFunction) xmlHashLookup(ctxt->context->funcHash, name));
}
/** /**
* xmlXPathEvalFunctionCall: * xmlXPathEvalFunctionCall:
* @ctxt: the XPath Parser context * @ctxt: the XPath Parser context
@ -4089,17 +4220,30 @@ xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
XP_ERROR(XPATH_EXPR_ERROR); XP_ERROR(XPATH_EXPR_ERROR);
} }
SKIP_BLANKS; SKIP_BLANKS;
func = xmlXPathIsFunction(ctxt, name); if (prefix == NULL) {
func = xmlXPathFunctionLookup(ctxt->context, name);
} else {
TODO;
func = NULL;
}
if (func == NULL) { if (func == NULL) {
xmlFree(name); xmlFree(name);
if (prefix != NULL) xmlFree(prefix);
XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR); XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
} }
#ifdef DEBUG_EXPR #ifdef DEBUG_EXPR
xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", name); if (prefix == NULL)
xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
name);
else
xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
prefix, name);
#endif #endif
xmlFree(name);
if (prefix != NULL) xmlFree(prefix);
if (CUR != '(') { if (CUR != '(') {
xmlFree(name);
XP_ERROR(XPATH_EXPR_ERROR); XP_ERROR(XPATH_EXPR_ERROR);
} }
NEXT; NEXT;
@ -4110,7 +4254,6 @@ xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
nbargs++; nbargs++;
if (CUR == ')') break; if (CUR == ')') break;
if (CUR != ',') { if (CUR != ',') {
xmlFree(name);
XP_ERROR(XPATH_EXPR_ERROR); XP_ERROR(XPATH_EXPR_ERROR);
} }
NEXT; NEXT;
@ -4118,7 +4261,6 @@ xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
} }
NEXT; NEXT;
SKIP_BLANKS; SKIP_BLANKS;
xmlFree(name);
func(ctxt, nbargs); func(ctxt, nbargs);
} }

View File

@ -38,12 +38,23 @@ extern "C" {
#define CHECK_TYPE(typeval) \ #define CHECK_TYPE(typeval) \
if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
XP_ERROR(XPATH_INVALID_TYPE) \ XP_ERROR(XPATH_INVALID_TYPE)
#define CHECK_ARITY(x) \ #define CHECK_ARITY(x) \
if (nargs != (x)) { \ if (nargs != (x)) \
XP_ERROR(XPATH_INVALID_ARITY); \ XP_ERROR(XPATH_INVALID_ARITY);
} \
#define CAST_TO_STRING \
if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) \
xmlXPathStringFunction(ctxt, 1);
#define CAST_TO_NUMBER \
if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) \
xmlXPathNumberFunction(ctxt, 1);
#define CAST_TO_BOOLEAN \
if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)) \
xmlXPathBooleanFunction(ctxt, 1);
void xmlXPatherror (xmlXPathParserContextPtr ctxt, void xmlXPatherror (xmlXPathParserContextPtr ctxt,
const char *file, const char *file,
@ -60,14 +71,28 @@ void xmlXPathDebugDumpObject (FILE *output,
int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt,
const xmlChar *name, const xmlChar *name,
xmlXPathFunction f); xmlXPathFunction f);
int xmlXPathRegisterFuncNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri,
xmlXPathFunction f);
int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt,
const xmlChar *name, const xmlChar *name,
xmlXPathObjectPtr value); xmlXPathObjectPtr value);
int xmlXPathRegisterVariableNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri,
xmlXPathObjectPtr value);
xmlXPathFunction xmlXPathFunctionLookup (xmlXPathContextPtr ctxt, xmlXPathFunction xmlXPathFunctionLookup (xmlXPathContextPtr ctxt,
const xmlChar *name); const xmlChar *name);
xmlXPathFunction xmlXPathFunctionLookupNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri);
void xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt); void xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt);
xmlXPathObjectPtr xmlXPathVariableLookup (xmlXPathContextPtr ctxt, xmlXPathObjectPtr xmlXPathVariableLookup (xmlXPathContextPtr ctxt,
const xmlChar *name); const xmlChar *name);
xmlXPathObjectPtr xmlXPathVariableLookupNS (xmlXPathContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri);
void xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt); void xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt);
/** /**