📄 xpath.c
字号:
/* * xpath.c: XML Path Language implementation * XPath is a language for addressing parts of an XML document, * designed to be used by both XSLT and XPointer. * * Reference: W3C Working Draft internal 5 July 1999 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html * Public reference: * http://www.w3.org/TR/WD-xpath/ * * See COPYRIGHT for the status of this software * * Author: Daniel.Veillard@w3.org */#include "global.h"#ifdef WIN32#include "win32config.h"#else#include "config.h"#endif#include "xmlversion.h"#ifdef LIBXML_XPATH_ENABLED#include <stdio.h>#include <string.h>#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_MATH_H#include <math.h>#endif#ifdef HAVE_MATH_H#include <float.h>#endif#ifdef HAVE_IEEEFP_H#include <ieeefp.h>#endif#ifdef HAVE_NAN_H#include <nan.h>#endif#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#include <libxml/xmlmemory.h>#include <libxml/tree.h>#include <libxml/valid.h>#include <libxml/xpath.h>#include <libxml/parserInternals.h>/* #define DEBUG *//* #define DEBUG_STEP *//* #define DEBUG_EXPR *//* * Setup stuff for floating point * The lack of portability of this section of the libc is annoying ! */double xmlXPathNAN = 0;double xmlXPathPINF = 1;double xmlXPathMINF = -1;#ifndef isinf#ifndef HAVE_ISINF#if HAVE_FPCLASSint isinf(double d) { fpclass_t type = fpclass(d); switch (type) { case FP_NINF: return(-1); case FP_PINF: return(1); } return(0);}#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)#if HAVE_FP_CLASS_H#include <fp_class.h>#endifint isinf(double d) {#if HAVE_FP_CLASS int fpclass = fp_class(d);#else int fpclass = fp_class_d(d);#endif if (fpclass == FP_POS_INF) return(1); if (fpclass == FP_NEG_INF) return(-1); return(0);}#elif defined(HAVE_CLASS)int isinf(double d) { int fpclass = class(d); if (fpclass == FP_PLUS_INF) return(1); if (fpclass == FP_MINUS_INF) return(-1); return(0);}#elif defined(finite) || defined(HAVE_FINITE)int isinf(double x) { return !finite(x) && x==x; }#elif defined(HUGE_VAL)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) */#ifndef isnan#ifndef HAVE_ISNAN#ifdef HAVE_ISNAND#define isnan(f) isnand(f)#endif /* HAVE_iSNAND */#endif /* ! HAVE_iSNAN */#endif /* ! defined(isnan) *//** * xmlXPathInit: * * Initialize the XPath environment */voidxmlXPathInit(void) { static int initialized = 0; if (initialized) return; xmlXPathNAN = 0; xmlXPathNAN /= 0; xmlXPathPINF = 1; xmlXPathPINF /= 0; xmlXPathMINF = -1; xmlXPathMINF /= 0; initialized = 1;}FILE *xmlXPathDebug = NULL;#define TODO \ fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__);#define STRANGE \ fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \ __FILE__, __LINE__);double xmlXPathStringEvalNumber(const xmlChar *str);void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);/************************************************************************ * * * Parser stacks related functions and macros * * * ************************************************************************//* * Generic function for accessing stacks in the Parser Context */#define PUSH_AND_POP(type, name) \extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \ if (ctxt->name##Nr >= ctxt->name##Max) { \ ctxt->name##Max *= 2; \ ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \ ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \ if (ctxt->name##Tab == NULL) { \ fprintf(xmlXPathDebug, "realloc failed !\n"); \ return(0); \ } \ } \ ctxt->name##Tab[ctxt->name##Nr] = value; \ ctxt->name = value; \ return(ctxt->name##Nr++); \} \extern type name##Pop(xmlXPathParserContextPtr ctxt) { \ type ret; \ if (ctxt->name##Nr <= 0) return(0); \ ctxt->name##Nr--; \ if (ctxt->name##Nr > 0) \ ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \ else \ ctxt->name = NULL; \ ret = ctxt->name##Tab[ctxt->name##Nr]; \ ctxt->name##Tab[ctxt->name##Nr] = 0; \ return(ret); \} \PUSH_AND_POP(xmlXPathObjectPtr, value)/* * Macros for accessing the content. Those should be used only by the parser, * and not exported. * * Dirty macros, i.e. one need to make assumption on the context to use them * * CUR_PTR return the current pointer to the xmlChar to be parsed. * CUR returns the current xmlChar value, i.e. a 8 bit value * in ISO-Latin or UTF-8. * This should be used internally by the parser * only to compare to ASCII values otherwise it would break when * running with UTF-8 encoding. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only * to compare on ASCII based substring. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined * strings within the parser. * CURRENT Returns the current char value, with the full decoding of * UTF-8 if we are using this mode. It returns an int. * NEXT Skip to the next character, this does the proper decoding * in UTF-8 mode. It also pop-up unfinished entities on the fly. * It returns the pointer to the current xmlChar. */#define CUR (*ctxt->cur)#define SKIP(val) ctxt->cur += (val)#define NXT(val) ctxt->cur[(val)]#define CUR_PTR ctxt->cur#define SKIP_BLANKS \ while (IS_BLANK(*(ctxt->cur))) NEXT#define CURRENT (*ctxt->cur)#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)/************************************************************************ * * * Error handling routines * * * ************************************************************************/#define XPATH_EXPRESSION_OK 0#define XPATH_NUMBER_ERROR 1#define XPATH_UNFINISHED_LITERAL_ERROR 2#define XPATH_START_LITERAL_ERROR 3#define XPATH_VARIABLE_REF_ERROR 4#define XPATH_UNDEF_VARIABLE_ERROR 5#define XPATH_INVALID_PREDICATE_ERROR 6#define XPATH_EXPR_ERROR 7#define XPATH_UNCLOSED_ERROR 8#define XPATH_UNKNOWN_FUNC_ERROR 9#define XPATH_INVALID_OPERAND 10#define XPATH_INVALID_TYPE 11#define XPATH_INVALID_ARITY 12const char *xmlXPathErrorMessages[] = { "Ok", "Number encoding", "Unfinished litteral", "Start of litteral", "Expected $ for variable reference", "Undefined variable", "Invalid predicate", "Invalid expression", "Missing closing curly brace", "Unregistered function", "Invalid operand", "Invalid type", "Invalid number of arguments",};/** * xmlXPathError: * @ctxt: the XPath Parser context * @file: the file name * @line: the line number * @no: the error number * * Create a new xmlNodeSetPtr of type double and of value @val * * Returns the newly created object. */voidxmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file, int line, int no) { int n; const xmlChar *cur; const xmlChar *base; fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line, xmlXPathErrorMessages[no]); cur = ctxt->cur; base = ctxt->base; while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) { cur--; } n = 0; while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r')) cur--; if ((*cur == '\n') || (*cur == '\r')) cur++; base = cur; n = 0; while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) { fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++); n++; } fprintf(xmlXPathDebug, "\n"); cur = ctxt->cur; while ((*cur == '\n') || (*cur == '\r')) cur--; n = 0; while ((cur != base) && (n++ < 80)) { fprintf(xmlXPathDebug, " "); base++; } fprintf(xmlXPathDebug,"^\n");}#define CHECK_ERROR \ if (ctxt->error != XPATH_EXPRESSION_OK) return
#ifdef WIN32
#undef ERROR
#endif#define ERROR(X) \ { 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) \/************************************************************************ * * * Routines to handle NodeSets * * * ************************************************************************/#define XML_NODESET_DEFAULT 10/** * xmlXPathNodeSetCreate: * @val: an initial xmlNodePtr, or NULL * * Create a new xmlNodeSetPtr of type double and of value @val * * Returns the newly created object. */xmlNodeSetPtrxmlXPathNodeSetCreate(xmlNodePtr val) { xmlNodeSetPtr ret; ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); if (ret == NULL) { fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n"); return(NULL); } memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); if (val != NULL) { ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); if (ret->nodeTab == NULL) { fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n"); return(NULL); } memset(ret->nodeTab, 0 , XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); ret->nodeMax = XML_NODESET_DEFAULT; ret->nodeTab[ret->nodeNr++] = val; } return(ret);}/** * xmlXPathNodeSetAdd: * @cur: the initial node set * @val: a new xmlNodePtr * * add a new xmlNodePtr ot an existing NodeSet */voidxmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { int i; if (val == NULL) return; /* * check against doublons */ for (i = 0;i < cur->nodeNr;i++) if (cur->nodeTab[i] == val) return; /* * grow the nodeTab if needed */ if (cur->nodeMax == 0) { cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); if (cur->nodeTab == NULL) { fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n"); return; } memset(cur->nodeTab, 0 , XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); cur->nodeMax = XML_NODESET_DEFAULT; } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp; cur->nodeMax *= 2; temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * sizeof(xmlNodePtr)); if (temp == NULL) { fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n"); return; } cur->nodeTab = temp; } cur->nodeTab[cur->nodeNr++] = val;}/** * xmlXPathNodeSetMerge: * @val1: the first NodeSet * @val2: the second NodeSet * * Merges two nodesets, all nodes from @val2 are added to @val1 * * Returns val1 once extended or NULL in case of error. */xmlNodeSetPtrxmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { int i; if (val1 == NULL) return(NULL); if (val2 == NULL) return(val1); /* * !!!!! this can be optimized a lot, knowing that both * val1 and val2 already have unicity of their values. */ for (i = 0;i < val2->nodeNr;i++) xmlXPathNodeSetAdd(val1, val2->nodeTab[i]); return(val1);}/** * xmlXPathNodeSetDel: * @cur: the initial node set * @val: an xmlNodePtr * * Removes an xmlNodePtr from an existing NodeSet */voidxmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { int i; if (cur == NULL) return; if (val == NULL) return; /* * check against doublons */ for (i = 0;i < cur->nodeNr;i++) if (cur->nodeTab[i] == val) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -