📄 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 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__);
/*
* 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;
double xmlXPathNZERO = 0;
static int xmlXPathInitialized = 0;
/**
* xmlXPathInit:
*
* Initialize the XPath environment
*/
void
xmlXPathInit(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
*/
int
xmlXPathIsNaN(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
*/
int
xmlXPathIsInf(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 int
xmlXPathGetSign(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
};
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 *
* *
************************************************************************/
/*
* 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 void
xmlXPathErrMemory(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 void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
{
ctxt->error = XPATH_MEMORY_ERROR;
if (ctxt == NULL)
xmlXPathErrMemory(NULL, extra);
else
xmlXPathErrMemory(ctxt->context, extra);
}
/**
* xmlXPathErr:
* @ctxt: a XPath parser context
* @error: the error code
*
* Handle an XPath error
*/
void
xmlXPathErr(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;
}
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.
*/
void
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
int line ATTRIBUTE_UNUSED, int no) {
xmlXPathErr(ctxt, no);
}
/************************************************************************
* *
* Parser Types *
* *
************************************************************************/
/*
* Types are private:
*/
typedef enum {
XPATH_OP_END=0,
XPATH_OP_AND,
XPATH_OP_OR,
XPATH_OP_EQUAL,
XPATH_OP_CMP,
XPATH_OP_PLUS,
XPATH_OP_MULT,
XPATH_OP_UNION,
XPATH_OP_ROOT,
XPATH_OP_NODE,
XPATH_OP_RESET,
XPATH_OP_COLLECT,
XPATH_OP_VALUE,
XPATH_OP_VARIABLE,
XPATH_OP_FUNCTION,
XPATH_OP_ARG,
XPATH_OP_PREDICATE,
XPATH_OP_FILTER,
XPATH_OP_SORT
#ifdef LIBXML_XPTR_ENABLED
,XPATH_OP_RANGETO
#endif
} xmlXPathOp;
typedef enum {
AXIS_ANCESTOR = 1,
AXIS_ANCESTOR_OR_SELF,
AXIS_ATTRIBUTE,
AXIS_CHILD,
AXIS_DESCENDANT,
AXIS_DESCENDANT_OR_SELF,
AXIS_FOLLOWING,
AXIS_FOLLOWING_SIBLING,
AXIS_NAMESPACE,
AXIS_PARENT,
AXIS_PRECEDING,
AXIS_PRECEDING_SIBLING,
AXIS_SELF
} xmlXPathAxisVal;
typedef enum {
NODE_TEST_NONE = 0,
NODE_TEST_TYPE = 1,
NODE_TEST_PI = 2,
NODE_TEST_ALL = 3,
NODE_TEST_NS = 4,
NODE_TEST_NAME = 5
} xmlXPathTestVal;
typedef enum {
NODE_TYPE_NODE = 0,
NODE_TYPE_COMMENT = XML_COMMENT_NODE,
NODE_TYPE_TEXT = XML_TEXT_NODE,
NODE_TYPE_PI = XML_PI_NODE
} xmlXPathTypeVal;
typedef struct _xmlXPathStepOp xmlXPathStepOp;
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
struct _xmlXPathStepOp {
xmlXPathOp op; /* The identifier of the operation */
int ch1; /* First child */
int ch2; /* Second child */
int value;
int value2;
int value3;
void *value4;
void *value5;
void *cache;
void *cacheURI;
};
struct _xmlXPathCompExpr {
int nbStep; /* Number of steps in this expression */
int maxStep; /* Maximum number of steps allocated */
xmlXPathStepOp *steps; /* ops for computation of this expression */
int last; /* index of last step in expression */
xmlChar *expr; /* the expression being computed */
xmlDictPtr dict; /* the dictionnary to use if any */
#ifdef DEBUG_EVAL_COUNTS
int nb;
xmlChar *string;
#endif
#ifdef XPATH_STREAMING
xmlPatternPtr stream;
#endif
};
/************************************************************************
* *
* Parser Type functions *
* *
************************************************************************/
/**
* xmlXPathNewCompExpr:
*
* Create a new Xpath component
*
* Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
*/
static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void) {
xmlXPathCompExprPtr cur;
cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
if (cur == NULL) {
xmlXPathErrMemory(NULL, "allocating component\n");
return(NULL);
}
memset(cur, 0, sizeof(xmlXPathCompExpr));
cur->maxStep = 10;
cur->nbStep = 0;
cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
sizeof(xmlXPathStepOp));
if (cur->steps == NULL) {
xmlXPathErrMemory(NULL, "allocating steps\n");
xmlFree(cur);
return(NULL);
}
memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -