📄 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 *f * Reference: W3C Recommendation 16 November 1999 * http://www.w3.org/TR/1999/REC-xpath-19991116 * Public reference: * http://www.w3.org/TR/xpath * * See Copyright for the status of this software * * Author: daniel@veillard.com * */#define IN_LIBXML#include "libxml.h"#include <string.h>#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_MATH_H#include <math.h>#endif#ifdef HAVE_FLOAT_H#include <float.h>#endif#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#ifdef HAVE_SIGNAL_H#include <signal.h>#endif#include <libxml/xmlmemory.h>#include <libxml/tree.h>#include <libxml/valid.h>#include <libxml/xpath.h>#include <libxml/xpathInternals.h>#include <libxml/parserInternals.h>#include <libxml/hash.h>#ifdef LIBXML_XPTR_ENABLED#include <libxml/xpointer.h>#endif#ifdef LIBXML_DEBUG_ENABLED#include <libxml/debugXML.h>#endif#include <libxml/xmlerror.h>#include <libxml/threads.h>#include <libxml/globals.h>#ifdef LIBXML_PATTERN_ENABLED#include <libxml/pattern.h>#endif#ifdef LIBXML_PATTERN_ENABLED#define XPATH_STREAMING#endif#define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__);/** XP_OPTIMIZED_NON_ELEM_COMPARISON:* If defined, this will use xmlXPathCmpNodesExt() instead of* xmlXPathCmpNodes(). The new function is optimized comparison of* non-element nodes; actually it will speed up comparison only if* xmlXPathOrderDocElems() was called in order to index the elements of* a tree in document order; Libxslt does such an indexing, thus it will* benefit from this optimization.*/#define XP_OPTIMIZED_NON_ELEM_COMPARISON/** XP_OPTIMIZED_FILTER_FIRST:* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"* in a way, that it stop evaluation at the first node.*/ #define XP_OPTIMIZED_FILTER_FIRST/** XP_DEBUG_OBJ_USAGE:* Internal flag to enable tracking of how much XPath objects have been* created.*//* #define XP_DEBUG_OBJ_USAGE *//* * TODO: * There are a few spots where some tests are done which depend upon ascii * data. These should be enhanced for full UTF8 support (see particularly * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) */#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/************************************************************************ * * * Floating point stuff * * * ************************************************************************/#ifndef TRIO_REPLACE_STDIO#define TRIO_PUBLIC static#endif#include "trionan.c"/* * The lack of portability of this section of the libc is annoying ! */double xmlXPathNAN = 0;double xmlXPathPINF = 1;double xmlXPathNINF = -1;static double xmlXPathNZERO = 0; /* not exported from headers */static int xmlXPathInitialized = 0;/** * xmlXPathInit: * * Initialize the XPath environment */voidxmlXPathInit(void) { if (xmlXPathInitialized) return; xmlXPathPINF = trio_pinf(); xmlXPathNINF = trio_ninf(); xmlXPathNAN = trio_nan(); xmlXPathNZERO = trio_nzero(); xmlXPathInitialized = 1;}/** * xmlXPathIsNaN: * @val: a double value * * Provides a portable isnan() function to detect whether a double * is a NotaNumber. Based on trio code * http://sourceforge.net/projects/ctrio/ * * Returns 1 if the value is a NaN, 0 otherwise */intxmlXPathIsNaN(double val) { return(trio_isnan(val));}/** * xmlXPathIsInf: * @val: a double value * * Provides a portable isinf() function to detect whether a double * is a +Infinite or -Infinite. Based on trio code * http://sourceforge.net/projects/ctrio/ * * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise */intxmlXPathIsInf(double val) { return(trio_isinf(val));}#endif /* SCHEMAS or XPATH */#ifdef LIBXML_XPATH_ENABLED/** * xmlXPathGetSign: * @val: a double value * * Provides a portable function to detect the sign of a double * Modified from trio code * http://sourceforge.net/projects/ctrio/ * * Returns 1 if the value is Negative, 0 if positive */static intxmlXPathGetSign(double val) { return(trio_signbit(val));}/* * TODO: when compatibility allows remove all "fake node libxslt" strings * the test should just be name[0] = ' ' *//* #define DEBUG *//* #define DEBUG_STEP *//* #define DEBUG_STEP_NTH *//* #define DEBUG_EXPR *//* #define DEBUG_EVAL_COUNTS */static xmlNs xmlXPathXMLNamespaceStruct = { NULL, XML_NAMESPACE_DECL, XML_XML_NAMESPACE, BAD_CAST "xml", NULL, NULL};static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;#ifndef LIBXML_THREAD_ENABLED/* * Optimizer is disabled only when threaded apps are detected while * the library ain't compiled for thread safety. */static int xmlXPathDisableOptimizer = 0;#endif/************************************************************************ * * * Error handling routines * * * ************************************************************************//** * XP_ERRORNULL: * @X: the error code * * Macro to raise an XPath error and return NULL. */#define XP_ERRORNULL(X) \ { xmlXPathErr(ctxt, X); return(NULL); }/* * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError */static const char *xmlXPathErrorMessages[] = { "Ok\n", "Number encoding\n", "Unfinished literal\n", "Start of literal\n", "Expected $ for variable reference\n", "Undefined variable\n", "Invalid predicate\n", "Invalid expression\n", "Missing closing curly brace\n", "Unregistered function\n", "Invalid operand\n", "Invalid type\n", "Invalid number of arguments\n", "Invalid context size\n", "Invalid context position\n", "Memory allocation error\n", "Syntax error\n", "Resource error\n", "Sub resource error\n", "Undefined namespace prefix\n", "Encoding error\n", "Char out of XML range\n", "Invalid or incomplete context\n", "?? Unknown error ??\n" /* Must be last in the list! */};#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ sizeof(xmlXPathErrorMessages[0])) - 1)/** * xmlXPathErrMemory: * @ctxt: an XPath context * @extra: extra informations * * Handle a redefinition of attribute error */static voidxmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra){ if (ctxt != NULL) { if (extra) { xmlChar buf[200]; xmlStrPrintf(buf, 200, BAD_CAST "Memory allocation failed : %s\n", extra); ctxt->lastError.message = (char *) xmlStrdup(buf); } else { ctxt->lastError.message = (char *) xmlStrdup(BAD_CAST "Memory allocation failed\n"); } ctxt->lastError.domain = XML_FROM_XPATH; ctxt->lastError.code = XML_ERR_NO_MEMORY; if (ctxt->error != NULL) ctxt->error(ctxt->userData, &ctxt->lastError); } else { if (extra) __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPATH, XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0, "Memory allocation failed : %s\n", extra); else __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPATH, XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, "Memory allocation failed\n"); }}/** * xmlXPathPErrMemory: * @ctxt: an XPath parser context * @extra: extra informations * * Handle a redefinition of attribute error */static voidxmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra){ if (ctxt == NULL) xmlXPathErrMemory(NULL, extra); else { ctxt->error = XPATH_MEMORY_ERROR; xmlXPathErrMemory(ctxt->context, extra); }}/** * xmlXPathErr: * @ctxt: a XPath parser context * @error: the error code * * Handle an XPath error */voidxmlXPathErr(xmlXPathParserContextPtr ctxt, int error){ if ((error < 0) || (error > MAXERRNO)) error = MAXERRNO; if (ctxt == NULL) { __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPATH, error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0, xmlXPathErrorMessages[error]); return; } ctxt->error = error; if (ctxt->context == NULL) { __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPATH, error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, XML_ERR_ERROR, NULL, 0, (const char *) ctxt->base, NULL, NULL, ctxt->cur - ctxt->base, 0, xmlXPathErrorMessages[error]); return; } /* cleanup current last error */ xmlResetError(&ctxt->context->lastError); ctxt->context->lastError.domain = XML_FROM_XPATH; ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK; ctxt->context->lastError.level = XML_ERR_ERROR; ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; ctxt->context->lastError.node = ctxt->context->debugNode; if (ctxt->context->error != NULL) { ctxt->context->error(ctxt->context->userData, &ctxt->context->lastError); } else { __xmlRaiseError(NULL, NULL, NULL, NULL, ctxt->context->debugNode, XML_FROM_XPATH, error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, XML_ERR_ERROR, NULL, 0, (const char *) ctxt->base, NULL, NULL, ctxt->cur - ctxt->base, 0, xmlXPathErrorMessages[error]); }}/** * xmlXPatherror: * @ctxt: the XPath Parser context * @file: the file name * @line: the line number * @no: the error number * * Formats an error message. */voidxmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, int line ATTRIBUTE_UNUSED, int no) { xmlXPathErr(ctxt, no);}/************************************************************************ * * * Utilities * * * ************************************************************************//** * xsltPointerList: * * Pointer-list for various purposes. */typedef struct _xmlPointerList xmlPointerList;typedef xmlPointerList *xmlPointerListPtr;struct _xmlPointerList { void **items; int number; int size;};/** TODO: Since such a list-handling is used in xmlschemas.c and libxslt* and here, we should make the functions public.*/static intxmlPointerListAddSize(xmlPointerListPtr list, void *item, int initialSize){ if (list->items == NULL) { if (initialSize <= 0) initialSize = 1; list->items = (void **) xmlMalloc( initialSize * sizeof(void *)); if (list->items == NULL) { xmlXPathErrMemory(NULL, "xmlPointerListCreate: allocating item\n"); return(-1); } list->number = 0; list->size = initialSize; } else if (list->size <= list->number) { list->size *= 2; list->items = (void **) xmlRealloc(list->items, list->size * sizeof(void *)); if (list->items == NULL) { xmlXPathErrMemory(NULL, "xmlPointerListCreate: re-allocating item\n"); list->size = 0; return(-1); } } list->items[list->number++] = item; return(0);}/** * xsltPointerListCreate: * * Creates an xsltPointerList structure. * * Returns a xsltPointerList structure or NULL in case of an error. */static xmlPointerListPtrxmlPointerListCreate(int initialSize){ xmlPointerListPtr ret; ret = xmlMalloc(sizeof(xmlPointerList)); if (ret == NULL) { xmlXPathErrMemory(NULL, "xmlPointerListCreate: allocating item\n"); return (NULL); } memset(ret, 0, sizeof(xmlPointerList)); if (initialSize > 0) { xmlPointerListAddSize(ret, NULL, initialSize); ret->number = 0; } return (ret);}/** * xsltPointerListFree: * * Frees the xsltPointerList structure. This does not free * the content of the list. */static voidxmlPointerListFree(xmlPointerListPtr list){ if (list == NULL) return; if (list->items != NULL) xmlFree(list->items);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -