From 2d38f047073a0c988a078f1536658b80e1cb4ee1 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 11 Oct 2000 10:54:10 +0000 Subject: [PATCH] - xpath.[ch] xpointer.[ch]: worked on XPath functions and variable handlings (registration, lookup, cleanup) Daniel --- ChangeLog | 5 + configure.in | 4 +- include/libxml/xpath.h | 16 +- include/libxml/xpointer.h | 9 +- xpath.c | 309 +++++++++++++++++++++++++++++++++++--- xpath.h | 16 +- xpointer.c | 43 +----- xpointer.h | 9 +- 8 files changed, 331 insertions(+), 80 deletions(-) diff --git a/ChangeLog b/ChangeLog index a729636e..035aeeff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Oct 11 12:41:30 CEST 2000 Daniel Veillard + + * xpath.[ch] xpointer.[ch]: worked on XPath functions and variable + handlings (registration, lookup, cleanup) + Wed Oct 11 01:46:44 CEST 2000 Daniel Veillard * configure.in Makefile.am include/makefile.am: adding XPointer diff --git a/configure.in b/configure.in index 28b4685e..ede84f5c 100644 --- a/configure.in +++ b/configure.in @@ -311,7 +311,7 @@ dnl create the libxml and include links needed to get dependencies right dnl if test ! -d $srcdir/include/libxml then - if [ ! -d $srcdir/include ] + if test ! -d $srcdir/include then rm -f $srcdir/include mkdir $srcdir/include @@ -325,7 +325,7 @@ then fi if test ! -e include/libxml then - if [ ! -d include ] + if test ! -d include then rm -f include mkdir include diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h index 98455783..533ca3fc 100644 --- a/include/libxml/xpath.h +++ b/include/libxml/xpath.h @@ -288,6 +288,7 @@ void xmlXPathIdFunction (xmlXPathParserContextPtr ctxt, int nargs); void xmlXPathRoot (xmlXPathParserContextPtr ctxt); void xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); +xmlChar * xmlXPathParseName (xmlXPathParserContextPtr ctxt); /************************************************************************ * * @@ -296,20 +297,14 @@ void xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); ************************************************************************/ /** - * Registering extensions to the expression language + * Extending a context */ -/* TODO */ int xmlXPathRegisterType (xmlXPathContextPtr ctxt, - const xmlChar *name, - xmlXPathConvertFunc f); -/* TODO */ int xmlXPathRegisterAxis (xmlXPathContextPtr ctxt, - const xmlChar *name, - xmlXPathAxisFunc f); -/* TODO */ int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, +int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, const xmlChar *name, xmlXPathFunction f); -/* TODO */ int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, +int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, const xmlChar *name, - xmlXPathObject value); + xmlXPathObjectPtr value); /** * Evaluation functions. @@ -327,6 +322,7 @@ xmlXPathObjectPtr xmlXPathEvalExpression (const xmlChar *str, xmlNodeSetPtr xmlXPathNodeSetCreate (xmlNodePtr val); void xmlXPathFreeNodeSetList (xmlXPathObjectPtr obj); void xmlXPathFreeNodeSet (xmlNodeSetPtr obj); +xmlXPathObjectPtr xmlXPathObjectCopy (xmlXPathObjectPtr val); #ifdef __cplusplus diff --git a/include/libxml/xpointer.h b/include/libxml/xpointer.h index 927cdfb7..39216876 100644 --- a/include/libxml/xpointer.h +++ b/include/libxml/xpointer.h @@ -30,6 +30,14 @@ struct _xmlLocationSet { xmlXPathObjectPtr *locTab;/* array of locations */ }; +/* + * Handling of location sets + */ + +void xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); +xmlLocationSetPtr xmlXPtrLocationSetMerge (xmlLocationSetPtr val1, + xmlLocationSetPtr val2); + /* * Functions */ @@ -40,7 +48,6 @@ xmlXPathObjectPtr xmlXPtrEval (const xmlChar *str, xmlXPathContextPtr ctx); void xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, int nargs); -void xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); #ifdef __cplusplus } diff --git a/xpath.c b/xpath.c index 1d307551..83b70875 100644 --- a/xpath.c +++ b/xpath.c @@ -413,10 +413,11 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { /** * xmlXPathNodeSetMerge: - * @val1: the first NodeSet + * @val1: the first NodeSet or NULL * @val2: the second NodeSet * * Merges two nodesets, all nodes from @val2 are added to @val1 + * if @val1 is NULL, a new set is created and copied from @val2 * * Returns val1 once extended or NULL in case of error. */ @@ -424,8 +425,10 @@ xmlNodeSetPtr xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { int i; - if (val1 == NULL) return(NULL); if (val2 == NULL) return(val1); + if (val1 == NULL) { + val1 = xmlXPathNodeSetCreate(NULL); + } /* * !!!!! this can be optimized a lot, knowing that both @@ -644,31 +647,218 @@ xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { /************************************************************************ * * - * Routines to handle Variable * - * * - * UNIMPLEMENTED CURRENTLY * + * Routines to handle extra functions * * * ************************************************************************/ /** - * xmlXPathVariablelookup: - * @ctxt: the XPath Parser context - * @prefix: the variable name namespace if any + * xmlXPathRegisterFunc: + * @ctxt: the XPath context + * @name: the function name + * @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 +xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, + xmlXPathFunction f) { + int i; + + if (ctxt == NULL) + return(-1); + if (name == NULL) + return(-1); + + for (i = 0;i < ctxt->nb_funcs;i++) { + if (xmlStrEqual(ctxt->funcs[i]->name, name)) { + /* + * It's just an update or a removal + */ + ctxt->funcs[i]->func = f; + return(0); + } + } + if (ctxt->max_funcs <= 0) { + ctxt->max_funcs = 10; + ctxt->nb_funcs = 0; + ctxt->funcs = (xmlXPathFuncPtr *) xmlMalloc(ctxt->max_funcs * + sizeof(xmlXPathFuncPtr)); + } else if (ctxt->max_funcs <= ctxt->nb_funcs) { + ctxt->max_funcs *= 2; + ctxt->funcs = (xmlXPathFuncPtr *) xmlRealloc(ctxt->funcs, + ctxt->max_funcs * sizeof(xmlXPathFuncPtr)); + } + if (ctxt->funcs == NULL) { + fprintf(xmlXPathDebug, "xmlXPathRegisterFunc: out of memory\n"); + return(-1); + } + ctxt->funcs[i]->name = xmlStrdup(name); + ctxt->funcs[i]->func = f; + return(0); +} + +/** + * xmlXPathFunctionLookup: + * @ctxt: the XPath context + * @name: the function name + * + * Search in the Function array of the context for the given + * function. + * + * Returns the xmlXPathFunction or NULL if not found + */ +xmlXPathFunction +xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { + int i; + + if (ctxt == NULL) + return(NULL); + if (name == NULL) + return(NULL); + + for (i = 0;i < ctxt->nb_funcs;i++) { + if (xmlStrEqual(ctxt->funcs[i]->name, name)) { + return(ctxt->funcs[i]->func); + } + } + return(NULL); +} + +/** + * xmlXPathRegisteredFuncsCleanup: + * @ctxt: the XPath context + * + * Cleanup the XPath context data associated to registered functions + */ +void +xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { + int i; + + if (ctxt == NULL) + return; + + for (i = 0;i < ctxt->nb_funcs;i++) { + xmlFree((xmlChar *) ctxt->funcs[i]->name); + } + ctxt->nb_funcs = -1; + ctxt->max_funcs = -1; + if (ctxt->funcs != NULL) + xmlFree(ctxt->funcs); + ctxt->funcs = NULL; +} + +/************************************************************************ + * * + * Routines to handle Variable * + * * + ************************************************************************/ + +/** + * xmlXPathRegisterVariable: + * @ctxt: the XPath context + * @name: the variable name + * @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 +xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, + xmlXPathObjectPtr value) { + int i; + + if (ctxt == NULL) + return(-1); + if (name == NULL) + return(-1); + + for (i = 0;i < ctxt->nb_variables;i++) { + if (xmlStrEqual(ctxt->variables[i]->name, name)) { + /* + * It's just an update or a removal + */ + if (ctxt->variables[i]->value != NULL) { + xmlXPathFreeObject(ctxt->variables[i]->value); + } + ctxt->variables[i]->value = xmlXPathObjectCopy(value); + return(0); + } + } + if (ctxt->max_variables <= 0) { + ctxt->max_variables = 10; + ctxt->nb_variables = 0; + ctxt->variables = (xmlXPathVariablePtr *) + xmlMalloc(ctxt->max_variables * sizeof(xmlXPathVariablePtr)); + } else if (ctxt->max_variables <= ctxt->nb_variables) { + ctxt->max_variables *= 2; + ctxt->variables = (xmlXPathVariablePtr *) + xmlRealloc(ctxt->variables, + ctxt->max_variables * sizeof(xmlXPathVariablePtr)); + } + if (ctxt->variables == NULL) { + fprintf(xmlXPathDebug, "xmlXPathRegisterVariable: out of memory\n"); + return(-1); + } + ctxt->variables[i]->name = xmlStrdup(name); + ctxt->variables[i]->value = xmlXPathObjectCopy(value); + return(0); +} + +/** + * xmlXPathVariableLookup: + * @ctxt: the XPath context * @name: the variable name * * Search in the Variable array of the context for the given * variable value. * - * UNIMPLEMENTED: always return NULL. - * * Returns the value or NULL if not found */ xmlXPathObjectPtr -xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt, - const xmlChar *prefix, const xmlChar *name) { +xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { + int i; + + if (ctxt == NULL) + return(NULL); + if (name == NULL) + return(NULL); + + for (i = 0;i < ctxt->nb_variables;i++) { + if (xmlStrEqual(ctxt->variables[i]->name, name)) { + return(xmlXPathObjectCopy(ctxt->variables[i]->value)); + } + } return(NULL); } +/** + * xmlXPathRegisteredVariablesCleanup: + * @ctxt: the XPath context + * + * Cleanup the XPath context data associated to registered variables + */ +void +xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { + int i; + + if (ctxt == NULL) + return; + + for (i = 0;i < ctxt->nb_variables;i++) { + xmlFree((xmlChar *) ctxt->variables[i]->name); + xmlXPathFreeObject(ctxt->variables[i]->value); + } + ctxt->nb_variables = -1; + ctxt->max_variables = -1; + if (ctxt->variables != NULL) + xmlFree(ctxt->variables); + ctxt->variables = NULL; +} + /************************************************************************ * * * Routines to handle Values * @@ -769,6 +959,53 @@ xmlXPathNewCString(const char *val) { return(ret); } +/** + * xmlXPathObjectCopy: + * @val: the original object + * + * allocate a new copy of a given object + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathObjectCopy(xmlXPathObjectPtr val) { + xmlXPathObjectPtr ret; + + if (val == NULL) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + fprintf(xmlXPathDebug, "xmlXPathObjectCopy: out of memory\n"); + return(NULL); + } + memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); + switch (val->type) { + case XPATH_BOOLEAN: + case XPATH_NUMBER: + case XPATH_STRING: + case XPATH_POINT: + case XPATH_RANGE: + break; + case XPATH_NODESET: + ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); + break; + case XPATH_LOCATIONSET: +#ifdef LIBXML_XPTR_ENABLED + { + xmlLocationSetPtr loc = val->user; + ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); + break; + } +#endif + case XPATH_UNDEFINED: + case XPATH_USERS: + fprintf(xmlXPathDebug, "xmlXPathObjectCopy: unsupported type %d\n", + val->type); + } + return(ret); +} + /** * xmlXPathFreeObject: * @obj: the object to free @@ -860,6 +1097,8 @@ xmlXPathFreeContext(xmlXPathContextPtr ctxt) { if (ctxt->namespaces != NULL) xmlFree(ctxt->namespaces); + xmlXPathRegisteredFuncsCleanup(ctxt); + xmlXPathRegisteredVariablesCleanup(ctxt); #ifdef DEBUG memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext)); #endif @@ -3348,6 +3587,41 @@ xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { return(ret); } +/** + * xmlXPathParseName: + * @ctxt: the XPointer Parser context + * + * parse an XML name + * + * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | + * CombiningChar | Extender + * + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + * + * Returns the namespace name or NULL + */ + +xmlChar * +xmlXPathParseName(xmlXPathParserContextPtr ctxt) { + const xmlChar *q; + xmlChar *ret = NULL; + + if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL); + q = NEXT; + + /* TODO Make this UTF8 compliant !!! */ + while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) || + (CUR == '.') || (CUR == '-') || + (CUR == '_') || (CUR == ':') || + (IS_COMBINING(CUR)) || + (IS_EXTENDER(CUR))) + NEXT; + + ret = xmlStrndup(q, CUR_PTR - q); + + return(ret); +} + /** * xmlXPathStringEvalNumber: * @str: A string to scan @@ -3503,23 +3777,21 @@ xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) { void xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) { xmlChar *name; - xmlChar *prefix; xmlXPathObjectPtr value; SKIP_BLANKS; if (CUR != '$') { XP_ERROR(XPATH_VARIABLE_REF_ERROR); } - name = xmlXPathParseQName(ctxt, &prefix); + name = xmlXPathParseName(ctxt); if (name == NULL) { XP_ERROR(XPATH_VARIABLE_REF_ERROR); } - value = xmlXPathVariablelookup(ctxt, prefix, name); + value = xmlXPathVariableLookup(ctxt->context, name); if (value == NULL) { XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); } valuePush(ctxt, value); - if (prefix != NULL) xmlFree(prefix); xmlFree(name); SKIP_BLANKS; } @@ -3570,6 +3842,9 @@ xmlXPathIsNodeType(const xmlChar *name) { */ xmlXPathFunction xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) { + if (name == NULL) + return(NULL); + switch (name[0]) { case 'b': if (xmlStrEqual(name, BAD_CAST "boolean")) @@ -3648,7 +3923,7 @@ xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) { return(xmlXPathTranslateFunction); break; } - return(NULL); + return(xmlXPathFunctionLookup(ctxt->context, name)); } /** diff --git a/xpath.h b/xpath.h index 98455783..533ca3fc 100644 --- a/xpath.h +++ b/xpath.h @@ -288,6 +288,7 @@ void xmlXPathIdFunction (xmlXPathParserContextPtr ctxt, int nargs); void xmlXPathRoot (xmlXPathParserContextPtr ctxt); void xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); +xmlChar * xmlXPathParseName (xmlXPathParserContextPtr ctxt); /************************************************************************ * * @@ -296,20 +297,14 @@ void xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); ************************************************************************/ /** - * Registering extensions to the expression language + * Extending a context */ -/* TODO */ int xmlXPathRegisterType (xmlXPathContextPtr ctxt, - const xmlChar *name, - xmlXPathConvertFunc f); -/* TODO */ int xmlXPathRegisterAxis (xmlXPathContextPtr ctxt, - const xmlChar *name, - xmlXPathAxisFunc f); -/* TODO */ int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, +int xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, const xmlChar *name, xmlXPathFunction f); -/* TODO */ int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, +int xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, const xmlChar *name, - xmlXPathObject value); + xmlXPathObjectPtr value); /** * Evaluation functions. @@ -327,6 +322,7 @@ xmlXPathObjectPtr xmlXPathEvalExpression (const xmlChar *str, xmlNodeSetPtr xmlXPathNodeSetCreate (xmlNodePtr val); void xmlXPathFreeNodeSetList (xmlXPathObjectPtr obj); void xmlXPathFreeNodeSet (xmlNodeSetPtr obj); +xmlXPathObjectPtr xmlXPathObjectCopy (xmlXPathObjectPtr val); #ifdef __cplusplus diff --git a/xpointer.c b/xpointer.c index 82379ab0..d9baf194 100644 --- a/xpointer.c +++ b/xpointer.c @@ -656,41 +656,6 @@ xmlXPtrWrapLocationSet(xmlLocationSetPtr val) { #define CURRENT (*ctxt->cur) #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) -/** - * xmlXPtrParseName: - * @ctxt: the XPointer Parser context - * - * parse an XML name - * - * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | - * CombiningChar | Extender - * - * [5] Name ::= (Letter | '_' | ':') (NameChar)* - * - * Returns the namespace name or NULL - */ - -xmlChar * -xmlXPtrParseName(xmlXPathParserContextPtr ctxt) { - const xmlChar *q; - xmlChar *ret = NULL; - - if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL); - q = NEXT; - - /* TODO Make this UTF8 compliant !!! */ - while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) || - (CUR == '.') || (CUR == '-') || - (CUR == '_') || (CUR == ':') || - (IS_COMBINING(CUR)) || - (IS_EXTENDER(CUR))) - NEXT; - - ret = xmlStrndup(q, CUR_PTR - q); - - return(ret); -} - /* * xmlXPtrGetChildNo: * @ctxt: the XPointer Parser context @@ -781,7 +746,7 @@ xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { int level; if (name == NULL) - name = xmlXPtrParseName(ctxt); + name = xmlXPathParseName(ctxt); if (name == NULL) XP_ERROR(XPATH_EXPR_ERROR); @@ -878,7 +843,7 @@ xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { void xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) { if (name == NULL) - name = xmlXPtrParseName(ctxt); + name = xmlXPathParseName(ctxt); if (name == NULL) XP_ERROR(XPATH_EXPR_ERROR); while (name != NULL) { @@ -928,7 +893,7 @@ xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) { * Is there another XPoointer part. */ SKIP_BLANKS; - name = xmlXPtrParseName(ctxt); + name = xmlXPathParseName(ctxt); } } @@ -992,7 +957,7 @@ xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { } else { xmlChar *name; - name = xmlXPtrParseName(ctxt); + name = xmlXPathParseName(ctxt); if (name == NULL) XP_ERROR(XPATH_EXPR_ERROR); if (CUR == '(') { diff --git a/xpointer.h b/xpointer.h index 927cdfb7..39216876 100644 --- a/xpointer.h +++ b/xpointer.h @@ -30,6 +30,14 @@ struct _xmlLocationSet { xmlXPathObjectPtr *locTab;/* array of locations */ }; +/* + * Handling of location sets + */ + +void xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); +xmlLocationSetPtr xmlXPtrLocationSetMerge (xmlLocationSetPtr val1, + xmlLocationSetPtr val2); + /* * Functions */ @@ -40,7 +48,6 @@ xmlXPathObjectPtr xmlXPtrEval (const xmlChar *str, xmlXPathContextPtr ctx); void xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, int nargs); -void xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); #ifdef __cplusplus }