2001-02-23 17:55:21 +00:00
/*
* 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
*
2001-12-31 16:16:02 +00:00
* See Copyright for the status of this software
2001-02-23 17:55:21 +00:00
*
2001-06-24 12:13:24 +00:00
* Author : daniel @ veillard . com
2001-02-23 17:55:21 +00:00
*
*/
2002-03-18 19:37:11 +00:00
# define IN_LIBXML
2001-04-21 16:57:29 +00:00
# include "libxml.h"
2001-02-23 17:55:21 +00:00
# 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
2001-04-30 17:44:45 +00:00
# ifdef HAVE_SIGNAL_H
2001-04-28 17:02:11 +00:00
# include <signal.h>
# endif
2001-02-23 17:55:21 +00:00
# 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>
2001-10-16 12:34:39 +00:00
# include <libxml/threads.h>
2001-10-17 15:58:35 +00:00
# include <libxml/globals.h>
2001-02-23 17:55:21 +00:00
2003-10-07 21:25:12 +00:00
# define TODO \
xmlGenericError ( xmlGenericErrorContext , \
" Unimplemented block at %s:%d \n " , \
__FILE__ , __LINE__ ) ;
2003-09-28 18:58:27 +00:00
# if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
2001-03-18 23:17:47 +00:00
/************************************************************************
* *
* Floating point stuff *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-09-20 13:56:06 +00:00
# ifndef TRIO_REPLACE_STDIO
2001-08-21 10:56:31 +00:00
# define TRIO_PUBLIC static
2001-09-20 13:56:06 +00:00
# endif
2001-08-21 10:56:31 +00:00
# include "trionan.c"
2001-02-23 17:55:21 +00:00
/*
* The lack of portability of this section of the libc is annoying !
*/
double xmlXPathNAN = 0 ;
double xmlXPathPINF = 1 ;
double xmlXPathNINF = - 1 ;
2002-03-27 09:05:40 +00:00
double xmlXPathNZERO = 0 ;
2001-10-05 09:18:14 +00:00
static int xmlXPathInitialized = 0 ;
2001-02-23 17:55:21 +00:00
/**
* xmlXPathInit :
*
* Initialize the XPath environment
*/
void
xmlXPathInit ( void ) {
2001-10-05 09:18:14 +00:00
if ( xmlXPathInitialized ) return ;
2001-02-23 17:55:21 +00:00
2001-08-21 09:23:53 +00:00
xmlXPathPINF = trio_pinf ( ) ;
xmlXPathNINF = trio_ninf ( ) ;
xmlXPathNAN = trio_nan ( ) ;
2002-03-27 09:05:40 +00:00
xmlXPathNZERO = trio_nzero ( ) ;
2001-02-23 17:55:21 +00:00
2001-10-05 09:18:14 +00:00
xmlXPathInitialized = 1 ;
2001-02-23 17:55:21 +00:00
}
2001-08-21 10:56:31 +00:00
/**
* 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 ) ) ;
}
2003-09-28 18:58:27 +00:00
# endif /* SCHEMAS or XPATH */
# ifdef LIBXML_XPATH_ENABLED
2002-03-27 09:05:40 +00:00
/**
* 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
*/
2002-03-27 16:12:22 +00:00
static int
2002-03-27 09:05:40 +00:00
xmlXPathGetSign ( double val ) {
2002-03-27 16:12:22 +00:00
return ( trio_signbit ( val ) ) ;
2002-03-27 09:05:40 +00:00
}
2003-07-05 20:32:43 +00:00
/*
* 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
2003-10-07 21:25:12 +00:00
/************************************************************************
* *
* Error handling routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 "
} ;
/**
* 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 )
2003-10-10 14:10:40 +00:00
__xmlRaiseError ( NULL , NULL , NULL ,
2003-10-07 21:25:12 +00:00
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
2003-10-10 14:10:40 +00:00
__xmlRaiseError ( NULL , NULL , NULL ,
2003-10-07 21:25:12 +00:00
NULL , NULL , XML_FROM_XPATH ,
XML_ERR_NO_MEMORY , XML_ERR_FATAL , NULL , 0 ,
NULL , NULL , NULL , 0 , 0 ,
" Memory allocation failed \n " ) ;
}
}
/**
* xmlXPathErrMemory :
* @ 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 a Relax NG Parsing error
*/
void
xmlXPathErr ( xmlXPathParserContextPtr ctxt , int error )
{
2003-12-08 10:25:02 +00:00
if ( ctxt = = NULL ) {
2003-10-10 14:10:40 +00:00
__xmlRaiseError ( NULL , NULL , NULL ,
2003-10-07 21:25:12 +00:00
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 ;
}
2003-12-08 10:25:02 +00:00
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 ;
}
2003-10-07 21:25:12 +00:00
ctxt - > context - > lastError . domain = XML_FROM_XPATH ;
ctxt - > context - > lastError . code = error + XML_XPATH_EXPRESSION_OK -
XPATH_EXPRESSION_OK ;
2003-10-10 11:42:17 +00:00
ctxt - > context - > lastError . level = XML_ERR_ERROR ;
2003-10-07 21:25:12 +00:00
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 {
2003-10-10 14:10:40 +00:00
__xmlRaiseError ( NULL , NULL , NULL ,
2003-10-07 21:25:12 +00:00
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 ) ;
}
2001-03-18 23:17:47 +00:00
/************************************************************************
* *
* 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 ,
2001-04-05 16:54:14 +00:00
XPATH_OP_FILTER ,
2001-03-18 23:17:47 +00:00
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 ;
int ch1 ;
int ch2 ;
int value ;
int value2 ;
int value3 ;
void * value4 ;
void * value5 ;
2001-04-28 14:35:02 +00:00
void * cache ;
2001-05-22 16:57:14 +00:00
void * cacheURI ;
2001-03-18 23:17:47 +00:00
} ;
struct _xmlXPathCompExpr {
int nbStep ;
int maxStep ;
xmlXPathStepOp * steps ; /* ops for computation */
int last ;
2002-09-24 14:13:13 +00:00
xmlChar * expr ;
2001-07-03 10:35:50 +00:00
# ifdef DEBUG_EVAL_COUNTS
int nb ;
xmlChar * string ;
# endif
2001-03-18 23:17:47 +00:00
} ;
/************************************************************************
* *
* Parser Type functions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPathNewCompExpr :
*
* Create a new Xpath component
*
* Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
*/
2001-03-24 17:00:36 +00:00
static xmlXPathCompExprPtr
2001-03-18 23:17:47 +00:00
xmlXPathNewCompExpr ( void ) {
xmlXPathCompExprPtr cur ;
cur = ( xmlXPathCompExprPtr ) xmlMalloc ( sizeof ( xmlXPathCompExpr ) ) ;
if ( cur = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " allocating component \n " ) ;
2001-03-18 23:17:47 +00:00
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 ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " allocating steps \n " ) ;
2001-03-18 23:17:47 +00:00
xmlFree ( cur ) ;
return ( NULL ) ;
}
memset ( cur - > steps , 0 , cur - > maxStep * sizeof ( xmlXPathStepOp ) ) ;
cur - > last = - 1 ;
2001-07-03 10:35:50 +00:00
# ifdef DEBUG_EVAL_COUNTS
cur - > nb = 0 ;
# endif
2001-03-18 23:17:47 +00:00
return ( cur ) ;
}
/**
* xmlXPathFreeCompExpr :
* @ comp : an XPATH comp
*
* Free up the memory allocated by @ comp
*/
void
2001-07-03 10:35:50 +00:00
xmlXPathFreeCompExpr ( xmlXPathCompExprPtr comp )
{
2001-03-18 23:17:47 +00:00
xmlXPathStepOpPtr op ;
int i ;
if ( comp = = NULL )
2001-07-03 10:35:50 +00:00
return ;
for ( i = 0 ; i < comp - > nbStep ; i + + ) {
op = & comp - > steps [ i ] ;
if ( op - > value4 ! = NULL ) {
if ( op - > op = = XPATH_OP_VALUE )
xmlXPathFreeObject ( op - > value4 ) ;
else
xmlFree ( op - > value4 ) ;
}
if ( op - > value5 ! = NULL )
xmlFree ( op - > value5 ) ;
2001-03-18 23:17:47 +00:00
}
if ( comp - > steps ! = NULL ) {
2001-07-03 10:35:50 +00:00
xmlFree ( comp - > steps ) ;
2001-03-18 23:17:47 +00:00
}
2001-07-03 10:35:50 +00:00
# ifdef DEBUG_EVAL_COUNTS
if ( comp - > string ! = NULL ) {
xmlFree ( comp - > string ) ;
}
# endif
2002-09-24 14:13:13 +00:00
if ( comp - > expr ! = NULL ) {
xmlFree ( comp - > expr ) ;
}
2001-07-03 10:35:50 +00:00
2001-03-18 23:17:47 +00:00
xmlFree ( comp ) ;
}
/**
* xmlXPathCompExprAdd :
* @ comp : the compiled expression
* @ ch1 : first child index
* @ ch2 : second child index
* @ op : an op
* @ value : the first int value
* @ value2 : the second int value
* @ value3 : the third int value
* @ value4 : the first string value
* @ value5 : the second string value
*
* Add an step to an XPath Compiled Expression
*
* Returns - 1 in case of failure , the index otherwise
*/
2001-03-24 17:00:36 +00:00
static int
2001-03-18 23:17:47 +00:00
xmlXPathCompExprAdd ( xmlXPathCompExprPtr comp , int ch1 , int ch2 ,
xmlXPathOp op , int value ,
int value2 , int value3 , void * value4 , void * value5 ) {
if ( comp - > nbStep > = comp - > maxStep ) {
xmlXPathStepOp * real ;
comp - > maxStep * = 2 ;
real = ( xmlXPathStepOp * ) xmlRealloc ( comp - > steps ,
comp - > maxStep * sizeof ( xmlXPathStepOp ) ) ;
if ( real = = NULL ) {
comp - > maxStep / = 2 ;
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " adding step \n " ) ;
2001-03-18 23:17:47 +00:00
return ( - 1 ) ;
}
comp - > steps = real ;
}
comp - > last = comp - > nbStep ;
comp - > steps [ comp - > nbStep ] . ch1 = ch1 ;
comp - > steps [ comp - > nbStep ] . ch2 = ch2 ;
comp - > steps [ comp - > nbStep ] . op = op ;
comp - > steps [ comp - > nbStep ] . value = value ;
comp - > steps [ comp - > nbStep ] . value2 = value2 ;
comp - > steps [ comp - > nbStep ] . value3 = value3 ;
comp - > steps [ comp - > nbStep ] . value4 = value4 ;
comp - > steps [ comp - > nbStep ] . value5 = value5 ;
2001-04-28 14:35:02 +00:00
comp - > steps [ comp - > nbStep ] . cache = NULL ;
2001-03-18 23:17:47 +00:00
return ( comp - > nbStep + + ) ;
}
2001-07-03 10:35:50 +00:00
/**
* xmlXPathCompSwap :
* @ comp : the compiled expression
* @ op : operation index
*
* Swaps 2 operations in the compiled expression
*/
static void
xmlXPathCompSwap ( xmlXPathStepOpPtr op ) {
int tmp ;
2002-04-16 07:49:59 +00:00
# ifndef LIBXML_THREAD_ENABLED
2001-10-16 12:34:39 +00:00
/*
* Since this manipulates possibly shared variables , this is
* disable if one detects that the library is used in a multithreaded
* application
*/
if ( xmlXPathDisableOptimizer )
return ;
# endif
2001-07-03 10:35:50 +00:00
tmp = op - > ch1 ;
op - > ch1 = op - > ch2 ;
op - > ch2 = tmp ;
}
2001-04-05 16:54:14 +00:00
# define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
xmlXPathCompExprAdd ( ctxt - > comp , ( op1 ) , ( op2 ) , \
( op ) , ( val ) , ( val2 ) , ( val3 ) , ( val4 ) , ( val5 ) )
2001-03-18 23:17:47 +00:00
# define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
xmlXPathCompExprAdd ( ctxt - > comp , ctxt - > comp - > last , - 1 , \
( op ) , ( val ) , ( val2 ) , ( val3 ) , ( val4 ) , ( val5 ) )
# define PUSH_LEAVE_EXPR(op, val, val2) \
xmlXPathCompExprAdd ( ctxt - > comp , - 1 , - 1 , ( op ) , ( val ) , ( val2 ) , 0 , NULL , NULL )
# define PUSH_UNARY_EXPR(op, ch, val, val2) \
xmlXPathCompExprAdd ( ctxt - > comp , ( ch ) , - 1 , ( op ) , ( val ) , ( val2 ) , 0 , NULL , NULL )
# define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
xmlXPathCompExprAdd ( ctxt - > comp , ( ch1 ) , ( ch2 ) , ( op ) , ( val ) , ( val2 ) , 0 , NULL , NULL )
2001-02-23 17:55:21 +00:00
/************************************************************************
* *
* Debugging related functions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define STRANGE \
xmlGenericError ( xmlGenericErrorContext , \
" Internal error at %s:%d \n " , \
__FILE__ , __LINE__ ) ;
# ifdef LIBXML_DEBUG_ENABLED
2001-03-24 17:00:36 +00:00
static void
xmlXPathDebugDumpNode ( FILE * output , xmlNodePtr cur , int depth ) {
2001-02-23 17:55:21 +00:00
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
if ( cur = = NULL ) {
fprintf ( output , shift ) ;
fprintf ( output , " Node is NULL ! \n " ) ;
return ;
}
if ( ( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
fprintf ( output , shift ) ;
fprintf ( output , " / \n " ) ;
} else if ( cur - > type = = XML_ATTRIBUTE_NODE )
xmlDebugDumpAttr ( output , ( xmlAttrPtr ) cur , depth ) ;
else
xmlDebugDumpOneNode ( output , cur , depth ) ;
}
2001-03-24 17:00:36 +00:00
static void
xmlXPathDebugDumpNodeList ( FILE * output , xmlNodePtr cur , int depth ) {
2001-02-23 18:44:52 +00:00
xmlNodePtr tmp ;
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
if ( cur = = NULL ) {
fprintf ( output , shift ) ;
fprintf ( output , " Node is NULL ! \n " ) ;
return ;
}
while ( cur ! = NULL ) {
tmp = cur ;
cur = cur - > next ;
xmlDebugDumpOneNode ( output , tmp , depth ) ;
}
}
2001-02-23 17:55:21 +00:00
2001-03-24 17:00:36 +00:00
static void
xmlXPathDebugDumpNodeSet ( FILE * output , xmlNodeSetPtr cur , int depth ) {
2001-02-23 17:55:21 +00:00
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
if ( cur = = NULL ) {
fprintf ( output , shift ) ;
fprintf ( output , " NodeSet is NULL ! \n " ) ;
return ;
}
2001-04-07 15:39:35 +00:00
if ( cur ! = NULL ) {
fprintf ( output , " Set contains %d nodes: \n " , cur - > nodeNr ) ;
for ( i = 0 ; i < cur - > nodeNr ; i + + ) {
fprintf ( output , shift ) ;
fprintf ( output , " %d " , i + 1 ) ;
xmlXPathDebugDumpNode ( output , cur - > nodeTab [ i ] , depth + 1 ) ;
}
2001-02-23 17:55:21 +00:00
}
}
2001-03-24 17:00:36 +00:00
static void
xmlXPathDebugDumpValueTree ( FILE * output , xmlNodeSetPtr cur , int depth ) {
2001-02-23 18:44:52 +00:00
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
if ( ( cur = = NULL ) | | ( cur - > nodeNr = = 0 ) | | ( cur - > nodeTab [ 0 ] = = NULL ) ) {
fprintf ( output , shift ) ;
fprintf ( output , " Value Tree is NULL ! \n " ) ;
return ;
}
fprintf ( output , shift ) ;
fprintf ( output , " %d " , i + 1 ) ;
xmlXPathDebugDumpNodeList ( output , cur - > nodeTab [ 0 ] - > children , depth + 1 ) ;
}
2001-02-23 17:55:21 +00:00
# if defined(LIBXML_XPTR_ENABLED)
2001-03-24 17:00:36 +00:00
static void
xmlXPathDebugDumpLocationSet ( FILE * output , xmlLocationSetPtr cur , int depth ) {
2001-02-23 17:55:21 +00:00
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
if ( cur = = NULL ) {
fprintf ( output , shift ) ;
fprintf ( output , " LocationSet is NULL ! \n " ) ;
return ;
}
for ( i = 0 ; i < cur - > locNr ; i + + ) {
fprintf ( output , shift ) ;
fprintf ( output , " %d : " , i + 1 ) ;
xmlXPathDebugDumpObject ( output , cur - > locTab [ i ] , depth + 1 ) ;
}
}
2001-06-21 11:20:21 +00:00
# endif /* LIBXML_XPTR_ENABLED */
2001-02-23 17:55:21 +00:00
2001-03-19 10:57:13 +00:00
/**
* xmlXPathDebugDumpObject :
* @ output : the FILE * to dump the output
* @ cur : the object to inspect
* @ depth : indentation level
*
* Dump the content of the object for debugging purposes
*/
void
xmlXPathDebugDumpObject ( FILE * output , xmlXPathObjectPtr cur , int depth ) {
2001-02-23 17:55:21 +00:00
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
fprintf ( output , shift ) ;
if ( cur = = NULL ) {
fprintf ( output , " Object is empty (NULL) \n " ) ;
return ;
}
switch ( cur - > type ) {
case XPATH_UNDEFINED :
fprintf ( output , " Object is uninitialized \n " ) ;
break ;
case XPATH_NODESET :
fprintf ( output , " Object is a Node Set : \n " ) ;
xmlXPathDebugDumpNodeSet ( output , cur - > nodesetval , depth ) ;
break ;
case XPATH_XSLT_TREE :
fprintf ( output , " Object is an XSLT value tree : \n " ) ;
2001-02-23 18:44:52 +00:00
xmlXPathDebugDumpValueTree ( output , cur - > nodesetval , depth ) ;
2001-02-23 17:55:21 +00:00
break ;
case XPATH_BOOLEAN :
fprintf ( output , " Object is a Boolean : " ) ;
if ( cur - > boolval ) fprintf ( output , " true \n " ) ;
else fprintf ( output , " false \n " ) ;
break ;
case XPATH_NUMBER :
2001-08-21 10:56:31 +00:00
switch ( xmlXPathIsInf ( cur - > floatval ) ) {
2001-05-03 10:49:20 +00:00
case 1 :
2002-03-27 09:05:40 +00:00
fprintf ( output , " Object is a number : Infinity \n " ) ;
2001-05-03 10:49:20 +00:00
break ;
case - 1 :
fprintf ( output , " Object is a number : -Infinity \n " ) ;
break ;
default :
2001-08-21 10:56:31 +00:00
if ( xmlXPathIsNaN ( cur - > floatval ) ) {
2001-05-03 10:49:20 +00:00
fprintf ( output , " Object is a number : NaN \n " ) ;
2002-03-28 18:25:31 +00:00
} else if ( cur - > floatval = = 0 & & xmlXPathGetSign ( cur - > floatval ) ! = 0 ) {
fprintf ( output , " Object is a number : 0 \n " ) ;
2001-05-03 10:49:20 +00:00
} else {
fprintf ( output , " Object is a number : %0g \n " , cur - > floatval ) ;
}
}
2001-02-23 17:55:21 +00:00
break ;
case XPATH_STRING :
fprintf ( output , " Object is a string : " ) ;
xmlDebugDumpString ( output , cur - > stringval ) ;
fprintf ( output , " \n " ) ;
break ;
case XPATH_POINT :
fprintf ( output , " Object is a point : index %d in node " , cur - > index ) ;
xmlXPathDebugDumpNode ( output , ( xmlNodePtr ) cur - > user , depth + 1 ) ;
fprintf ( output , " \n " ) ;
break ;
case XPATH_RANGE :
if ( ( cur - > user2 = = NULL ) | |
( ( cur - > user2 = = cur - > user ) & & ( cur - > index = = cur - > index2 ) ) ) {
fprintf ( output , " Object is a collapsed range : \n " ) ;
fprintf ( output , shift ) ;
if ( cur - > index > = 0 )
fprintf ( output , " index %d in " , cur - > index ) ;
fprintf ( output , " node \n " ) ;
xmlXPathDebugDumpNode ( output , ( xmlNodePtr ) cur - > user ,
depth + 1 ) ;
} else {
fprintf ( output , " Object is a range : \n " ) ;
fprintf ( output , shift ) ;
fprintf ( output , " From " ) ;
if ( cur - > index > = 0 )
fprintf ( output , " index %d in " , cur - > index ) ;
fprintf ( output , " node \n " ) ;
xmlXPathDebugDumpNode ( output , ( xmlNodePtr ) cur - > user ,
depth + 1 ) ;
fprintf ( output , shift ) ;
fprintf ( output , " To " ) ;
if ( cur - > index2 > = 0 )
fprintf ( output , " index %d in " , cur - > index2 ) ;
fprintf ( output , " node \n " ) ;
xmlXPathDebugDumpNode ( output , ( xmlNodePtr ) cur - > user2 ,
depth + 1 ) ;
fprintf ( output , " \n " ) ;
}
break ;
case XPATH_LOCATIONSET :
# if defined(LIBXML_XPTR_ENABLED)
fprintf ( output , " Object is a Location Set: \n " ) ;
xmlXPathDebugDumpLocationSet ( output ,
( xmlLocationSetPtr ) cur - > user , depth ) ;
# endif
break ;
case XPATH_USERS :
fprintf ( output , " Object is user defined \n " ) ;
break ;
}
}
2001-03-18 23:17:47 +00:00
2001-03-24 17:00:36 +00:00
static void
xmlXPathDebugDumpStepOp ( FILE * output , xmlXPathCompExprPtr comp ,
2001-03-18 23:17:47 +00:00
xmlXPathStepOpPtr op , int depth ) {
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
fprintf ( output , shift ) ;
if ( op = = NULL ) {
fprintf ( output , " Step is NULL \n " ) ;
return ;
}
switch ( op - > op ) {
case XPATH_OP_END :
fprintf ( output , " END " ) ; break ;
case XPATH_OP_AND :
fprintf ( output , " AND " ) ; break ;
case XPATH_OP_OR :
fprintf ( output , " OR " ) ; break ;
case XPATH_OP_EQUAL :
if ( op - > value )
fprintf ( output , " EQUAL = " ) ;
else
fprintf ( output , " EQUAL != " ) ;
break ;
case XPATH_OP_CMP :
if ( op - > value )
fprintf ( output , " CMP < " ) ;
else
fprintf ( output , " CMP > " ) ;
if ( ! op - > value2 )
fprintf ( output , " = " ) ;
break ;
case XPATH_OP_PLUS :
if ( op - > value = = 0 )
fprintf ( output , " PLUS - " ) ;
else if ( op - > value = = 1 )
fprintf ( output , " PLUS + " ) ;
else if ( op - > value = = 2 )
fprintf ( output , " PLUS unary - " ) ;
else if ( op - > value = = 3 )
fprintf ( output , " PLUS unary - - " ) ;
break ;
case XPATH_OP_MULT :
if ( op - > value = = 0 )
fprintf ( output , " MULT * " ) ;
else if ( op - > value = = 1 )
fprintf ( output , " MULT div " ) ;
else
fprintf ( output , " MULT mod " ) ;
break ;
case XPATH_OP_UNION :
fprintf ( output , " UNION " ) ; break ;
case XPATH_OP_ROOT :
fprintf ( output , " ROOT " ) ; break ;
case XPATH_OP_NODE :
fprintf ( output , " NODE " ) ; break ;
case XPATH_OP_RESET :
fprintf ( output , " RESET " ) ; break ;
case XPATH_OP_SORT :
fprintf ( output , " SORT " ) ; break ;
case XPATH_OP_COLLECT : {
2003-07-31 14:47:38 +00:00
xmlXPathAxisVal axis = ( xmlXPathAxisVal ) op - > value ;
xmlXPathTestVal test = ( xmlXPathTestVal ) op - > value2 ;
xmlXPathTypeVal type = ( xmlXPathTypeVal ) op - > value3 ;
2001-03-18 23:17:47 +00:00
const xmlChar * prefix = op - > value4 ;
const xmlChar * name = op - > value5 ;
fprintf ( output , " COLLECT " ) ;
switch ( axis ) {
case AXIS_ANCESTOR :
fprintf ( output , " 'ancestors' " ) ; break ;
case AXIS_ANCESTOR_OR_SELF :
fprintf ( output , " 'ancestors-or-self' " ) ; break ;
case AXIS_ATTRIBUTE :
fprintf ( output , " 'attributes' " ) ; break ;
case AXIS_CHILD :
fprintf ( output , " 'child' " ) ; break ;
case AXIS_DESCENDANT :
fprintf ( output , " 'descendant' " ) ; break ;
case AXIS_DESCENDANT_OR_SELF :
fprintf ( output , " 'descendant-or-self' " ) ; break ;
case AXIS_FOLLOWING :
fprintf ( output , " 'following' " ) ; break ;
case AXIS_FOLLOWING_SIBLING :
fprintf ( output , " 'following-siblings' " ) ; break ;
case AXIS_NAMESPACE :
fprintf ( output , " 'namespace' " ) ; break ;
case AXIS_PARENT :
fprintf ( output , " 'parent' " ) ; break ;
case AXIS_PRECEDING :
fprintf ( output , " 'preceding' " ) ; break ;
case AXIS_PRECEDING_SIBLING :
fprintf ( output , " 'preceding-sibling' " ) ; break ;
case AXIS_SELF :
fprintf ( output , " 'self' " ) ; break ;
}
switch ( test ) {
case NODE_TEST_NONE :
fprintf ( output , " 'none' " ) ; break ;
case NODE_TEST_TYPE :
fprintf ( output , " 'type' " ) ; break ;
case NODE_TEST_PI :
fprintf ( output , " 'PI' " ) ; break ;
case NODE_TEST_ALL :
fprintf ( output , " 'all' " ) ; break ;
case NODE_TEST_NS :
fprintf ( output , " 'namespace' " ) ; break ;
case NODE_TEST_NAME :
fprintf ( output , " 'name' " ) ; break ;
}
switch ( type ) {
case NODE_TYPE_NODE :
fprintf ( output , " 'node' " ) ; break ;
case NODE_TYPE_COMMENT :
fprintf ( output , " 'comment' " ) ; break ;
case NODE_TYPE_TEXT :
fprintf ( output , " 'text' " ) ; break ;
case NODE_TYPE_PI :
fprintf ( output , " 'PI' " ) ; break ;
}
if ( prefix ! = NULL )
fprintf ( output , " %s: " , prefix ) ;
if ( name ! = NULL )
2003-03-21 21:22:48 +00:00
fprintf ( output , " %s " , ( const char * ) name ) ;
2001-03-18 23:17:47 +00:00
break ;
}
case XPATH_OP_VALUE : {
xmlXPathObjectPtr object = ( xmlXPathObjectPtr ) op - > value4 ;
fprintf ( output , " ELEM " ) ;
xmlXPathDebugDumpObject ( output , object , 0 ) ;
goto finish ;
}
case XPATH_OP_VARIABLE : {
const xmlChar * prefix = op - > value5 ;
const xmlChar * name = op - > value4 ;
if ( prefix ! = NULL )
fprintf ( output , " VARIABLE %s:%s " , prefix , name ) ;
else
fprintf ( output , " VARIABLE %s " , name ) ;
break ;
}
case XPATH_OP_FUNCTION : {
int nbargs = op - > value ;
const xmlChar * prefix = op - > value5 ;
const xmlChar * name = op - > value4 ;
if ( prefix ! = NULL )
fprintf ( output , " FUNCTION %s:%s(%d args) " ,
prefix , name , nbargs ) ;
else
fprintf ( output , " FUNCTION %s(%d args) " , name , nbargs ) ;
break ;
}
case XPATH_OP_ARG : fprintf ( output , " ARG " ) ; break ;
case XPATH_OP_PREDICATE : fprintf ( output , " PREDICATE " ) ; break ;
2001-04-05 16:54:14 +00:00
case XPATH_OP_FILTER : fprintf ( output , " FILTER " ) ; break ;
2001-04-22 19:13:10 +00:00
# ifdef LIBXML_XPTR_ENABLED
case XPATH_OP_RANGETO : fprintf ( output , " RANGETO " ) ; break ;
# endif
2001-03-18 23:17:47 +00:00
default :
fprintf ( output , " UNKNOWN %d \n " , op - > op ) ; return ;
}
fprintf ( output , " \n " ) ;
finish :
if ( op - > ch1 > = 0 )
xmlXPathDebugDumpStepOp ( output , comp , & comp - > steps [ op - > ch1 ] , depth + 1 ) ;
if ( op - > ch2 > = 0 )
xmlXPathDebugDumpStepOp ( output , comp , & comp - > steps [ op - > ch2 ] , depth + 1 ) ;
}
2001-03-24 17:00:36 +00:00
2001-07-18 19:30:27 +00:00
/**
* xmlXPathDebugDumpCompExpr :
* @ output : the FILE * for the output
* @ comp : the precompiled XPath expression
* @ depth : the indentation level .
*
* Dumps the tree of the compiled XPath expression .
*/
2001-03-24 17:00:36 +00:00
void
xmlXPathDebugDumpCompExpr ( FILE * output , xmlXPathCompExprPtr comp ,
int depth ) {
2001-03-18 23:17:47 +00:00
int i ;
char shift [ 100 ] ;
for ( i = 0 ; ( ( i < depth ) & & ( i < 25 ) ) ; i + + )
shift [ 2 * i ] = shift [ 2 * i + 1 ] = ' ' ;
shift [ 2 * i ] = shift [ 2 * i + 1 ] = 0 ;
fprintf ( output , shift ) ;
if ( comp = = NULL ) {
fprintf ( output , " Compiled Expression is NULL \n " ) ;
return ;
}
fprintf ( output , " Compiled Expression : %d elements \n " ,
comp - > nbStep ) ;
i = comp - > last ;
xmlXPathDebugDumpStepOp ( output , comp , & comp - > steps [ i ] , depth + 1 ) ;
}
2001-06-21 11:20:21 +00:00
# endif /* LIBXML_DEBUG_ENABLED */
2001-02-23 17:55:21 +00:00
/************************************************************************
* *
* Parser stacks related functions and macros *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-07-18 19:30:27 +00:00
/**
* valuePop :
* @ ctxt : an XPath evaluation context
*
* Pops the top XPath object from the value stack
*
* Returns the XPath object just removed
*/
2002-11-30 11:22:59 +00:00
extern xmlXPathObjectPtr
valuePop ( xmlXPathParserContextPtr ctxt )
{
xmlXPathObjectPtr ret ;
if ( ctxt - > valueNr < = 0 )
return ( 0 ) ;
ctxt - > valueNr - - ;
if ( ctxt - > valueNr > 0 )
ctxt - > value = ctxt - > valueTab [ ctxt - > valueNr - 1 ] ;
else
ctxt - > value = NULL ;
ret = ctxt - > valueTab [ ctxt - > valueNr ] ;
ctxt - > valueTab [ ctxt - > valueNr ] = 0 ;
return ( ret ) ;
}
2001-07-18 19:30:27 +00:00
/**
* valuePush :
* @ ctxt : an XPath evaluation context
* @ value : the XPath object
*
* Pushes a new XPath object on top of the value stack
2001-12-31 16:16:02 +00:00
*
* returns the number of items on the value stack
2001-07-18 19:30:27 +00:00
*/
2002-11-30 11:22:59 +00:00
extern int
valuePush ( xmlXPathParserContextPtr ctxt , xmlXPathObjectPtr value )
{
if ( ctxt - > valueNr > = ctxt - > valueMax ) {
ctxt - > valueMax * = 2 ;
ctxt - > valueTab =
( xmlXPathObjectPtr * ) xmlRealloc ( ctxt - > valueTab ,
ctxt - > valueMax *
sizeof ( ctxt - > valueTab [ 0 ] ) ) ;
if ( ctxt - > valueTab = = NULL ) {
xmlGenericError ( xmlGenericErrorContext , " realloc failed ! \n " ) ;
return ( 0 ) ;
}
}
ctxt - > valueTab [ ctxt - > valueNr ] = value ;
ctxt - > value = value ;
return ( ctxt - > valueNr + + ) ;
}
2001-02-23 17:55:21 +00:00
2001-07-16 04:52:57 +00:00
/**
* xmlXPathPopBoolean :
* @ ctxt : an XPath parser context
*
* Pops a boolean from the stack , handling conversion if needed .
* Check error with # xmlXPathCheckError .
*
* Returns the boolean
*/
int
xmlXPathPopBoolean ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr obj ;
int ret ;
obj = valuePop ( ctxt ) ;
if ( obj = = NULL ) {
xmlXPathSetError ( ctxt , XPATH_INVALID_OPERAND ) ;
return ( 0 ) ;
}
ret = xmlXPathCastToBoolean ( obj ) ;
xmlXPathFreeObject ( obj ) ;
return ( ret ) ;
}
/**
* xmlXPathPopNumber :
* @ ctxt : an XPath parser context
*
* Pops a number from the stack , handling conversion if needed .
* Check error with # xmlXPathCheckError .
*
* Returns the number
*/
double
xmlXPathPopNumber ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr obj ;
double ret ;
obj = valuePop ( ctxt ) ;
if ( obj = = NULL ) {
xmlXPathSetError ( ctxt , XPATH_INVALID_OPERAND ) ;
return ( 0 ) ;
}
ret = xmlXPathCastToNumber ( obj ) ;
xmlXPathFreeObject ( obj ) ;
return ( ret ) ;
}
/**
* xmlXPathPopString :
* @ ctxt : an XPath parser context
*
* Pops a string from the stack , handling conversion if needed .
* Check error with # xmlXPathCheckError .
*
* Returns the string
*/
xmlChar *
xmlXPathPopString ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr obj ;
xmlChar * ret ;
obj = valuePop ( ctxt ) ;
if ( obj = = NULL ) {
xmlXPathSetError ( ctxt , XPATH_INVALID_OPERAND ) ;
return ( NULL ) ;
}
ret = xmlXPathCastToString ( obj ) ;
/* TODO: needs refactoring somewhere else */
if ( obj - > stringval = = ret )
obj - > stringval = NULL ;
xmlXPathFreeObject ( obj ) ;
return ( ret ) ;
}
/**
* xmlXPathPopNodeSet :
* @ ctxt : an XPath parser context
*
* Pops a node - set from the stack , handling conversion if needed .
* Check error with # xmlXPathCheckError .
*
* Returns the node - set
*/
xmlNodeSetPtr
xmlXPathPopNodeSet ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr obj ;
xmlNodeSetPtr ret ;
if ( ctxt - > value = = NULL ) {
xmlXPathSetError ( ctxt , XPATH_INVALID_OPERAND ) ;
return ( NULL ) ;
}
if ( ! xmlXPathStackIsNodeSet ( ctxt ) ) {
xmlXPathSetTypeError ( ctxt ) ;
return ( NULL ) ;
}
obj = valuePop ( ctxt ) ;
ret = obj - > nodesetval ;
2003-07-28 20:40:59 +00:00
/* to fix memory leak of not clearing obj->user */
if ( obj - > boolval & & obj - > user ! = NULL )
xmlFreeNodeList ( ( xmlNodePtr ) obj - > user ) ;
2001-07-16 04:52:57 +00:00
xmlXPathFreeNodeSetList ( obj ) ;
return ( ret ) ;
}
/**
* xmlXPathPopExternal :
* @ ctxt : an XPath parser context
*
2001-12-31 16:16:02 +00:00
* Pops an external object from the stack , handling conversion if needed .
2001-07-16 04:52:57 +00:00
* Check error with # xmlXPathCheckError .
*
* Returns the object
*/
void *
xmlXPathPopExternal ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr obj ;
void * ret ;
if ( ctxt - > value = = NULL ) {
xmlXPathSetError ( ctxt , XPATH_INVALID_OPERAND ) ;
return ( NULL ) ;
}
if ( ctxt - > value - > type ! = XPATH_USERS ) {
xmlXPathSetTypeError ( ctxt ) ;
return ( NULL ) ;
}
obj = valuePop ( ctxt ) ;
ret = obj - > user ;
xmlXPathFreeObject ( obj ) ;
return ( ret ) ;
}
2001-02-23 17:55:21 +00:00
/*
* 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
2001-04-27 17:13:01 +00:00
# define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
# define COPY_BUF(l,b,i,v) \
if ( l = = 1 ) b [ i + + ] = ( xmlChar ) v ; \
else i + = xmlCopyChar ( l , & b [ i ] , v )
# define NEXTL(l) ctxt->cur += l
2001-02-23 17:55:21 +00:00
# define SKIP_BLANKS \
2003-10-18 16:20:14 +00:00
while ( IS_BLANK_CH ( * ( ctxt - > cur ) ) ) NEXT
2001-02-23 17:55:21 +00:00
# define CURRENT (*ctxt->cur)
# define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2001-03-03 12:09:03 +00:00
# ifndef DBL_DIG
# define DBL_DIG 16
# endif
# ifndef DBL_EPSILON
# define DBL_EPSILON 1E-9
# endif
# define UPPER_DOUBLE 1E9
# define LOWER_DOUBLE 1E-5
# define INTEGER_DIGITS DBL_DIG
# define FRACTION_DIGITS (DBL_DIG + 1)
# define EXPONENT_DIGITS (3 + 2)
/**
* xmlXPathFormatNumber :
* @ number : number to format
* @ buffer : output buffer
* @ buffersize : size of output buffer
*
* Convert the number into a string representation .
*/
static void
xmlXPathFormatNumber ( double number , char buffer [ ] , int buffersize )
{
2001-08-21 10:56:31 +00:00
switch ( xmlXPathIsInf ( number ) ) {
2001-03-03 12:09:03 +00:00
case 1 :
2002-03-27 09:05:40 +00:00
if ( buffersize > ( int ) sizeof ( " Infinity " ) )
2002-06-14 17:07:10 +00:00
snprintf ( buffer , buffersize , " Infinity " ) ;
2001-03-03 12:09:03 +00:00
break ;
case - 1 :
if ( buffersize > ( int ) sizeof ( " -Infinity " ) )
2002-06-14 17:07:10 +00:00
snprintf ( buffer , buffersize , " -Infinity " ) ;
2001-03-03 12:09:03 +00:00
break ;
default :
2001-08-21 10:56:31 +00:00
if ( xmlXPathIsNaN ( number ) ) {
2001-03-03 12:09:03 +00:00
if ( buffersize > ( int ) sizeof ( " NaN " ) )
2002-06-14 17:07:10 +00:00
snprintf ( buffer , buffersize , " NaN " ) ;
2002-03-28 18:25:31 +00:00
} else if ( number = = 0 & & xmlXPathGetSign ( number ) ! = 0 ) {
2002-06-14 17:07:10 +00:00
snprintf ( buffer , buffersize , " 0 " ) ;
2002-03-19 11:25:30 +00:00
} else if ( number = = ( ( int ) number ) ) {
char work [ 30 ] ;
char * ptr , * cur ;
int res , value = ( int ) number ;
ptr = & buffer [ 0 ] ;
if ( value < 0 ) {
* ptr + + = ' - ' ;
value = - value ;
}
if ( value = = 0 ) {
* ptr + + = ' 0 ' ;
} else {
cur = & work [ 0 ] ;
while ( value ! = 0 ) {
res = value % 10 ;
value = value / 10 ;
* cur + + = ' 0 ' + res ;
}
cur - - ;
while ( ( cur > = & work [ 0 ] ) & & ( ptr - buffer < buffersize ) ) {
* ptr + + = * cur - - ;
}
}
if ( ptr - buffer < buffersize ) {
* ptr = 0 ;
} else if ( buffersize > 0 ) {
ptr - - ;
* ptr = 0 ;
}
2001-03-03 12:09:03 +00:00
} else {
2001-04-21 16:57:29 +00:00
/* 3 is sign, decimal point, and terminating zero */
char work [ DBL_DIG + EXPONENT_DIGITS + 3 ] ;
int integer_place , fraction_place ;
char * ptr ;
char * after_fraction ;
double absolute_value ;
int size ;
absolute_value = fabs ( number ) ;
/*
* First choose format - scientific or regular floating point .
* In either case , result is in work , and after_fraction points
* just past the fractional part .
*/
if ( ( ( absolute_value > UPPER_DOUBLE ) | |
( absolute_value < LOWER_DOUBLE ) ) & &
( absolute_value ! = 0.0 ) ) {
/* Use scientific notation */
integer_place = DBL_DIG + EXPONENT_DIGITS + 1 ;
fraction_place = DBL_DIG - 1 ;
snprintf ( work , sizeof ( work ) , " %*.*e " ,
integer_place , fraction_place , number ) ;
after_fraction = strchr ( work + DBL_DIG , ' e ' ) ;
2001-03-03 12:09:03 +00:00
}
2001-04-21 16:57:29 +00:00
else {
/* Use regular notation */
2001-06-24 21:34:03 +00:00
if ( absolute_value > 0.0 )
integer_place = 1 + ( int ) log10 ( absolute_value ) ;
else
2001-06-24 21:39:39 +00:00
integer_place = 0 ;
2001-04-21 16:57:29 +00:00
fraction_place = ( integer_place > 0 )
? DBL_DIG - integer_place
: DBL_DIG ;
size = snprintf ( work , sizeof ( work ) , " %0.*f " ,
fraction_place , number ) ;
after_fraction = work + size ;
2001-03-03 12:09:03 +00:00
}
2001-04-21 16:57:29 +00:00
/* Remove fractional trailing zeroes */
ptr = after_fraction ;
while ( * ( - - ptr ) = = ' 0 ' )
;
if ( * ptr ! = ' . ' )
ptr + + ;
2003-09-12 15:32:16 +00:00
while ( ( * ptr + + = * after_fraction + + ) ! = 0 ) ;
2001-04-21 16:57:29 +00:00
/* Finally copy result back to caller */
size = strlen ( work ) + 1 ;
if ( size > buffersize ) {
work [ buffersize - 1 ] = 0 ;
size = buffersize ;
}
2003-09-12 15:32:16 +00:00
memmove ( buffer , work , size ) ;
2001-03-03 12:09:03 +00:00
}
break ;
}
}
2001-02-23 17:55:21 +00:00
/************************************************************************
* *
* Routines to handle NodeSets *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-03-26 00:38:10 +00:00
/**
* xmlXPathOrderDocElems :
* @ doc : an input document
*
* Call this routine to speed up XPath computation on static documents .
* This stamps all the element nodes with the document order
* Like for line information , the order is kept in the element - > content
* field , the value stored is actually - the node number ( startting at - 1 )
* to be able to differenciate from line numbers .
*
* Returns the number of element found in the document or - 1 in case
* of error .
*/
long
xmlXPathOrderDocElems ( xmlDocPtr doc ) {
long count = 0 ;
xmlNodePtr cur ;
if ( doc = = NULL )
return ( - 1 ) ;
cur = doc - > children ;
while ( cur ! = NULL ) {
if ( cur - > type = = XML_ELEMENT_NODE ) {
cur - > content = ( void * ) ( - ( + + count ) ) ;
if ( cur - > children ! = NULL ) {
cur = cur - > children ;
continue ;
}
}
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
continue ;
}
do {
cur = cur - > parent ;
if ( cur = = NULL )
break ;
if ( cur = = ( xmlNodePtr ) doc ) {
cur = NULL ;
break ;
}
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
break ;
}
} while ( cur ! = NULL ) ;
}
return ( count ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathCmpNodes :
* @ node1 : the first node
* @ node2 : the second node
*
* Compare two nodes w . r . t document order
*
* Returns - 2 in case of error 1 if first point < second point , 0 if
* that ' s the same node , - 1 otherwise
*/
int
xmlXPathCmpNodes ( xmlNodePtr node1 , xmlNodePtr node2 ) {
int depth1 , depth2 ;
2003-03-07 14:20:40 +00:00
int attr1 = 0 , attr2 = 0 ;
2001-02-23 17:55:21 +00:00
xmlNodePtr cur , root ;
if ( ( node1 = = NULL ) | | ( node2 = = NULL ) )
return ( - 2 ) ;
/*
* a couple of optimizations which will avoid computations in most cases
*/
2003-03-07 14:20:40 +00:00
if ( node1 - > type = = XML_ATTRIBUTE_NODE ) {
attr1 = 1 ;
node1 = node1 - > parent ;
}
if ( node2 - > type = = XML_ATTRIBUTE_NODE ) {
attr2 = 1 ;
node2 = node2 - > parent ;
}
if ( node1 = = node2 ) {
if ( attr1 = = attr2 )
return ( 0 ) ;
if ( attr2 = = 1 )
return ( 1 ) ;
return ( - 1 ) ;
}
2001-04-25 12:59:04 +00:00
if ( ( node1 - > type = = XML_NAMESPACE_DECL ) | |
( node2 - > type = = XML_NAMESPACE_DECL ) )
return ( 1 ) ;
2001-02-23 17:55:21 +00:00
if ( node1 = = node2 - > prev )
return ( 1 ) ;
if ( node1 = = node2 - > next )
return ( - 1 ) ;
2002-11-08 15:10:00 +00:00
/*
2003-03-26 00:38:10 +00:00
* Speedup using document order if availble .
2002-11-08 15:10:00 +00:00
*/
if ( ( node1 - > type = = XML_ELEMENT_NODE ) & &
( node2 - > type = = XML_ELEMENT_NODE ) & &
2003-03-26 00:38:10 +00:00
( 0 > ( long ) node1 - > content ) & &
( 0 > ( long ) node2 - > content ) & &
( node1 - > doc = = node2 - > doc ) ) {
long l1 , l2 ;
l1 = - ( ( long ) node1 - > content ) ;
l2 = - ( ( long ) node2 - > content ) ;
2002-11-08 15:10:00 +00:00
if ( l1 < l2 )
return ( 1 ) ;
if ( l1 > l2 )
return ( - 1 ) ;
}
2003-03-26 00:38:10 +00:00
2001-02-23 17:55:21 +00:00
/*
* compute depth to root
*/
for ( depth2 = 0 , cur = node2 ; cur - > parent ! = NULL ; cur = cur - > parent ) {
if ( cur = = node1 )
return ( 1 ) ;
depth2 + + ;
}
root = cur ;
for ( depth1 = 0 , cur = node1 ; cur - > parent ! = NULL ; cur = cur - > parent ) {
if ( cur = = node2 )
return ( - 1 ) ;
depth1 + + ;
}
/*
* Distinct document ( or distinct entities : - ( ) case .
*/
if ( root ! = cur ) {
return ( - 2 ) ;
}
/*
* get the nearest common ancestor .
*/
while ( depth1 > depth2 ) {
depth1 - - ;
node1 = node1 - > parent ;
}
while ( depth2 > depth1 ) {
depth2 - - ;
node2 = node2 - > parent ;
}
while ( node1 - > parent ! = node2 - > parent ) {
node1 = node1 - > parent ;
node2 = node2 - > parent ;
/* should not happen but just in case ... */
if ( ( node1 = = NULL ) | | ( node2 = = NULL ) )
return ( - 2 ) ;
}
/*
* Find who ' s first .
*/
if ( node1 = = node2 - > next )
return ( - 1 ) ;
for ( cur = node1 - > next ; cur ! = NULL ; cur = cur - > next )
if ( cur = = node2 )
return ( 1 ) ;
return ( - 1 ) ; /* assume there is no sibling list corruption */
}
/**
* xmlXPathNodeSetSort :
* @ set : the node set
*
* Sort the node set in document order
*/
void
xmlXPathNodeSetSort ( xmlNodeSetPtr set ) {
2001-03-03 12:09:03 +00:00
int i , j , incr , len ;
2001-02-23 17:55:21 +00:00
xmlNodePtr tmp ;
if ( set = = NULL )
return ;
/* Use Shell's sort to sort the node-set */
len = set - > nodeNr ;
for ( incr = len / 2 ; incr > 0 ; incr / = 2 ) {
for ( i = incr ; i < len ; i + + ) {
j = i - incr ;
while ( j > = 0 ) {
2001-03-03 12:09:03 +00:00
if ( xmlXPathCmpNodes ( set - > nodeTab [ j ] ,
set - > nodeTab [ j + incr ] ) = = - 1 ) {
2001-02-23 17:55:21 +00:00
tmp = set - > nodeTab [ j ] ;
set - > nodeTab [ j ] = set - > nodeTab [ j + incr ] ;
set - > nodeTab [ j + incr ] = tmp ;
j - = incr ;
} else
break ;
}
}
}
}
# define XML_NODESET_DEFAULT 10
2002-03-04 17:09:44 +00:00
/**
* xmlXPathNodeSetDupNs :
* @ node : the parent node of the namespace XPath node
* @ ns : the libxml namespace declaration node .
*
* Namespace node in libxml don ' t match the XPath semantic . In a node set
* the namespace nodes are duplicated and the next pointer is set to the
* parent node in the XPath semantic .
*
* Returns the newly created object .
*/
static xmlNodePtr
xmlXPathNodeSetDupNs ( xmlNodePtr node , xmlNsPtr ns ) {
xmlNsPtr cur ;
if ( ( ns = = NULL ) | | ( ns - > type ! = XML_NAMESPACE_DECL ) )
return ( NULL ) ;
if ( ( node = = NULL ) | | ( node - > type = = XML_NAMESPACE_DECL ) )
return ( ( xmlNodePtr ) ns ) ;
/*
* Allocate a new Namespace and fill the fields .
*/
cur = ( xmlNsPtr ) xmlMalloc ( sizeof ( xmlNs ) ) ;
if ( cur = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " duplicating namespace \n " ) ;
2002-03-04 17:09:44 +00:00
return ( NULL ) ;
}
memset ( cur , 0 , sizeof ( xmlNs ) ) ;
cur - > type = XML_NAMESPACE_DECL ;
if ( ns - > href ! = NULL )
cur - > href = xmlStrdup ( ns - > href ) ;
if ( ns - > prefix ! = NULL )
cur - > prefix = xmlStrdup ( ns - > prefix ) ;
cur - > next = ( xmlNsPtr ) node ;
return ( ( xmlNodePtr ) cur ) ;
}
/**
* xmlXPathNodeSetFreeNs :
* @ ns : the XPath namespace node found in a nodeset .
*
* Namespace node in libxml don ' t match the XPath semantic . In a node set
* the namespace nodes are duplicated and the next pointer is set to the
* parent node in the XPath semantic . Check if such a node need to be freed
*/
2002-06-04 04:27:06 +00:00
void
2002-03-04 17:09:44 +00:00
xmlXPathNodeSetFreeNs ( xmlNsPtr ns ) {
if ( ( ns = = NULL ) | | ( ns - > type ! = XML_NAMESPACE_DECL ) )
return ;
if ( ( ns - > next ! = NULL ) & & ( ns - > next - > type ! = XML_NAMESPACE_DECL ) ) {
if ( ns - > href ! = NULL )
xmlFree ( ( xmlChar * ) ns - > href ) ;
if ( ns - > prefix ! = NULL )
xmlFree ( ( xmlChar * ) ns - > prefix ) ;
xmlFree ( ns ) ;
}
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathNodeSetCreate :
* @ val : an initial xmlNodePtr , or NULL
*
* Create a new xmlNodeSetPtr of type double and of value @ val
*
* Returns the newly created object .
*/
xmlNodeSetPtr
xmlXPathNodeSetCreate ( xmlNodePtr val ) {
xmlNodeSetPtr ret ;
ret = ( xmlNodeSetPtr ) xmlMalloc ( sizeof ( xmlNodeSet ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
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 ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating nodeset \n " ) ;
xmlFree ( ret ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret - > nodeTab , 0 ,
XML_NODESET_DEFAULT * ( size_t ) sizeof ( xmlNodePtr ) ) ;
ret - > nodeMax = XML_NODESET_DEFAULT ;
2002-03-04 17:09:44 +00:00
if ( val - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns = ( xmlNsPtr ) val ;
ret - > nodeTab [ ret - > nodeNr + + ] =
xmlXPathNodeSetDupNs ( ( xmlNodePtr ) ns - > next , ns ) ;
} else
ret - > nodeTab [ ret - > nodeNr + + ] = val ;
2001-02-23 17:55:21 +00:00
}
return ( ret ) ;
}
2001-07-16 04:52:57 +00:00
/**
* xmlXPathNodeSetContains :
* @ cur : the node - set
* @ val : the node
*
* checks whether @ cur contains @ val
*
* Returns true ( 1 ) if @ cur contains @ val , false ( 0 ) otherwise
*/
int
xmlXPathNodeSetContains ( xmlNodeSetPtr cur , xmlNodePtr val ) {
int i ;
2002-03-04 17:09:44 +00:00
if ( val - > type = = XML_NAMESPACE_DECL ) {
for ( i = 0 ; i < cur - > nodeNr ; i + + ) {
if ( cur - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns1 , ns2 ;
ns1 = ( xmlNsPtr ) val ;
ns2 = ( xmlNsPtr ) cur - > nodeTab [ i ] ;
if ( ns1 = = ns2 )
return ( 1 ) ;
if ( ( ns1 - > next ! = NULL ) & & ( ns2 - > next = = ns1 - > next ) & &
( xmlStrEqual ( ns1 - > prefix , ns2 - > prefix ) ) )
return ( 1 ) ;
}
}
} else {
for ( i = 0 ; i < cur - > nodeNr ; i + + ) {
if ( cur - > nodeTab [ i ] = = val )
return ( 1 ) ;
}
2001-07-16 04:52:57 +00:00
}
return ( 0 ) ;
}
2002-03-04 17:09:44 +00:00
/**
* xmlXPathNodeSetAddNs :
* @ cur : the initial node set
* @ node : the hosting node
* @ ns : a the namespace node
*
* add a new namespace node to an existing NodeSet
*/
2002-05-14 06:41:32 +00:00
void
2002-03-04 17:09:44 +00:00
xmlXPathNodeSetAddNs ( xmlNodeSetPtr cur , xmlNodePtr node , xmlNsPtr ns ) {
int i ;
if ( ( ns = = NULL ) | | ( node = = NULL ) | | ( ns - > type ! = XML_NAMESPACE_DECL ) | |
( node - > type ! = XML_ELEMENT_NODE ) )
return ;
/* @@ with_ns to check wether namespace nodes should be looked at @@ */
/*
* check against doublons
*/
for ( i = 0 ; i < cur - > nodeNr ; i + + ) {
if ( ( cur - > nodeTab [ i ] ! = NULL ) & &
( cur - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) & &
2002-03-19 18:35:12 +00:00
( ( ( xmlNsPtr ) cur - > nodeTab [ i ] ) - > next = = ( xmlNsPtr ) node ) & &
2002-03-04 17:09:44 +00:00
( xmlStrEqual ( ns - > prefix , ( ( xmlNsPtr ) cur - > nodeTab [ i ] ) - > prefix ) ) )
return ;
}
/*
* grow the nodeTab if needed
*/
if ( cur - > nodeMax = = 0 ) {
cur - > nodeTab = ( xmlNodePtr * ) xmlMalloc ( XML_NODESET_DEFAULT *
sizeof ( xmlNodePtr ) ) ;
if ( cur - > nodeTab = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " growing nodeset \n " ) ;
2002-03-04 17:09:44 +00:00
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 ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " growing nodeset \n " ) ;
2002-03-04 17:09:44 +00:00
return ;
}
cur - > nodeTab = temp ;
}
cur - > nodeTab [ cur - > nodeNr + + ] = xmlXPathNodeSetDupNs ( node , ns ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathNodeSetAdd :
* @ cur : the initial node set
* @ val : a new xmlNodePtr
*
2001-12-31 16:16:02 +00:00
* add a new xmlNodePtr to an existing NodeSet
2001-02-23 17:55:21 +00:00
*/
void
xmlXPathNodeSetAdd ( xmlNodeSetPtr cur , xmlNodePtr val ) {
int i ;
if ( val = = NULL ) return ;
2003-03-24 13:57:34 +00:00
#if 0
2003-02-04 19:28:49 +00:00
if ( ( val - > type = = XML_ELEMENT_NODE ) & & ( val - > name [ 0 ] = = ' ' ) )
return ; /* an XSLT fake node */
2003-03-24 13:57:34 +00:00
# endif
2003-02-04 19:28:49 +00:00
2002-03-04 17:09:44 +00:00
/* @@ with_ns to check wether namespace nodes should be looked at @@ */
2001-02-23 17:55:21 +00:00
/*
* 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 ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " growing nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
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 ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " growing nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
return ;
}
cur - > nodeTab = temp ;
}
2002-03-04 17:09:44 +00:00
if ( val - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns = ( xmlNsPtr ) val ;
cur - > nodeTab [ cur - > nodeNr + + ] =
xmlXPathNodeSetDupNs ( ( xmlNodePtr ) ns - > next , ns ) ;
} else
cur - > nodeTab [ cur - > nodeNr + + ] = val ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathNodeSetAddUnique :
* @ cur : the initial node set
* @ val : a new xmlNodePtr
*
2001-12-31 16:16:02 +00:00
* add a new xmlNodePtr to an existing NodeSet , optimized version
2001-02-23 17:55:21 +00:00
* when we are sure the node is not already in the set .
*/
void
xmlXPathNodeSetAddUnique ( xmlNodeSetPtr cur , xmlNodePtr val ) {
if ( val = = NULL ) return ;
2003-03-24 13:57:34 +00:00
#if 0
2003-02-04 19:28:49 +00:00
if ( ( val - > type = = XML_ELEMENT_NODE ) & & ( val - > name [ 0 ] = = ' ' ) )
return ; /* an XSLT fake node */
2003-03-24 13:57:34 +00:00
# endif
2003-02-04 19:28:49 +00:00
2002-03-04 17:09:44 +00:00
/* @@ with_ns to check wether namespace nodes should be looked at @@ */
2001-02-23 17:55:21 +00:00
/*
* grow the nodeTab if needed
*/
if ( cur - > nodeMax = = 0 ) {
cur - > nodeTab = ( xmlNodePtr * ) xmlMalloc ( XML_NODESET_DEFAULT *
sizeof ( xmlNodePtr ) ) ;
if ( cur - > nodeTab = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " growing nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
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 ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " growing nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
return ;
}
cur - > nodeTab = temp ;
}
2002-03-04 17:09:44 +00:00
if ( val - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns = ( xmlNsPtr ) val ;
cur - > nodeTab [ cur - > nodeNr + + ] =
xmlXPathNodeSetDupNs ( ( xmlNodePtr ) ns - > next , ns ) ;
} else
cur - > nodeTab [ cur - > nodeNr + + ] = val ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathNodeSetMerge :
* @ 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
*
2001-12-31 16:16:02 +00:00
* Returns @ val1 once extended or NULL in case of error .
2001-02-23 17:55:21 +00:00
*/
xmlNodeSetPtr
xmlXPathNodeSetMerge ( xmlNodeSetPtr val1 , xmlNodeSetPtr val2 ) {
2001-04-05 16:54:14 +00:00
int i , j , initNr , skip ;
2001-02-23 17:55:21 +00:00
if ( val2 = = NULL ) return ( val1 ) ;
if ( val1 = = NULL ) {
val1 = xmlXPathNodeSetCreate ( NULL ) ;
}
2002-03-04 17:09:44 +00:00
/* @@ with_ns to check wether namespace nodes should be looked at @@ */
2001-02-23 17:55:21 +00:00
initNr = val1 - > nodeNr ;
for ( i = 0 ; i < val2 - > nodeNr ; i + + ) {
/*
* check against doublons
*/
2001-04-05 16:54:14 +00:00
skip = 0 ;
for ( j = 0 ; j < initNr ; j + + ) {
if ( val1 - > nodeTab [ j ] = = val2 - > nodeTab [ i ] ) {
skip = 1 ;
break ;
2002-03-04 17:09:44 +00:00
} else if ( ( val1 - > nodeTab [ j ] - > type = = XML_NAMESPACE_DECL ) & &
( val2 - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) ) {
xmlNsPtr ns1 , ns2 ;
ns1 = ( xmlNsPtr ) val1 - > nodeTab [ j ] ;
ns2 = ( xmlNsPtr ) val2 - > nodeTab [ i ] ;
if ( ( ns1 - > next = = ns2 - > next ) & &
( xmlStrEqual ( ns1 - > prefix , ns2 - > prefix ) ) ) {
skip = 1 ;
break ;
}
2001-04-05 16:54:14 +00:00
}
}
if ( skip )
continue ;
2001-02-23 17:55:21 +00:00
/*
* grow the nodeTab if needed
*/
if ( val1 - > nodeMax = = 0 ) {
val1 - > nodeTab = ( xmlNodePtr * ) xmlMalloc ( XML_NODESET_DEFAULT *
sizeof ( xmlNodePtr ) ) ;
if ( val1 - > nodeTab = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " merging nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( val1 - > nodeTab , 0 ,
XML_NODESET_DEFAULT * ( size_t ) sizeof ( xmlNodePtr ) ) ;
val1 - > nodeMax = XML_NODESET_DEFAULT ;
} else if ( val1 - > nodeNr = = val1 - > nodeMax ) {
xmlNodePtr * temp ;
val1 - > nodeMax * = 2 ;
temp = ( xmlNodePtr * ) xmlRealloc ( val1 - > nodeTab , val1 - > nodeMax *
sizeof ( xmlNodePtr ) ) ;
if ( temp = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " merging nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
val1 - > nodeTab = temp ;
}
2002-03-04 17:09:44 +00:00
if ( val2 - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns = ( xmlNsPtr ) val2 - > nodeTab [ i ] ;
val1 - > nodeTab [ val1 - > nodeNr + + ] =
xmlXPathNodeSetDupNs ( ( xmlNodePtr ) ns - > next , ns ) ;
} else
val1 - > nodeTab [ val1 - > nodeNr + + ] = val2 - > nodeTab [ i ] ;
2001-02-23 17:55:21 +00:00
}
return ( val1 ) ;
}
2002-03-13 10:03:35 +00:00
/**
* xmlXPathNodeSetMergeUnique :
* @ 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 .
*/
static xmlNodeSetPtr
xmlXPathNodeSetMergeUnique ( xmlNodeSetPtr val1 , xmlNodeSetPtr val2 ) {
2003-07-31 14:47:38 +00:00
int i ;
2002-03-13 10:03:35 +00:00
if ( val2 = = NULL ) return ( val1 ) ;
if ( val1 = = NULL ) {
val1 = xmlXPathNodeSetCreate ( NULL ) ;
}
/* @@ with_ns to check wether namespace nodes should be looked at @@ */
for ( i = 0 ; i < val2 - > nodeNr ; i + + ) {
/*
* grow the nodeTab if needed
*/
if ( val1 - > nodeMax = = 0 ) {
val1 - > nodeTab = ( xmlNodePtr * ) xmlMalloc ( XML_NODESET_DEFAULT *
sizeof ( xmlNodePtr ) ) ;
if ( val1 - > nodeTab = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " merging nodeset \n " ) ;
2002-03-13 10:03:35 +00:00
return ( NULL ) ;
}
memset ( val1 - > nodeTab , 0 ,
XML_NODESET_DEFAULT * ( size_t ) sizeof ( xmlNodePtr ) ) ;
val1 - > nodeMax = XML_NODESET_DEFAULT ;
} else if ( val1 - > nodeNr = = val1 - > nodeMax ) {
xmlNodePtr * temp ;
val1 - > nodeMax * = 2 ;
temp = ( xmlNodePtr * ) xmlRealloc ( val1 - > nodeTab , val1 - > nodeMax *
sizeof ( xmlNodePtr ) ) ;
if ( temp = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " merging nodeset \n " ) ;
2002-03-13 10:03:35 +00:00
return ( NULL ) ;
}
val1 - > nodeTab = temp ;
}
if ( val2 - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns = ( xmlNsPtr ) val2 - > nodeTab [ i ] ;
val1 - > nodeTab [ val1 - > nodeNr + + ] =
xmlXPathNodeSetDupNs ( ( xmlNodePtr ) ns - > next , ns ) ;
} else
val1 - > nodeTab [ val1 - > nodeNr + + ] = val2 - > nodeTab [ i ] ;
}
return ( val1 ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathNodeSetDel :
* @ cur : the initial node set
* @ val : an xmlNodePtr
*
* Removes an xmlNodePtr from an existing NodeSet
*/
void
xmlXPathNodeSetDel ( 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 ;
if ( i > = cur - > nodeNr ) {
# ifdef DEBUG
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathNodeSetDel: Node %s wasn't found in NodeList \n " ,
val - > name ) ;
# endif
return ;
}
2002-03-04 17:09:44 +00:00
if ( ( cur - > nodeTab [ i ] ! = NULL ) & &
( cur - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) )
xmlXPathNodeSetFreeNs ( ( xmlNsPtr ) cur - > nodeTab [ i ] ) ;
2001-02-23 17:55:21 +00:00
cur - > nodeNr - - ;
for ( ; i < cur - > nodeNr ; i + + )
cur - > nodeTab [ i ] = cur - > nodeTab [ i + 1 ] ;
cur - > nodeTab [ cur - > nodeNr ] = NULL ;
}
/**
* xmlXPathNodeSetRemove :
* @ cur : the initial node set
* @ val : the index to remove
*
* Removes an entry from an existing NodeSet list .
*/
void
xmlXPathNodeSetRemove ( xmlNodeSetPtr cur , int val ) {
if ( cur = = NULL ) return ;
if ( val > = cur - > nodeNr ) return ;
2002-03-04 17:09:44 +00:00
if ( ( cur - > nodeTab [ val ] ! = NULL ) & &
( cur - > nodeTab [ val ] - > type = = XML_NAMESPACE_DECL ) )
xmlXPathNodeSetFreeNs ( ( xmlNsPtr ) cur - > nodeTab [ val ] ) ;
2001-02-23 17:55:21 +00:00
cur - > nodeNr - - ;
for ( ; val < cur - > nodeNr ; val + + )
cur - > nodeTab [ val ] = cur - > nodeTab [ val + 1 ] ;
cur - > nodeTab [ cur - > nodeNr ] = NULL ;
}
/**
* xmlXPathFreeNodeSet :
* @ obj : the xmlNodeSetPtr to free
*
* Free the NodeSet compound ( not the actual nodes ! ) .
*/
void
xmlXPathFreeNodeSet ( xmlNodeSetPtr obj ) {
if ( obj = = NULL ) return ;
if ( obj - > nodeTab ! = NULL ) {
2002-03-04 17:09:44 +00:00
int i ;
/* @@ with_ns to check wether namespace nodes should be looked at @@ */
for ( i = 0 ; i < obj - > nodeNr ; i + + )
if ( ( obj - > nodeTab [ i ] ! = NULL ) & &
( obj - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) )
xmlXPathNodeSetFreeNs ( ( xmlNsPtr ) obj - > nodeTab [ i ] ) ;
2001-02-23 17:55:21 +00:00
xmlFree ( obj - > nodeTab ) ;
}
xmlFree ( obj ) ;
}
/**
* xmlXPathFreeValueTree :
* @ obj : the xmlNodeSetPtr to free
*
* Free the NodeSet compound and the actual tree , this is different
* from xmlXPathFreeNodeSet ( )
*/
2001-03-24 17:00:36 +00:00
static void
2001-02-23 17:55:21 +00:00
xmlXPathFreeValueTree ( xmlNodeSetPtr obj ) {
int i ;
if ( obj = = NULL ) return ;
if ( obj - > nodeTab ! = NULL ) {
2002-03-04 17:09:44 +00:00
for ( i = 0 ; i < obj - > nodeNr ; i + + ) {
if ( obj - > nodeTab [ i ] ! = NULL ) {
if ( obj - > nodeTab [ i ] - > type = = XML_NAMESPACE_DECL ) {
xmlXPathNodeSetFreeNs ( ( xmlNsPtr ) obj - > nodeTab [ i ] ) ;
} else {
xmlFreeNodeList ( obj - > nodeTab [ i ] ) ;
}
}
}
2001-02-23 17:55:21 +00:00
xmlFree ( obj - > nodeTab ) ;
}
xmlFree ( obj ) ;
}
# if defined(DEBUG) || defined(DEBUG_STEP)
/**
* xmlGenericErrorContextNodeSet :
* @ output : a FILE * for the output
* @ obj : the xmlNodeSetPtr to free
*
* Quick display of a NodeSet
*/
void
xmlGenericErrorContextNodeSet ( FILE * output , xmlNodeSetPtr obj ) {
int i ;
if ( output = = NULL ) output = xmlGenericErrorContext ;
if ( obj = = NULL ) {
fprintf ( output , " NodeSet == NULL ! \n " ) ;
return ;
}
if ( obj - > nodeNr = = 0 ) {
fprintf ( output , " NodeSet is empty \n " ) ;
return ;
}
if ( obj - > nodeTab = = NULL ) {
fprintf ( output , " nodeTab == NULL ! \n " ) ;
return ;
}
for ( i = 0 ; i < obj - > nodeNr ; i + + ) {
if ( obj - > nodeTab [ i ] = = NULL ) {
fprintf ( output , " NULL ! \n " ) ;
return ;
}
if ( ( obj - > nodeTab [ i ] - > type = = XML_DOCUMENT_NODE ) | |
( obj - > nodeTab [ i ] - > type = = XML_HTML_DOCUMENT_NODE ) )
fprintf ( output , " / " ) ;
else if ( obj - > nodeTab [ i ] - > name = = NULL )
fprintf ( output , " noname! " ) ;
else fprintf ( output , " %s " , obj - > nodeTab [ i ] - > name ) ;
}
fprintf ( output , " \n " ) ;
}
# endif
/**
* xmlXPathNewNodeSet :
* @ val : the NodePtr value
*
* Create a new xmlXPathObjectPtr of type NodeSet and initialize
* it with the single Node @ val
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathNewNodeSet ( xmlNodePtr val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating nodeset \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_NODESET ;
2001-02-27 21:54:07 +00:00
ret - > boolval = 0 ;
2001-02-23 17:55:21 +00:00
ret - > nodesetval = xmlXPathNodeSetCreate ( val ) ;
2002-03-04 17:09:44 +00:00
/* @@ with_ns to check wether namespace nodes should be looked at @@ */
2001-02-23 17:55:21 +00:00
return ( ret ) ;
}
/**
* xmlXPathNewValueTree :
* @ val : the NodePtr value
*
* Create a new xmlXPathObjectPtr of type Value Tree ( XSLT ) and initialize
* it with the tree root @ val
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathNewValueTree ( xmlNodePtr val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating result value tree \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_XSLT_TREE ;
2001-08-14 16:43:10 +00:00
ret - > boolval = 1 ;
ret - > user = ( void * ) val ;
2001-02-23 17:55:21 +00:00
ret - > nodesetval = xmlXPathNodeSetCreate ( val ) ;
return ( ret ) ;
}
/**
* xmlXPathNewNodeSetList :
* @ val : an existing NodeSet
*
* Create a new xmlXPathObjectPtr of type NodeSet and initialize
* it with the Nodeset @ val
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
2002-03-04 17:09:44 +00:00
xmlXPathNewNodeSetList ( xmlNodeSetPtr val )
{
2001-02-23 17:55:21 +00:00
xmlXPathObjectPtr ret ;
int i ;
if ( val = = NULL )
2002-03-04 17:09:44 +00:00
ret = NULL ;
2001-02-23 17:55:21 +00:00
else if ( val - > nodeTab = = NULL )
2002-03-04 17:09:44 +00:00
ret = xmlXPathNewNodeSet ( NULL ) ;
else {
ret = xmlXPathNewNodeSet ( val - > nodeTab [ 0 ] ) ;
for ( i = 1 ; i < val - > nodeNr ; + + i )
xmlXPathNodeSetAddUnique ( ret - > nodesetval , val - > nodeTab [ i ] ) ;
}
2001-02-23 17:55:21 +00:00
2002-03-04 17:09:44 +00:00
return ( ret ) ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathWrapNodeSet :
* @ val : the NodePtr value
*
* Wrap the Nodeset @ val in a new xmlXPathObjectPtr
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathWrapNodeSet ( xmlNodeSetPtr val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating node set object \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_NODESET ;
ret - > nodesetval = val ;
return ( ret ) ;
}
/**
* xmlXPathFreeNodeSetList :
* @ obj : an existing NodeSetList object
*
* Free up the xmlXPathObjectPtr @ obj but don ' t deallocate the objects in
* the list contrary to xmlXPathFreeObject ( ) .
*/
void
xmlXPathFreeNodeSetList ( xmlXPathObjectPtr obj ) {
if ( obj = = NULL ) return ;
xmlFree ( obj ) ;
}
2001-07-16 04:52:57 +00:00
/**
* xmlXPathDifference :
* @ nodes1 : a node - set
* @ nodes2 : a node - set
*
* Implements the EXSLT - Sets difference ( ) function :
* node - set set : difference ( node - set , node - set )
*
* Returns the difference between the two node sets , or nodes1 if
* nodes2 is empty
*/
xmlNodeSetPtr
xmlXPathDifference ( xmlNodeSetPtr nodes1 , xmlNodeSetPtr nodes2 ) {
xmlNodeSetPtr ret ;
int i , l1 ;
xmlNodePtr cur ;
if ( xmlXPathNodeSetIsEmpty ( nodes2 ) )
return ( nodes1 ) ;
ret = xmlXPathNodeSetCreate ( NULL ) ;
if ( xmlXPathNodeSetIsEmpty ( nodes1 ) )
return ( ret ) ;
l1 = xmlXPathNodeSetGetLength ( nodes1 ) ;
for ( i = 0 ; i < l1 ; i + + ) {
cur = xmlXPathNodeSetItem ( nodes1 , i ) ;
if ( ! xmlXPathNodeSetContains ( nodes2 , cur ) )
xmlXPathNodeSetAddUnique ( ret , cur ) ;
}
return ( ret ) ;
}
/**
* xmlXPathIntersection :
* @ nodes1 : a node - set
* @ nodes2 : a node - set
*
* Implements the EXSLT - Sets intersection ( ) function :
* node - set set : intersection ( node - set , node - set )
*
* Returns a node set comprising the nodes that are within both the
* node sets passed as arguments
*/
xmlNodeSetPtr
xmlXPathIntersection ( xmlNodeSetPtr nodes1 , xmlNodeSetPtr nodes2 ) {
xmlNodeSetPtr ret = xmlXPathNodeSetCreate ( NULL ) ;
int i , l1 ;
xmlNodePtr cur ;
if ( xmlXPathNodeSetIsEmpty ( nodes1 ) )
return ( ret ) ;
if ( xmlXPathNodeSetIsEmpty ( nodes2 ) )
return ( ret ) ;
l1 = xmlXPathNodeSetGetLength ( nodes1 ) ;
for ( i = 0 ; i < l1 ; i + + ) {
cur = xmlXPathNodeSetItem ( nodes1 , i ) ;
if ( xmlXPathNodeSetContains ( nodes2 , cur ) )
xmlXPathNodeSetAddUnique ( ret , cur ) ;
}
return ( ret ) ;
}
/**
* xmlXPathDistinctSorted :
* @ nodes : a node - set , sorted by document order
*
* Implements the EXSLT - Sets distinct ( ) function :
* node - set set : distinct ( node - set )
*
* Returns a subset of the nodes contained in @ nodes , or @ nodes if
* it is empty
*/
xmlNodeSetPtr
xmlXPathDistinctSorted ( xmlNodeSetPtr nodes ) {
xmlNodeSetPtr ret ;
xmlHashTablePtr hash ;
int i , l ;
xmlChar * strval ;
xmlNodePtr cur ;
if ( xmlXPathNodeSetIsEmpty ( nodes ) )
return ( nodes ) ;
ret = xmlXPathNodeSetCreate ( NULL ) ;
l = xmlXPathNodeSetGetLength ( nodes ) ;
hash = xmlHashCreate ( l ) ;
for ( i = 0 ; i < l ; i + + ) {
cur = xmlXPathNodeSetItem ( nodes , i ) ;
strval = xmlXPathCastNodeToString ( cur ) ;
if ( xmlHashLookup ( hash , strval ) = = NULL ) {
xmlHashAddEntry ( hash , strval , strval ) ;
xmlXPathNodeSetAddUnique ( ret , cur ) ;
} else {
xmlFree ( strval ) ;
}
}
xmlHashFree ( hash , ( xmlHashDeallocator ) xmlFree ) ;
return ( ret ) ;
}
/**
* xmlXPathDistinct :
* @ nodes : a node - set
*
* Implements the EXSLT - Sets distinct ( ) function :
* node - set set : distinct ( node - set )
* @ nodes is sorted by document order , then # exslSetsDistinctSorted
* is called with the sorted node - set
*
* Returns a subset of the nodes contained in @ nodes , or @ nodes if
* it is empty
*/
xmlNodeSetPtr
xmlXPathDistinct ( xmlNodeSetPtr nodes ) {
if ( xmlXPathNodeSetIsEmpty ( nodes ) )
return ( nodes ) ;
xmlXPathNodeSetSort ( nodes ) ;
return ( xmlXPathDistinctSorted ( nodes ) ) ;
}
/**
* xmlXPathHasSameNodes :
* @ nodes1 : a node - set
* @ nodes2 : a node - set
*
* Implements the EXSLT - Sets has - same - nodes function :
* boolean set : has - same - node ( node - set , node - set )
*
* Returns true ( 1 ) if @ nodes1 shares any node with @ nodes2 , false ( 0 )
* otherwise
*/
int
xmlXPathHasSameNodes ( xmlNodeSetPtr nodes1 , xmlNodeSetPtr nodes2 ) {
int i , l ;
xmlNodePtr cur ;
if ( xmlXPathNodeSetIsEmpty ( nodes1 ) | |
xmlXPathNodeSetIsEmpty ( nodes2 ) )
return ( 0 ) ;
l = xmlXPathNodeSetGetLength ( nodes1 ) ;
for ( i = 0 ; i < l ; i + + ) {
cur = xmlXPathNodeSetItem ( nodes1 , i ) ;
if ( xmlXPathNodeSetContains ( nodes2 , cur ) )
return ( 1 ) ;
}
return ( 0 ) ;
}
/**
* xmlXPathNodeLeadingSorted :
* @ nodes : a node - set , sorted by document order
* @ node : a node
*
* Implements the EXSLT - Sets leading ( ) function :
* node - set set : leading ( node - set , node - set )
*
* Returns the nodes in @ nodes that precede @ node in document order ,
* @ nodes if @ node is NULL or an empty node - set if @ nodes
* doesn ' t contain @ node
*/
xmlNodeSetPtr
xmlXPathNodeLeadingSorted ( xmlNodeSetPtr nodes , xmlNodePtr node ) {
int i , l ;
xmlNodePtr cur ;
xmlNodeSetPtr ret ;
if ( node = = NULL )
return ( nodes ) ;
ret = xmlXPathNodeSetCreate ( NULL ) ;
if ( xmlXPathNodeSetIsEmpty ( nodes ) | |
( ! xmlXPathNodeSetContains ( nodes , node ) ) )
return ( ret ) ;
l = xmlXPathNodeSetGetLength ( nodes ) ;
for ( i = 0 ; i < l ; i + + ) {
cur = xmlXPathNodeSetItem ( nodes , i ) ;
if ( cur = = node )
break ;
xmlXPathNodeSetAddUnique ( ret , cur ) ;
}
return ( ret ) ;
}
/**
* xmlXPathNodeLeading :
* @ nodes : a node - set
* @ node : a node
*
* Implements the EXSLT - Sets leading ( ) function :
* node - set set : leading ( node - set , node - set )
* @ nodes is sorted by document order , then # exslSetsNodeLeadingSorted
* is called .
*
* Returns the nodes in @ nodes that precede @ node in document order ,
* @ nodes if @ node is NULL or an empty node - set if @ nodes
* doesn ' t contain @ node
*/
xmlNodeSetPtr
xmlXPathNodeLeading ( xmlNodeSetPtr nodes , xmlNodePtr node ) {
xmlXPathNodeSetSort ( nodes ) ;
return ( xmlXPathNodeLeadingSorted ( nodes , node ) ) ;
}
/**
* xmlXPathLeadingSorted :
* @ nodes1 : a node - set , sorted by document order
* @ nodes2 : a node - set , sorted by document order
*
* Implements the EXSLT - Sets leading ( ) function :
* node - set set : leading ( node - set , node - set )
*
* Returns the nodes in @ nodes1 that precede the first node in @ nodes2
* in document order , @ nodes1 if @ nodes2 is NULL or empty or
* an empty node - set if @ nodes1 doesn ' t contain @ nodes2
*/
xmlNodeSetPtr
xmlXPathLeadingSorted ( xmlNodeSetPtr nodes1 , xmlNodeSetPtr nodes2 ) {
if ( xmlXPathNodeSetIsEmpty ( nodes2 ) )
return ( nodes1 ) ;
return ( xmlXPathNodeLeadingSorted ( nodes1 ,
xmlXPathNodeSetItem ( nodes2 , 1 ) ) ) ;
}
/**
* xmlXPathLeading :
* @ nodes1 : a node - set
* @ nodes2 : a node - set
*
* Implements the EXSLT - Sets leading ( ) function :
* node - set set : leading ( node - set , node - set )
* @ nodes1 and @ nodes2 are sorted by document order , then
* # exslSetsLeadingSorted is called .
*
* Returns the nodes in @ nodes1 that precede the first node in @ nodes2
* in document order , @ nodes1 if @ nodes2 is NULL or empty or
* an empty node - set if @ nodes1 doesn ' t contain @ nodes2
*/
xmlNodeSetPtr
xmlXPathLeading ( xmlNodeSetPtr nodes1 , xmlNodeSetPtr nodes2 ) {
if ( xmlXPathNodeSetIsEmpty ( nodes2 ) )
return ( nodes1 ) ;
if ( xmlXPathNodeSetIsEmpty ( nodes1 ) )
return ( xmlXPathNodeSetCreate ( NULL ) ) ;
xmlXPathNodeSetSort ( nodes1 ) ;
xmlXPathNodeSetSort ( nodes2 ) ;
return ( xmlXPathNodeLeadingSorted ( nodes1 ,
xmlXPathNodeSetItem ( nodes2 , 1 ) ) ) ;
}
/**
* xmlXPathNodeTrailingSorted :
* @ nodes : a node - set , sorted by document order
* @ node : a node
*
* Implements the EXSLT - Sets trailing ( ) function :
* node - set set : trailing ( node - set , node - set )
*
* Returns the nodes in @ nodes that follow @ node in document order ,
* @ nodes if @ node is NULL or an empty node - set if @ nodes
* doesn ' t contain @ node
*/
xmlNodeSetPtr
xmlXPathNodeTrailingSorted ( xmlNodeSetPtr nodes , xmlNodePtr node ) {
int i , l ;
xmlNodePtr cur ;
xmlNodeSetPtr ret ;
if ( node = = NULL )
return ( nodes ) ;
ret = xmlXPathNodeSetCreate ( NULL ) ;
if ( xmlXPathNodeSetIsEmpty ( nodes ) | |
( ! xmlXPathNodeSetContains ( nodes , node ) ) )
return ( ret ) ;
l = xmlXPathNodeSetGetLength ( nodes ) ;
2001-07-31 23:30:37 +00:00
for ( i = l ; i > 0 ; i - - ) {
2001-07-16 04:52:57 +00:00
cur = xmlXPathNodeSetItem ( nodes , i ) ;
if ( cur = = node )
break ;
xmlXPathNodeSetAddUnique ( ret , cur ) ;
}
return ( ret ) ;
}
/**
* xmlXPathNodeTrailing :
* @ nodes : a node - set
* @ node : a node
*
* Implements the EXSLT - Sets trailing ( ) function :
* node - set set : trailing ( node - set , node - set )
* @ nodes is sorted by document order , then # xmlXPathNodeTrailingSorted
* is called .
*
* Returns the nodes in @ nodes that follow @ node in document order ,
* @ nodes if @ node is NULL or an empty node - set if @ nodes
* doesn ' t contain @ node
*/
xmlNodeSetPtr
xmlXPathNodeTrailing ( xmlNodeSetPtr nodes , xmlNodePtr node ) {
xmlXPathNodeSetSort ( nodes ) ;
return ( xmlXPathNodeTrailingSorted ( nodes , node ) ) ;
}
/**
* xmlXPathTrailingSorted :
* @ nodes1 : a node - set , sorted by document order
* @ nodes2 : a node - set , sorted by document order
*
* Implements the EXSLT - Sets trailing ( ) function :
* node - set set : trailing ( node - set , node - set )
*
* Returns the nodes in @ nodes1 that follow the first node in @ nodes2
* in document order , @ nodes1 if @ nodes2 is NULL or empty or
* an empty node - set if @ nodes1 doesn ' t contain @ nodes2
*/
xmlNodeSetPtr
xmlXPathTrailingSorted ( xmlNodeSetPtr nodes1 , xmlNodeSetPtr nodes2 ) {
if ( xmlXPathNodeSetIsEmpty ( nodes2 ) )
return ( nodes1 ) ;
return ( xmlXPathNodeTrailingSorted ( nodes1 ,
xmlXPathNodeSetItem ( nodes2 , 0 ) ) ) ;
}
/**
* xmlXPathTrailing :
* @ nodes1 : a node - set
* @ nodes2 : a node - set
*
* Implements the EXSLT - Sets trailing ( ) function :
* node - set set : trailing ( node - set , node - set )
* @ nodes1 and @ nodes2 are sorted by document order , then
* # xmlXPathTrailingSorted is called .
*
* Returns the nodes in @ nodes1 that follow the first node in @ nodes2
* in document order , @ nodes1 if @ nodes2 is NULL or empty or
* an empty node - set if @ nodes1 doesn ' t contain @ nodes2
*/
xmlNodeSetPtr
xmlXPathTrailing ( xmlNodeSetPtr nodes1 , xmlNodeSetPtr nodes2 ) {
if ( xmlXPathNodeSetIsEmpty ( nodes2 ) )
return ( nodes1 ) ;
if ( xmlXPathNodeSetIsEmpty ( nodes1 ) )
return ( xmlXPathNodeSetCreate ( NULL ) ) ;
xmlXPathNodeSetSort ( nodes1 ) ;
xmlXPathNodeSetSort ( nodes2 ) ;
return ( xmlXPathNodeTrailingSorted ( nodes1 ,
xmlXPathNodeSetItem ( nodes2 , 0 ) ) ) ;
}
2001-02-23 17:55:21 +00:00
/************************************************************************
* *
* Routines to handle extra functions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* 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 ) {
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 )
return ( - 1 ) ;
if ( name = = NULL )
return ( - 1 ) ;
if ( ctxt - > funcHash = = NULL )
ctxt - > funcHash = xmlHashCreate ( 0 ) ;
if ( ctxt - > funcHash = = NULL )
return ( - 1 ) ;
2003-10-29 17:07:51 +00:00
if ( f = = NULL )
return ( xmlHashRemoveEntry2 ( ctxt - > funcHash , name , ns_uri , NULL ) ) ;
2001-02-23 17:55:21 +00:00
return ( xmlHashAddEntry2 ( ctxt - > funcHash , name , ns_uri , ( void * ) f ) ) ;
}
2001-07-26 16:55:21 +00:00
/**
* xmlXPathRegisterFuncLookup :
* @ ctxt : the XPath context
* @ f : the lookup function
2001-12-31 16:16:02 +00:00
* @ funcCtxt : the lookup data
2001-07-26 16:55:21 +00:00
*
2001-12-31 16:16:02 +00:00
* Registers an external mechanism to do function lookup .
2001-07-26 16:55:21 +00:00
*/
void
xmlXPathRegisterFuncLookup ( xmlXPathContextPtr ctxt ,
xmlXPathFuncLookupFunc f ,
void * funcCtxt ) {
if ( ctxt = = NULL )
return ;
ctxt - > funcLookupFunc = ( void * ) f ;
ctxt - > funcLookupData = funcCtxt ;
}
2001-02-23 17:55:21 +00:00
/**
* 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 ) {
2001-07-26 16:55:21 +00:00
if ( ctxt = = NULL )
return ( NULL ) ;
if ( ctxt - > funcLookupFunc ! = NULL ) {
xmlXPathFunction ret ;
2002-01-21 08:56:29 +00:00
xmlXPathFuncLookupFunc f ;
2001-07-26 16:55:21 +00:00
2002-01-21 08:56:29 +00:00
f = ( xmlXPathFuncLookupFunc ) ctxt - > funcLookupFunc ;
2002-01-20 22:08:18 +00:00
ret = f ( ctxt - > funcLookupData , name , NULL ) ;
2001-07-26 16:55:21 +00:00
if ( ret ! = NULL )
return ( ret ) ;
}
2001-02-23 17:55:21 +00:00
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 )
return ( NULL ) ;
if ( name = = NULL )
return ( NULL ) ;
2001-07-26 16:55:21 +00:00
if ( ctxt - > funcLookupFunc ! = NULL ) {
xmlXPathFunction ret ;
2002-01-21 08:56:29 +00:00
xmlXPathFuncLookupFunc f ;
2001-07-26 16:55:21 +00:00
2002-01-21 08:56:29 +00:00
f = ( xmlXPathFuncLookupFunc ) ctxt - > funcLookupFunc ;
2002-01-20 22:08:18 +00:00
ret = f ( ctxt - > funcLookupData , name , ns_uri ) ;
2001-07-26 16:55:21 +00:00
if ( ret ! = NULL )
return ( ret ) ;
}
if ( ctxt - > funcHash = = NULL )
return ( NULL ) ;
2001-02-23 17:55:21 +00:00
return ( ( xmlXPathFunction ) xmlHashLookup2 ( ctxt - > funcHash , name , ns_uri ) ) ;
}
/**
* xmlXPathRegisteredFuncsCleanup :
* @ ctxt : the XPath context
*
* Cleanup the XPath context data associated to registered functions
*/
void
xmlXPathRegisteredFuncsCleanup ( xmlXPathContextPtr ctxt ) {
if ( ctxt = = NULL )
return ;
xmlHashFree ( ctxt - > funcHash , NULL ) ;
ctxt - > funcHash = 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 ) {
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 )
return ( - 1 ) ;
if ( name = = NULL )
return ( - 1 ) ;
if ( ctxt - > varHash = = NULL )
ctxt - > varHash = xmlHashCreate ( 0 ) ;
if ( ctxt - > varHash = = NULL )
return ( - 1 ) ;
2003-10-29 17:07:51 +00:00
if ( value = = NULL )
return ( xmlHashRemoveEntry2 ( ctxt - > varHash , name , ns_uri ,
( xmlHashDeallocator ) xmlXPathFreeObject ) ) ;
2001-02-23 17:55:21 +00:00
return ( xmlHashUpdateEntry2 ( ctxt - > varHash , name , ns_uri ,
( void * ) value ,
( xmlHashDeallocator ) xmlXPathFreeObject ) ) ;
}
/**
* xmlXPathRegisterVariableLookup :
* @ ctxt : the XPath context
* @ f : the lookup function
* @ data : the lookup data
*
* register an external mechanism to do variable lookup
*/
void
xmlXPathRegisterVariableLookup ( xmlXPathContextPtr ctxt ,
xmlXPathVariableLookupFunc f , void * data ) {
if ( ctxt = = NULL )
return ;
ctxt - > varLookupFunc = ( void * ) f ;
ctxt - > varLookupData = data ;
}
/**
* xmlXPathVariableLookup :
* @ ctxt : the XPath context
* @ name : the variable name
*
* Search in the Variable array of the context for the given
* variable value .
*
2001-07-05 20:02:54 +00:00
* Returns a copy of the value or NULL if not found
2001-02-23 17:55:21 +00:00
*/
xmlXPathObjectPtr
xmlXPathVariableLookup ( xmlXPathContextPtr ctxt , const xmlChar * name ) {
if ( ctxt = = NULL )
return ( NULL ) ;
if ( ctxt - > varLookupFunc ! = NULL ) {
xmlXPathObjectPtr ret ;
ret = ( ( xmlXPathVariableLookupFunc ) ctxt - > varLookupFunc )
( ctxt - > varLookupData , name , NULL ) ;
2001-10-06 09:59:51 +00:00
return ( ret ) ;
2001-02-23 17:55:21 +00:00
}
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
2001-07-05 20:02:54 +00:00
* variable value .
2001-02-23 17:55:21 +00:00
*
2001-07-05 20:02:54 +00:00
* Returns the a copy of the value or NULL if not found
2001-02-23 17:55:21 +00:00
*/
xmlXPathObjectPtr
xmlXPathVariableLookupNS ( xmlXPathContextPtr ctxt , const xmlChar * name ,
const xmlChar * ns_uri ) {
if ( ctxt = = NULL )
return ( NULL ) ;
if ( ctxt - > varLookupFunc ! = NULL ) {
xmlXPathObjectPtr ret ;
ret = ( ( xmlXPathVariableLookupFunc ) ctxt - > varLookupFunc )
( ctxt - > varLookupData , name , ns_uri ) ;
if ( ret ! = NULL ) return ( ret ) ;
}
if ( ctxt - > varHash = = NULL )
return ( NULL ) ;
if ( name = = NULL )
return ( NULL ) ;
2001-07-03 23:43:33 +00:00
return ( xmlXPathObjectCopy ( ( xmlXPathObjectPtr )
xmlHashLookup2 ( ctxt - > varHash , name , ns_uri ) ) ) ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathRegisteredVariablesCleanup :
* @ ctxt : the XPath context
*
* Cleanup the XPath context data associated to registered variables
*/
void
xmlXPathRegisteredVariablesCleanup ( xmlXPathContextPtr ctxt ) {
if ( ctxt = = NULL )
return ;
2001-05-16 21:05:17 +00:00
xmlHashFree ( ctxt - > varHash , ( xmlHashDeallocator ) xmlXPathFreeObject ) ;
2001-02-23 17:55:21 +00:00
ctxt - > varHash = NULL ;
}
/**
* xmlXPathRegisterNs :
* @ ctxt : the XPath context
* @ prefix : the namespace prefix
* @ ns_uri : the namespace name
*
* Register a new namespace . If @ ns_uri is NULL it unregisters
* the namespace
*
* Returns 0 in case of success , - 1 in case of error
*/
int
xmlXPathRegisterNs ( xmlXPathContextPtr ctxt , const xmlChar * prefix ,
const xmlChar * ns_uri ) {
if ( ctxt = = NULL )
return ( - 1 ) ;
if ( prefix = = NULL )
return ( - 1 ) ;
if ( ctxt - > nsHash = = NULL )
ctxt - > nsHash = xmlHashCreate ( 10 ) ;
if ( ctxt - > nsHash = = NULL )
return ( - 1 ) ;
2003-10-29 11:18:37 +00:00
if ( ns_uri = = NULL )
2003-10-29 17:07:51 +00:00
return ( xmlHashRemoveEntry ( ctxt - > nsHash , prefix ,
2003-10-29 11:18:37 +00:00
( xmlHashDeallocator ) xmlFree ) ) ;
2002-08-22 20:52:17 +00:00
return ( xmlHashUpdateEntry ( ctxt - > nsHash , prefix , ( void * ) xmlStrdup ( ns_uri ) ,
2001-02-23 17:55:21 +00:00
( xmlHashDeallocator ) xmlFree ) ) ;
}
/**
* xmlXPathNsLookup :
* @ ctxt : the XPath context
* @ prefix : the namespace prefix value
*
* Search in the namespace declaration array of the context for the given
* namespace name associated to the given prefix
*
* Returns the value or NULL if not found
*/
const xmlChar *
xmlXPathNsLookup ( xmlXPathContextPtr ctxt , const xmlChar * prefix ) {
if ( ctxt = = NULL )
return ( NULL ) ;
if ( prefix = = NULL )
return ( NULL ) ;
# ifdef XML_XML_NAMESPACE
if ( xmlStrEqual ( prefix , ( const xmlChar * ) " xml " ) )
return ( XML_XML_NAMESPACE ) ;
# endif
2001-04-30 20:31:33 +00:00
if ( ctxt - > namespaces ! = NULL ) {
int i ;
for ( i = 0 ; i < ctxt - > nsNr ; i + + ) {
if ( ( ctxt - > namespaces [ i ] ! = NULL ) & &
( xmlStrEqual ( ctxt - > namespaces [ i ] - > prefix , prefix ) ) )
return ( ctxt - > namespaces [ i ] - > href ) ;
}
}
2001-02-23 17:55:21 +00:00
return ( ( const xmlChar * ) xmlHashLookup ( ctxt - > nsHash , prefix ) ) ;
}
/**
2001-07-18 19:30:27 +00:00
* xmlXPathRegisteredNsCleanup :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath context
*
* Cleanup the XPath context data associated to registered variables
*/
void
xmlXPathRegisteredNsCleanup ( xmlXPathContextPtr ctxt ) {
if ( ctxt = = NULL )
return ;
2002-08-22 20:52:17 +00:00
xmlHashFree ( ctxt - > nsHash , ( xmlHashDeallocator ) xmlFree ) ;
2001-02-23 17:55:21 +00:00
ctxt - > nsHash = NULL ;
}
/************************************************************************
* *
* Routines to handle Values *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Allocations are terrible, one need to optimize all this !!! */
/**
* xmlXPathNewFloat :
* @ val : the double value
*
* Create a new xmlXPathObjectPtr of type double and of value @ val
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathNewFloat ( double val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating float object \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_NUMBER ;
ret - > floatval = val ;
return ( ret ) ;
}
/**
* xmlXPathNewBoolean :
* @ val : the boolean value
*
* Create a new xmlXPathObjectPtr of type boolean and of value @ val
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathNewBoolean ( int val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating boolean object \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_BOOLEAN ;
ret - > boolval = ( val ! = 0 ) ;
return ( ret ) ;
}
/**
* xmlXPathNewString :
* @ val : the xmlChar * value
*
* Create a new xmlXPathObjectPtr of type string and of value @ val
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathNewString ( const xmlChar * val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating string object \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_STRING ;
if ( val ! = NULL )
ret - > stringval = xmlStrdup ( val ) ;
else
ret - > stringval = xmlStrdup ( ( const xmlChar * ) " " ) ;
return ( ret ) ;
}
2001-05-15 09:43:47 +00:00
/**
* xmlXPathWrapString :
* @ val : the xmlChar * value
*
* Wraps the @ val string into an XPath object .
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathWrapString ( xmlChar * val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating string object \n " ) ;
2001-05-15 09:43:47 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_STRING ;
ret - > stringval = val ;
return ( ret ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathNewCString :
* @ val : the char * value
*
* Create a new xmlXPathObjectPtr of type string and of value @ val
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathNewCString ( const char * val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating string object \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_STRING ;
ret - > stringval = xmlStrdup ( BAD_CAST val ) ;
return ( ret ) ;
}
2001-05-15 09:43:47 +00:00
/**
* xmlXPathWrapCString :
* @ val : the char * value
*
* Wraps a string into an XPath object .
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathWrapCString ( char * val ) {
return ( xmlXPathWrapString ( ( xmlChar * ) ( val ) ) ) ;
}
2001-07-16 04:52:57 +00:00
/**
* xmlXPathWrapExternal :
* @ val : the user data
*
* Wraps the @ val data into an XPath object .
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPathWrapExternal ( void * val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating user object \n " ) ;
2001-07-16 04:52:57 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_USERS ;
ret - > user = val ;
return ( ret ) ;
}
2001-02-23 17:55:21 +00:00
/**
* 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 ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " copying object \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memcpy ( ret , val , ( size_t ) sizeof ( xmlXPathObject ) ) ;
switch ( val - > type ) {
case XPATH_BOOLEAN :
case XPATH_NUMBER :
case XPATH_POINT :
case XPATH_RANGE :
break ;
case XPATH_STRING :
ret - > stringval = xmlStrdup ( val - > stringval ) ;
break ;
case XPATH_XSLT_TREE :
if ( ( val - > nodesetval ! = NULL ) & &
2001-08-14 16:43:10 +00:00
( val - > nodesetval - > nodeTab ! = NULL ) ) {
2003-03-24 18:39:54 +00:00
xmlNodePtr cur , tmp ;
xmlDocPtr top ;
2003-03-24 13:57:34 +00:00
2001-08-14 16:43:10 +00:00
ret - > boolval = 1 ;
2003-03-24 18:39:54 +00:00
top = xmlNewDoc ( NULL ) ;
top - > name = ( char * )
xmlStrdup ( val - > nodesetval - > nodeTab [ 0 ] - > name ) ;
2003-03-24 13:57:34 +00:00
ret - > user = top ;
if ( top ! = NULL ) {
2003-03-24 18:39:54 +00:00
top - > doc = top ;
2003-03-24 13:57:34 +00:00
cur = val - > nodesetval - > nodeTab [ 0 ] - > children ;
while ( cur ! = NULL ) {
2003-03-24 18:39:54 +00:00
tmp = xmlDocCopyNode ( cur , top , 1 ) ;
xmlAddChild ( ( xmlNodePtr ) top , tmp ) ;
2003-03-24 13:57:34 +00:00
cur = cur - > next ;
}
}
2003-03-24 18:39:54 +00:00
ret - > nodesetval = xmlXPathNodeSetCreate ( ( xmlNodePtr ) top ) ;
2001-08-14 16:43:10 +00:00
} else
2001-02-23 17:55:21 +00:00
ret - > nodesetval = xmlXPathNodeSetCreate ( NULL ) ;
2001-08-14 16:43:10 +00:00
/* Deallocate the copied tree value */
2001-02-23 17:55:21 +00:00
break ;
case XPATH_NODESET :
ret - > nodesetval = xmlXPathNodeSetMerge ( NULL , val - > nodesetval ) ;
2001-08-14 16:43:10 +00:00
/* Do not deallocate the copied tree value */
ret - > boolval = 0 ;
2001-02-23 17:55:21 +00:00
break ;
case XPATH_LOCATIONSET :
# ifdef LIBXML_XPTR_ENABLED
{
xmlLocationSetPtr loc = val - > user ;
ret - > user = ( void * ) xmlXPtrLocationSetMerge ( NULL , loc ) ;
break ;
}
# endif
2001-10-07 16:41:52 +00:00
case XPATH_USERS :
ret - > user = val - > user ;
break ;
case XPATH_UNDEFINED :
2001-02-23 17:55:21 +00:00
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathObjectCopy: unsupported type %d \n " ,
val - > type ) ;
break ;
}
return ( ret ) ;
}
/**
* xmlXPathFreeObject :
* @ obj : the object to free
*
* Free up an xmlXPathObjectPtr object .
*/
void
xmlXPathFreeObject ( xmlXPathObjectPtr obj ) {
if ( obj = = NULL ) return ;
2001-08-14 16:43:10 +00:00
if ( ( obj - > type = = XPATH_NODESET ) | | ( obj - > type = = XPATH_XSLT_TREE ) ) {
2001-02-27 21:54:07 +00:00
if ( obj - > boolval ) {
2001-08-14 16:43:10 +00:00
if ( obj - > user ! = NULL ) {
xmlXPathFreeNodeSet ( obj - > nodesetval ) ;
2002-03-16 22:03:31 +00:00
xmlFreeNodeList ( ( xmlNodePtr ) obj - > user ) ;
2001-08-14 16:43:10 +00:00
} else if ( obj - > nodesetval ! = NULL )
2001-02-27 21:54:07 +00:00
xmlXPathFreeValueTree ( obj - > nodesetval ) ;
} else {
if ( obj - > nodesetval ! = NULL )
xmlXPathFreeNodeSet ( obj - > nodesetval ) ;
}
2001-02-23 17:55:21 +00:00
# ifdef LIBXML_XPTR_ENABLED
} else if ( obj - > type = = XPATH_LOCATIONSET ) {
if ( obj - > user ! = NULL )
xmlXPtrFreeLocationSet ( obj - > user ) ;
# endif
} else if ( obj - > type = = XPATH_STRING ) {
if ( obj - > stringval ! = NULL )
xmlFree ( obj - > stringval ) ;
}
xmlFree ( obj ) ;
}
2001-05-15 09:43:47 +00:00
/************************************************************************
* *
* Type Casting Routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPathCastBooleanToString :
* @ val : a boolean
*
* Converts a boolean to its string value .
*
* Returns a newly allocated string .
*/
xmlChar *
xmlXPathCastBooleanToString ( int val ) {
xmlChar * ret ;
if ( val )
ret = xmlStrdup ( ( const xmlChar * ) " true " ) ;
else
ret = xmlStrdup ( ( const xmlChar * ) " false " ) ;
return ( ret ) ;
}
/**
* xmlXPathCastNumberToString :
* @ val : a number
*
* Converts a number to its string value .
*
* Returns a newly allocated string .
*/
xmlChar *
xmlXPathCastNumberToString ( double val ) {
xmlChar * ret ;
2001-08-21 10:56:31 +00:00
switch ( xmlXPathIsInf ( val ) ) {
2001-05-15 09:43:47 +00:00
case 1 :
2002-03-27 09:05:40 +00:00
ret = xmlStrdup ( ( const xmlChar * ) " Infinity " ) ;
2001-05-15 09:43:47 +00:00
break ;
case - 1 :
ret = xmlStrdup ( ( const xmlChar * ) " -Infinity " ) ;
break ;
default :
2001-08-21 10:56:31 +00:00
if ( xmlXPathIsNaN ( val ) ) {
2001-05-15 09:43:47 +00:00
ret = xmlStrdup ( ( const xmlChar * ) " NaN " ) ;
2002-03-28 18:25:31 +00:00
} else if ( val = = 0 & & xmlXPathGetSign ( val ) ! = 0 ) {
ret = xmlStrdup ( ( const xmlChar * ) " 0 " ) ;
2001-05-15 09:43:47 +00:00
} else {
/* could be improved */
char buf [ 100 ] ;
xmlXPathFormatNumber ( val , buf , 100 ) ;
ret = xmlStrdup ( ( const xmlChar * ) buf ) ;
}
}
return ( ret ) ;
}
/**
* xmlXPathCastNodeToString :
* @ node : a node
*
* Converts a node to its string value .
*
* Returns a newly allocated string .
*/
xmlChar *
xmlXPathCastNodeToString ( xmlNodePtr node ) {
return ( xmlNodeGetContent ( node ) ) ;
}
/**
* xmlXPathCastNodeSetToString :
* @ ns : a node - set
*
* Converts a node - set to its string value .
*
* Returns a newly allocated string .
*/
xmlChar *
xmlXPathCastNodeSetToString ( xmlNodeSetPtr ns ) {
if ( ( ns = = NULL ) | | ( ns - > nodeNr = = 0 ) | | ( ns - > nodeTab = = NULL ) )
return ( xmlStrdup ( ( const xmlChar * ) " " ) ) ;
xmlXPathNodeSetSort ( ns ) ;
return ( xmlXPathCastNodeToString ( ns - > nodeTab [ 0 ] ) ) ;
}
/**
* xmlXPathCastToString :
* @ val : an XPath object
*
* Converts an existing object to its string ( ) equivalent
*
* Returns the string value of the object , NULL in case of error .
2001-12-31 16:16:02 +00:00
* A new string is allocated only if needed ( @ val isn ' t a
2001-05-15 09:43:47 +00:00
* string object ) .
*/
xmlChar *
xmlXPathCastToString ( xmlXPathObjectPtr val ) {
xmlChar * ret = NULL ;
if ( val = = NULL )
return ( xmlStrdup ( ( const xmlChar * ) " " ) ) ;
switch ( val - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext , " String: undefined \n " ) ;
# endif
ret = xmlStrdup ( ( const xmlChar * ) " " ) ;
break ;
case XPATH_NODESET :
2002-07-12 00:56:01 +00:00
case XPATH_XSLT_TREE :
2001-05-15 09:43:47 +00:00
ret = xmlXPathCastNodeSetToString ( val - > nodesetval ) ;
break ;
case XPATH_STRING :
2002-03-22 12:23:14 +00:00
return ( xmlStrdup ( val - > stringval ) ) ;
2001-05-15 09:43:47 +00:00
case XPATH_BOOLEAN :
ret = xmlXPathCastBooleanToString ( val - > boolval ) ;
break ;
case XPATH_NUMBER : {
ret = xmlXPathCastNumberToString ( val - > floatval ) ;
break ;
}
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO
ret = xmlStrdup ( ( const xmlChar * ) " " ) ;
break ;
}
return ( ret ) ;
}
/**
* xmlXPathConvertString :
* @ val : an XPath object
*
* Converts an existing object to its string ( ) equivalent
*
* Returns the new object , the old one is freed ( or the operation
* is done directly on @ val )
*/
xmlXPathObjectPtr
xmlXPathConvertString ( xmlXPathObjectPtr val ) {
xmlChar * res = NULL ;
if ( val = = NULL )
return ( xmlXPathNewCString ( " " ) ) ;
switch ( val - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext , " STRING: undefined \n " ) ;
# endif
break ;
case XPATH_NODESET :
2002-07-12 00:56:01 +00:00
case XPATH_XSLT_TREE :
2001-05-15 09:43:47 +00:00
res = xmlXPathCastNodeSetToString ( val - > nodesetval ) ;
break ;
case XPATH_STRING :
return ( val ) ;
case XPATH_BOOLEAN :
res = xmlXPathCastBooleanToString ( val - > boolval ) ;
break ;
case XPATH_NUMBER :
res = xmlXPathCastNumberToString ( val - > floatval ) ;
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO ;
break ;
}
xmlXPathFreeObject ( val ) ;
if ( res = = NULL )
return ( xmlXPathNewCString ( " " ) ) ;
return ( xmlXPathWrapString ( res ) ) ;
}
/**
* xmlXPathCastBooleanToNumber :
* @ val : a boolean
*
* Converts a boolean to its number value
*
* Returns the number value
*/
double
xmlXPathCastBooleanToNumber ( int val ) {
if ( val )
return ( 1.0 ) ;
return ( 0.0 ) ;
}
/**
* xmlXPathCastStringToNumber :
* @ val : a string
*
* Converts a string to its number value
*
* Returns the number value
*/
double
xmlXPathCastStringToNumber ( const xmlChar * val ) {
return ( xmlXPathStringEvalNumber ( val ) ) ;
}
/**
* xmlXPathCastNodeToNumber :
* @ node : a node
*
* Converts a node to its number value
*
* Returns the number value
*/
double
xmlXPathCastNodeToNumber ( xmlNodePtr node ) {
xmlChar * strval ;
double ret ;
if ( node = = NULL )
return ( xmlXPathNAN ) ;
strval = xmlXPathCastNodeToString ( node ) ;
if ( strval = = NULL )
return ( xmlXPathNAN ) ;
ret = xmlXPathCastStringToNumber ( strval ) ;
xmlFree ( strval ) ;
return ( ret ) ;
}
/**
* xmlXPathCastNodeSetToNumber :
* @ ns : a node - set
*
* Converts a node - set to its number value
*
* Returns the number value
*/
double
xmlXPathCastNodeSetToNumber ( xmlNodeSetPtr ns ) {
xmlChar * str ;
double ret ;
if ( ns = = NULL )
return ( xmlXPathNAN ) ;
str = xmlXPathCastNodeSetToString ( ns ) ;
ret = xmlXPathCastStringToNumber ( str ) ;
xmlFree ( str ) ;
return ( ret ) ;
}
/**
* xmlXPathCastToNumber :
* @ val : an XPath object
*
* Converts an XPath object to its number value
*
* Returns the number value
*/
double
xmlXPathCastToNumber ( xmlXPathObjectPtr val ) {
double ret = 0.0 ;
if ( val = = NULL )
return ( xmlXPathNAN ) ;
switch ( val - > type ) {
case XPATH_UNDEFINED :
# ifdef DEGUB_EXPR
xmlGenericError ( xmlGenericErrorContext , " NUMBER: undefined \n " ) ;
# endif
ret = xmlXPathNAN ;
break ;
case XPATH_NODESET :
2002-07-12 00:56:01 +00:00
case XPATH_XSLT_TREE :
2001-05-15 09:43:47 +00:00
ret = xmlXPathCastNodeSetToNumber ( val - > nodesetval ) ;
break ;
case XPATH_STRING :
ret = xmlXPathCastStringToNumber ( val - > stringval ) ;
break ;
case XPATH_NUMBER :
ret = val - > floatval ;
break ;
case XPATH_BOOLEAN :
ret = xmlXPathCastBooleanToNumber ( val - > boolval ) ;
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO ;
ret = xmlXPathNAN ;
break ;
}
return ( ret ) ;
}
/**
* xmlXPathConvertNumber :
* @ val : an XPath object
*
* Converts an existing object to its number ( ) equivalent
*
* Returns the new object , the old one is freed ( or the operation
* is done directly on @ val )
*/
xmlXPathObjectPtr
xmlXPathConvertNumber ( xmlXPathObjectPtr val ) {
xmlXPathObjectPtr ret ;
if ( val = = NULL )
return ( xmlXPathNewFloat ( 0.0 ) ) ;
if ( val - > type = = XPATH_NUMBER )
return ( val ) ;
ret = xmlXPathNewFloat ( xmlXPathCastToNumber ( val ) ) ;
xmlXPathFreeObject ( val ) ;
return ( ret ) ;
}
/**
* xmlXPathCastNumberToBoolean :
* @ val : a number
*
* Converts a number to its boolean value
*
* Returns the boolean value
*/
int
xmlXPathCastNumberToBoolean ( double val ) {
2001-08-21 10:56:31 +00:00
if ( xmlXPathIsNaN ( val ) | | ( val = = 0.0 ) )
2001-05-15 09:43:47 +00:00
return ( 0 ) ;
return ( 1 ) ;
}
/**
* xmlXPathCastStringToBoolean :
* @ val : a string
*
* Converts a string to its boolean value
*
* Returns the boolean value
*/
int
xmlXPathCastStringToBoolean ( const xmlChar * val ) {
if ( ( val = = NULL ) | | ( xmlStrlen ( val ) = = 0 ) )
return ( 0 ) ;
return ( 1 ) ;
}
/**
* xmlXPathCastNodeSetToBoolean :
* @ ns : a node - set
*
* Converts a node - set to its boolean value
*
* Returns the boolean value
*/
int
xmlXPathCastNodeSetToBoolean ( xmlNodeSetPtr ns ) {
if ( ( ns = = NULL ) | | ( ns - > nodeNr = = 0 ) )
return ( 0 ) ;
return ( 1 ) ;
}
/**
2001-07-18 19:30:27 +00:00
* xmlXPathCastToBoolean :
2001-05-15 09:43:47 +00:00
* @ val : an XPath object
*
* Converts an XPath object to its boolean value
*
* Returns the boolean value
*/
int
xmlXPathCastToBoolean ( xmlXPathObjectPtr val ) {
int ret = 0 ;
if ( val = = NULL )
return ( 0 ) ;
switch ( val - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext , " BOOLEAN: undefined \n " ) ;
# endif
ret = 0 ;
break ;
case XPATH_NODESET :
2002-07-12 00:56:01 +00:00
case XPATH_XSLT_TREE :
2001-05-15 09:43:47 +00:00
ret = xmlXPathCastNodeSetToBoolean ( val - > nodesetval ) ;
break ;
case XPATH_STRING :
ret = xmlXPathCastStringToBoolean ( val - > stringval ) ;
break ;
case XPATH_NUMBER :
ret = xmlXPathCastNumberToBoolean ( val - > floatval ) ;
break ;
case XPATH_BOOLEAN :
ret = val - > boolval ;
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO ;
ret = 0 ;
break ;
}
return ( ret ) ;
}
/**
* xmlXPathConvertBoolean :
* @ val : an XPath object
*
* Converts an existing object to its boolean ( ) equivalent
*
* Returns the new object , the old one is freed ( or the operation
* is done directly on @ val )
*/
xmlXPathObjectPtr
xmlXPathConvertBoolean ( xmlXPathObjectPtr val ) {
xmlXPathObjectPtr ret ;
if ( val = = NULL )
return ( xmlXPathNewBoolean ( 0 ) ) ;
if ( val - > type = = XPATH_BOOLEAN )
return ( val ) ;
ret = xmlXPathNewBoolean ( xmlXPathCastToBoolean ( val ) ) ;
xmlXPathFreeObject ( val ) ;
return ( ret ) ;
}
2001-02-23 17:55:21 +00:00
/************************************************************************
* *
* Routines to handle XPath contexts *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPathNewContext :
* @ doc : the XML document
*
* Create a new xmlXPathContext
*
2002-03-08 15:05:20 +00:00
* Returns the xmlXPathContext just allocated . The caller will need to free it .
2001-02-23 17:55:21 +00:00
*/
xmlXPathContextPtr
xmlXPathNewContext ( xmlDocPtr doc ) {
xmlXPathContextPtr ret ;
ret = ( xmlXPathContextPtr ) xmlMalloc ( sizeof ( xmlXPathContext ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " creating context \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathContext ) ) ;
ret - > doc = doc ;
ret - > node = NULL ;
ret - > varHash = NULL ;
ret - > nb_types = 0 ;
ret - > max_types = 0 ;
ret - > types = NULL ;
ret - > funcHash = xmlHashCreate ( 0 ) ;
ret - > nb_axis = 0 ;
ret - > max_axis = 0 ;
ret - > axis = NULL ;
ret - > nsHash = NULL ;
ret - > user = NULL ;
ret - > contextSize = - 1 ;
ret - > proximityPosition = - 1 ;
xmlXPathRegisterAllFunctions ( ret ) ;
return ( ret ) ;
}
/**
* xmlXPathFreeContext :
* @ ctxt : the context to free
*
* Free up an xmlXPathContext
*/
void
xmlXPathFreeContext ( xmlXPathContextPtr ctxt ) {
xmlXPathRegisteredNsCleanup ( ctxt ) ;
xmlXPathRegisteredFuncsCleanup ( ctxt ) ;
xmlXPathRegisteredVariablesCleanup ( ctxt ) ;
xmlFree ( ctxt ) ;
}
/************************************************************************
* *
* Routines to handle XPath parser contexts *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define CHECK_CTXT(ctxt) \
if ( ctxt = = NULL ) { \
xmlGenericError ( xmlGenericErrorContext , \
" %s:%d Internal error: ctxt == NULL \n " , \
__FILE__ , __LINE__ ) ; \
} \
# define CHECK_CONTEXT(ctxt) \
if ( ctxt = = NULL ) { \
xmlGenericError ( xmlGenericErrorContext , \
" %s:%d Internal error: no context \n " , \
__FILE__ , __LINE__ ) ; \
} \
else if ( ctxt - > doc = = NULL ) { \
xmlGenericError ( xmlGenericErrorContext , \
" %s:%d Internal error: no document \n " , \
__FILE__ , __LINE__ ) ; \
} \
else if ( ctxt - > doc - > children = = NULL ) { \
xmlGenericError ( xmlGenericErrorContext , \
" %s:%d Internal error: document without root \n " , \
__FILE__ , __LINE__ ) ; \
} \
/**
* xmlXPathNewParserContext :
* @ str : the XPath expression
* @ ctxt : the XPath context
*
* Create a new xmlXPathParserContext
*
* Returns the xmlXPathParserContext just allocated .
*/
xmlXPathParserContextPtr
xmlXPathNewParserContext ( const xmlChar * str , xmlXPathContextPtr ctxt ) {
xmlXPathParserContextPtr ret ;
ret = ( xmlXPathParserContextPtr ) xmlMalloc ( sizeof ( xmlXPathParserContext ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( ctxt , " creating parser context \n " ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathParserContext ) ) ;
ret - > cur = ret - > base = str ;
ret - > context = ctxt ;
2001-03-18 23:17:47 +00:00
ret - > comp = xmlXPathNewCompExpr ( ) ;
if ( ret - > comp = = NULL ) {
xmlFree ( ret - > valueTab ) ;
xmlFree ( ret ) ;
return ( NULL ) ;
}
return ( ret ) ;
}
/**
* xmlXPathCompParserContext :
* @ comp : the XPath compiled expression
* @ ctxt : the XPath context
*
* Create a new xmlXPathParserContext when processing a compiled expression
*
* Returns the xmlXPathParserContext just allocated .
*/
2001-03-24 17:00:36 +00:00
static xmlXPathParserContextPtr
2001-03-18 23:17:47 +00:00
xmlXPathCompParserContext ( xmlXPathCompExprPtr comp , xmlXPathContextPtr ctxt ) {
xmlXPathParserContextPtr ret ;
ret = ( xmlXPathParserContextPtr ) xmlMalloc ( sizeof ( xmlXPathParserContext ) ) ;
if ( ret = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( ctxt , " creating evaluation context \n " ) ;
2001-03-18 23:17:47 +00:00
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathParserContext ) ) ;
2001-02-23 17:55:21 +00:00
/* Allocate the value stack */
ret - > valueTab = ( xmlXPathObjectPtr * )
xmlMalloc ( 10 * sizeof ( xmlXPathObjectPtr ) ) ;
2001-03-18 23:17:47 +00:00
if ( ret - > valueTab = = NULL ) {
xmlFree ( ret ) ;
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( ctxt , " creating evaluation context \n " ) ;
2001-03-18 23:17:47 +00:00
return ( NULL ) ;
}
2001-02-23 17:55:21 +00:00
ret - > valueNr = 0 ;
ret - > valueMax = 10 ;
ret - > value = NULL ;
2001-03-18 23:17:47 +00:00
2001-03-19 15:58:54 +00:00
ret - > context = ctxt ;
2001-03-18 23:17:47 +00:00
ret - > comp = comp ;
2001-02-23 17:55:21 +00:00
return ( ret ) ;
}
/**
* xmlXPathFreeParserContext :
* @ ctxt : the context to free
*
* Free up an xmlXPathParserContext
*/
void
xmlXPathFreeParserContext ( xmlXPathParserContextPtr ctxt ) {
if ( ctxt - > valueTab ! = NULL ) {
xmlFree ( ctxt - > valueTab ) ;
}
2001-03-18 23:17:47 +00:00
if ( ctxt - > comp )
xmlXPathFreeCompExpr ( ctxt - > comp ) ;
2001-02-23 17:55:21 +00:00
xmlFree ( ctxt ) ;
}
/************************************************************************
* *
* The implicit core function library *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-07-03 10:35:50 +00:00
/**
2002-12-10 15:19:08 +00:00
* xmlXPathNodeValHash :
2001-07-03 10:35:50 +00:00
* @ node : a node pointer
*
* Function computing the beginning of the string value of the node ,
* used to speed up comparisons
*
* Returns an int usable as a hash
*/
static unsigned int
xmlXPathNodeValHash ( xmlNodePtr node ) {
int len = 2 ;
const xmlChar * string = NULL ;
xmlNodePtr tmp = NULL ;
unsigned int ret = 0 ;
if ( node = = NULL )
return ( 0 ) ;
2003-03-24 18:39:54 +00:00
if ( node - > type = = XML_DOCUMENT_NODE ) {
tmp = xmlDocGetRootElement ( ( xmlDocPtr ) node ) ;
if ( tmp = = NULL )
node = node - > children ;
else
node = tmp ;
if ( node = = NULL )
return ( 0 ) ;
}
2001-07-03 10:35:50 +00:00
switch ( node - > type ) {
case XML_COMMENT_NODE :
case XML_PI_NODE :
case XML_CDATA_SECTION_NODE :
case XML_TEXT_NODE :
string = node - > content ;
if ( string = = NULL )
return ( 0 ) ;
if ( string [ 0 ] = = 0 )
return ( 0 ) ;
return ( ( ( unsigned int ) string [ 0 ] ) +
( ( ( unsigned int ) string [ 1 ] ) < < 8 ) ) ;
case XML_NAMESPACE_DECL :
string = ( ( xmlNsPtr ) node ) - > href ;
if ( string = = NULL )
return ( 0 ) ;
if ( string [ 0 ] = = 0 )
return ( 0 ) ;
return ( ( ( unsigned int ) string [ 0 ] ) +
( ( ( unsigned int ) string [ 1 ] ) < < 8 ) ) ;
case XML_ATTRIBUTE_NODE :
tmp = ( ( xmlAttrPtr ) node ) - > children ;
break ;
case XML_ELEMENT_NODE :
tmp = node - > children ;
break ;
default :
return ( 0 ) ;
}
while ( tmp ! = NULL ) {
switch ( tmp - > type ) {
case XML_COMMENT_NODE :
case XML_PI_NODE :
case XML_CDATA_SECTION_NODE :
case XML_TEXT_NODE :
string = tmp - > content ;
break ;
case XML_NAMESPACE_DECL :
string = ( ( xmlNsPtr ) tmp ) - > href ;
break ;
default :
break ;
}
if ( ( string ! = NULL ) & & ( string [ 0 ] ! = 0 ) ) {
if ( string [ 0 ] = = 0 )
return ( 0 ) ;
if ( len = = 1 ) {
return ( ret + ( ( ( unsigned int ) string [ 0 ] ) < < 8 ) ) ;
}
if ( string [ 1 ] = = 0 ) {
len = 1 ;
ret = ( unsigned int ) string [ 0 ] ;
} else {
return ( ( ( unsigned int ) string [ 0 ] ) +
( ( ( unsigned int ) string [ 1 ] ) < < 8 ) ) ;
}
}
/*
* Skip to next node
*/
if ( ( tmp - > children ! = NULL ) & & ( tmp - > type ! = XML_DTD_NODE ) ) {
if ( tmp - > children - > type ! = XML_ENTITY_DECL ) {
tmp = tmp - > children ;
continue ;
}
}
if ( tmp = = node )
break ;
if ( tmp - > next ! = NULL ) {
tmp = tmp - > next ;
continue ;
}
do {
tmp = tmp - > parent ;
if ( tmp = = NULL )
break ;
if ( tmp = = node ) {
tmp = NULL ;
break ;
}
if ( tmp - > next ! = NULL ) {
tmp = tmp - > next ;
break ;
}
} while ( tmp ! = NULL ) ;
}
return ( ret ) ;
}
/**
* xmlXPathStringHash :
* @ string : a string
*
* Function computing the beginning of the string value of the node ,
* used to speed up comparisons
*
* Returns an int usable as a hash
*/
static unsigned int
xmlXPathStringHash ( const xmlChar * string ) {
if ( string = = NULL )
return ( ( unsigned int ) 0 ) ;
if ( string [ 0 ] = = 0 )
return ( 0 ) ;
return ( ( ( unsigned int ) string [ 0 ] ) +
( ( ( unsigned int ) string [ 1 ] ) < < 8 ) ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathCompareNodeSetFloat :
* @ ctxt : the XPath Parser context
* @ inf : less than ( 1 ) or greater than ( 0 )
* @ strict : is the comparison strict
* @ arg : the node set
* @ f : the value
*
* Implement the compare operation between a nodeset and a number
* @ ns < @ val ( 1 , 1 , . . .
* @ ns < = @ val ( 1 , 0 , . . .
* @ ns > @ val ( 0 , 1 , . . .
* @ ns > = @ val ( 0 , 0 , . . .
*
* If one object to be compared is a node - set and the other is a number ,
* then the comparison will be true if and only if there is a node in the
* node - set such that the result of performing the comparison on the number
* to be compared and on the result of converting the string - value of that
* node to a number using the number function is true .
*
* Returns 0 or 1 depending on the results of the test .
*/
2001-03-24 17:00:36 +00:00
static int
2001-02-23 17:55:21 +00:00
xmlXPathCompareNodeSetFloat ( xmlXPathParserContextPtr ctxt , int inf , int strict ,
xmlXPathObjectPtr arg , xmlXPathObjectPtr f ) {
int i , ret = 0 ;
xmlNodeSetPtr ns ;
xmlChar * str2 ;
if ( ( f = = NULL ) | | ( arg = = NULL ) | |
( ( arg - > type ! = XPATH_NODESET ) & & ( arg - > type ! = XPATH_XSLT_TREE ) ) ) {
xmlXPathFreeObject ( arg ) ;
xmlXPathFreeObject ( f ) ;
return ( 0 ) ;
}
ns = arg - > nodesetval ;
2001-04-07 15:39:35 +00:00
if ( ns ! = NULL ) {
for ( i = 0 ; i < ns - > nodeNr ; i + + ) {
2001-05-15 09:43:47 +00:00
str2 = xmlXPathCastNodeToString ( ns - > nodeTab [ i ] ) ;
2001-04-07 15:39:35 +00:00
if ( str2 ! = NULL ) {
valuePush ( ctxt ,
xmlXPathNewString ( str2 ) ) ;
xmlFree ( str2 ) ;
xmlXPathNumberFunction ( ctxt , 1 ) ;
valuePush ( ctxt , xmlXPathObjectCopy ( f ) ) ;
ret = xmlXPathCompareValues ( ctxt , inf , strict ) ;
if ( ret )
break ;
}
}
2001-02-23 17:55:21 +00:00
}
xmlXPathFreeObject ( arg ) ;
xmlXPathFreeObject ( f ) ;
return ( ret ) ;
}
/**
* xmlXPathCompareNodeSetString :
* @ ctxt : the XPath Parser context
* @ inf : less than ( 1 ) or greater than ( 0 )
* @ strict : is the comparison strict
* @ arg : the node set
* @ s : the value
*
* Implement the compare operation between a nodeset and a string
* @ ns < @ val ( 1 , 1 , . . .
* @ ns < = @ val ( 1 , 0 , . . .
* @ ns > @ val ( 0 , 1 , . . .
* @ ns > = @ val ( 0 , 0 , . . .
*
* If one object to be compared is a node - set and the other is a string ,
* then the comparison will be true if and only if there is a node in
* the node - set such that the result of performing the comparison on the
* string - value of the node and the other string is true .
*
* Returns 0 or 1 depending on the results of the test .
*/
2001-03-24 17:00:36 +00:00
static int
2001-02-23 17:55:21 +00:00
xmlXPathCompareNodeSetString ( xmlXPathParserContextPtr ctxt , int inf , int strict ,
xmlXPathObjectPtr arg , xmlXPathObjectPtr s ) {
int i , ret = 0 ;
xmlNodeSetPtr ns ;
xmlChar * str2 ;
if ( ( s = = NULL ) | | ( arg = = NULL ) | |
( ( arg - > type ! = XPATH_NODESET ) & & ( arg - > type ! = XPATH_XSLT_TREE ) ) ) {
xmlXPathFreeObject ( arg ) ;
xmlXPathFreeObject ( s ) ;
return ( 0 ) ;
}
ns = arg - > nodesetval ;
2001-04-07 15:39:35 +00:00
if ( ns ! = NULL ) {
for ( i = 0 ; i < ns - > nodeNr ; i + + ) {
2001-05-15 09:43:47 +00:00
str2 = xmlXPathCastNodeToString ( ns - > nodeTab [ i ] ) ;
2001-04-07 15:39:35 +00:00
if ( str2 ! = NULL ) {
valuePush ( ctxt ,
xmlXPathNewString ( str2 ) ) ;
xmlFree ( str2 ) ;
valuePush ( ctxt , xmlXPathObjectCopy ( s ) ) ;
ret = xmlXPathCompareValues ( ctxt , inf , strict ) ;
if ( ret )
break ;
}
}
2001-02-23 17:55:21 +00:00
}
xmlXPathFreeObject ( arg ) ;
xmlXPathFreeObject ( s ) ;
return ( ret ) ;
}
/**
* xmlXPathCompareNodeSets :
2001-05-15 09:43:47 +00:00
* @ inf : less than ( 1 ) or greater than ( 0 )
2001-02-23 17:55:21 +00:00
* @ strict : is the comparison strict
2001-12-31 16:16:02 +00:00
* @ arg1 : the first node set object
2001-02-23 17:55:21 +00:00
* @ arg2 : the second node set object
*
* Implement the compare operation on nodesets :
*
* If both objects to be compared are node - sets , then the comparison
* will be true if and only if there is a node in the first node - set
* and a node in the second node - set such that the result of performing
* the comparison on the string - values of the two nodes is true .
* . . . .
* When neither object to be compared is a node - set and the operator
* is < = , < , > = or > , then the objects are compared by converting both
* objects to numbers and comparing the numbers according to IEEE 754.
* . . . .
* The number function converts its argument to a number as follows :
* - a string that consists of optional whitespace followed by an
* optional minus sign followed by a Number followed by whitespace
* is converted to the IEEE 754 number that is nearest ( according
* to the IEEE 754 round - to - nearest rule ) to the mathematical value
* represented by the string ; any other string is converted to NaN
*
* Conclusion all nodes need to be converted first to their string value
* and then the comparison must be done when possible
*/
2001-03-24 17:00:36 +00:00
static int
xmlXPathCompareNodeSets ( int inf , int strict ,
2001-02-23 17:55:21 +00:00
xmlXPathObjectPtr arg1 , xmlXPathObjectPtr arg2 ) {
int i , j , init = 0 ;
double val1 ;
double * values2 ;
int ret = 0 ;
xmlNodeSetPtr ns1 ;
xmlNodeSetPtr ns2 ;
if ( ( arg1 = = NULL ) | |
2001-04-02 15:16:19 +00:00
( ( arg1 - > type ! = XPATH_NODESET ) & & ( arg1 - > type ! = XPATH_XSLT_TREE ) ) ) {
xmlXPathFreeObject ( arg2 ) ;
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
2001-04-02 15:16:19 +00:00
}
2001-02-23 17:55:21 +00:00
if ( ( arg2 = = NULL ) | |
2001-04-02 15:16:19 +00:00
( ( arg2 - > type ! = XPATH_NODESET ) & & ( arg2 - > type ! = XPATH_XSLT_TREE ) ) ) {
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
2001-04-02 15:16:19 +00:00
}
2001-02-23 17:55:21 +00:00
ns1 = arg1 - > nodesetval ;
ns2 = arg2 - > nodesetval ;
2001-04-05 16:54:14 +00:00
if ( ( ns1 = = NULL ) | | ( ns1 - > nodeNr < = 0 ) ) {
2001-04-02 15:16:19 +00:00
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
2001-04-02 15:16:19 +00:00
}
2001-04-05 16:54:14 +00:00
if ( ( ns2 = = NULL ) | | ( ns2 - > nodeNr < = 0 ) ) {
2001-04-02 15:16:19 +00:00
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
2001-04-02 15:16:19 +00:00
}
2001-02-23 17:55:21 +00:00
values2 = ( double * ) xmlMalloc ( ns2 - > nodeNr * sizeof ( double ) ) ;
if ( values2 = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " comparing nodesets \n " ) ;
2001-04-02 15:16:19 +00:00
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
}
for ( i = 0 ; i < ns1 - > nodeNr ; i + + ) {
2001-05-15 09:43:47 +00:00
val1 = xmlXPathCastNodeToNumber ( ns1 - > nodeTab [ i ] ) ;
2001-08-21 10:56:31 +00:00
if ( xmlXPathIsNaN ( val1 ) )
2001-02-23 17:55:21 +00:00
continue ;
for ( j = 0 ; j < ns2 - > nodeNr ; j + + ) {
if ( init = = 0 ) {
2001-05-15 09:43:47 +00:00
values2 [ j ] = xmlXPathCastNodeToNumber ( ns2 - > nodeTab [ j ] ) ;
2001-02-23 17:55:21 +00:00
}
2001-08-21 10:56:31 +00:00
if ( xmlXPathIsNaN ( values2 [ j ] ) )
2001-02-23 17:55:21 +00:00
continue ;
if ( inf & & strict )
ret = ( val1 < values2 [ j ] ) ;
else if ( inf & & ! strict )
ret = ( val1 < = values2 [ j ] ) ;
else if ( ! inf & & strict )
ret = ( val1 > values2 [ j ] ) ;
else if ( ! inf & & ! strict )
ret = ( val1 > = values2 [ j ] ) ;
if ( ret )
break ;
}
if ( ret )
break ;
init = 1 ;
}
xmlFree ( values2 ) ;
2001-04-02 15:16:19 +00:00
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
2001-02-23 17:55:21 +00:00
return ( ret ) ;
}
/**
* xmlXPathCompareNodeSetValue :
* @ ctxt : the XPath Parser context
* @ inf : less than ( 1 ) or greater than ( 0 )
* @ strict : is the comparison strict
* @ arg : the node set
* @ val : the value
*
* Implement the compare operation between a nodeset and a value
* @ ns < @ val ( 1 , 1 , . . .
* @ ns < = @ val ( 1 , 0 , . . .
* @ ns > @ val ( 0 , 1 , . . .
* @ ns > = @ val ( 0 , 0 , . . .
*
* If one object to be compared is a node - set and the other is a boolean ,
* then the comparison will be true if and only if the result of performing
* the comparison on the boolean and on the result of converting
* the node - set to a boolean using the boolean function is true .
*
* Returns 0 or 1 depending on the results of the test .
*/
2001-03-24 17:00:36 +00:00
static int
2001-02-23 17:55:21 +00:00
xmlXPathCompareNodeSetValue ( xmlXPathParserContextPtr ctxt , int inf , int strict ,
xmlXPathObjectPtr arg , xmlXPathObjectPtr val ) {
if ( ( val = = NULL ) | | ( arg = = NULL ) | |
( ( arg - > type ! = XPATH_NODESET ) & & ( arg - > type ! = XPATH_XSLT_TREE ) ) )
return ( 0 ) ;
switch ( val - > type ) {
case XPATH_NUMBER :
return ( xmlXPathCompareNodeSetFloat ( ctxt , inf , strict , arg , val ) ) ;
case XPATH_NODESET :
case XPATH_XSLT_TREE :
2001-03-24 17:00:36 +00:00
return ( xmlXPathCompareNodeSets ( inf , strict , arg , val ) ) ;
2001-02-23 17:55:21 +00:00
case XPATH_STRING :
return ( xmlXPathCompareNodeSetString ( ctxt , inf , strict , arg , val ) ) ;
case XPATH_BOOLEAN :
valuePush ( ctxt , arg ) ;
xmlXPathBooleanFunction ( ctxt , 1 ) ;
valuePush ( ctxt , val ) ;
return ( xmlXPathCompareValues ( ctxt , inf , strict ) ) ;
default :
TODO
}
return ( 0 ) ;
}
/**
2002-12-10 15:19:08 +00:00
* xmlXPathEqualNodeSetString :
2001-02-23 17:55:21 +00:00
* @ arg : the nodeset object argument
* @ str : the string to compare to .
2002-07-12 00:56:01 +00:00
* @ neq : flag to show whether for ' = ' ( 0 ) or ' ! = ' ( 1 )
2001-02-23 17:55:21 +00:00
*
* Implement the equal operation on XPath objects content : @ arg1 = = @ arg2
* If one object to be compared is a node - set and the other is a string ,
* then the comparison will be true if and only if there is a node in
* the node - set such that the result of performing the comparison on the
* string - value of the node and the other string is true .
*
* Returns 0 or 1 depending on the results of the test .
*/
2001-03-24 17:00:36 +00:00
static int
2002-07-12 00:56:01 +00:00
xmlXPathEqualNodeSetString ( xmlXPathObjectPtr arg , const xmlChar * str , int neq )
2001-07-03 10:35:50 +00:00
{
2001-02-23 17:55:21 +00:00
int i ;
xmlNodeSetPtr ns ;
xmlChar * str2 ;
2001-07-03 10:35:50 +00:00
unsigned int hash ;
2001-02-23 17:55:21 +00:00
if ( ( str = = NULL ) | | ( arg = = NULL ) | |
2001-07-03 10:35:50 +00:00
( ( arg - > type ! = XPATH_NODESET ) & & ( arg - > type ! = XPATH_XSLT_TREE ) ) )
return ( 0 ) ;
2001-02-23 17:55:21 +00:00
ns = arg - > nodesetval ;
2003-11-16 08:06:19 +00:00
/*
* A NULL nodeset compared with a string is always false
* ( since there is no node equal , and no node not equal )
*/
if ( ( ns = = NULL ) | | ( ns - > nodeNr < = 0 ) )
2001-07-03 10:35:50 +00:00
return ( 0 ) ;
2003-11-16 08:06:19 +00:00
hash = xmlXPathStringHash ( str ) ;
2001-07-03 10:35:50 +00:00
for ( i = 0 ; i < ns - > nodeNr ; i + + ) {
if ( xmlXPathNodeValHash ( ns - > nodeTab [ i ] ) = = hash ) {
str2 = xmlNodeGetContent ( ns - > nodeTab [ i ] ) ;
if ( ( str2 ! = NULL ) & & ( xmlStrEqual ( str , str2 ) ) ) {
xmlFree ( str2 ) ;
2002-07-12 00:56:01 +00:00
if ( neq )
continue ;
2001-07-03 10:35:50 +00:00
return ( 1 ) ;
2003-03-24 18:39:54 +00:00
} else if ( ( str2 = = NULL ) & & ( xmlStrEqual ( str , BAD_CAST " " ) ) ) {
if ( neq )
continue ;
return ( 1 ) ;
2002-07-12 00:56:01 +00:00
} else if ( neq ) {
if ( str2 ! = NULL )
xmlFree ( str2 ) ;
return ( 1 ) ;
}
2001-07-03 10:35:50 +00:00
if ( str2 ! = NULL )
xmlFree ( str2 ) ;
2002-07-12 00:56:01 +00:00
} else if ( neq )
return ( 1 ) ;
2001-02-23 17:55:21 +00:00
}
2001-07-03 10:35:50 +00:00
return ( 0 ) ;
2001-02-23 17:55:21 +00:00
}
/**
2002-12-10 15:19:08 +00:00
* xmlXPathEqualNodeSetFloat :
2001-02-23 17:55:21 +00:00
* @ arg : the nodeset object argument
* @ f : the float to compare to
2002-07-12 00:56:01 +00:00
* @ neq : flag to show whether to compare ' = ' ( 0 ) or ' ! = ' ( 1 )
2001-02-23 17:55:21 +00:00
*
* Implement the equal operation on XPath objects content : @ arg1 = = @ arg2
* If one object to be compared is a node - set and the other is a number ,
* then the comparison will be true if and only if there is a node in
* the node - set such that the result of performing the comparison on the
* number to be compared and on the result of converting the string - value
* of that node to a number using the number function is true .
*
* Returns 0 or 1 depending on the results of the test .
*/
2001-03-24 17:00:36 +00:00
static int
2002-07-12 00:56:01 +00:00
xmlXPathEqualNodeSetFloat ( xmlXPathParserContextPtr ctxt ,
xmlXPathObjectPtr arg , double f , int neq ) {
int i , ret = 0 ;
xmlNodeSetPtr ns ;
xmlChar * str2 ;
xmlXPathObjectPtr val ;
double v ;
2001-02-23 17:55:21 +00:00
if ( ( arg = = NULL ) | |
( ( arg - > type ! = XPATH_NODESET ) & & ( arg - > type ! = XPATH_XSLT_TREE ) ) )
return ( 0 ) ;
2002-07-12 00:56:01 +00:00
ns = arg - > nodesetval ;
if ( ns ! = NULL ) {
for ( i = 0 ; i < ns - > nodeNr ; i + + ) {
str2 = xmlXPathCastNodeToString ( ns - > nodeTab [ i ] ) ;
if ( str2 ! = NULL ) {
valuePush ( ctxt , xmlXPathNewString ( str2 ) ) ;
xmlFree ( str2 ) ;
xmlXPathNumberFunction ( ctxt , 1 ) ;
val = valuePop ( ctxt ) ;
v = val - > floatval ;
xmlXPathFreeObject ( val ) ;
if ( ! xmlXPathIsNaN ( v ) ) {
if ( ( ! neq ) & & ( v = = f ) ) {
ret = 1 ;
break ;
} else if ( ( neq ) & & ( v ! = f ) ) {
ret = 1 ;
break ;
}
}
}
}
}
return ( ret ) ;
2001-02-23 17:55:21 +00:00
}
/**
2002-12-10 15:19:08 +00:00
* xmlXPathEqualNodeSets :
2001-02-23 17:55:21 +00:00
* @ arg1 : first nodeset object argument
* @ arg2 : second nodeset object argument
2002-07-12 00:56:01 +00:00
* @ neq : flag to show whether to test ' = ' ( 0 ) or ' ! = ' ( 1 )
2001-02-23 17:55:21 +00:00
*
2002-07-12 00:56:01 +00:00
* Implement the equal / not equal operation on XPath nodesets :
* @ arg1 = = @ arg2 or @ arg1 ! = @ arg2
2001-02-23 17:55:21 +00:00
* If both objects to be compared are node - sets , then the comparison
* will be true if and only if there is a node in the first node - set and
* a node in the second node - set such that the result of performing the
* comparison on the string - values of the two nodes is true .
*
* ( needless to say , this is a costly operation )
*
* Returns 0 or 1 depending on the results of the test .
*/
2001-03-24 17:00:36 +00:00
static int
2002-07-12 00:56:01 +00:00
xmlXPathEqualNodeSets ( xmlXPathObjectPtr arg1 , xmlXPathObjectPtr arg2 , int neq ) {
2001-02-23 17:55:21 +00:00
int i , j ;
2001-07-03 10:35:50 +00:00
unsigned int * hashs1 ;
unsigned int * hashs2 ;
2001-02-23 17:55:21 +00:00
xmlChar * * values1 ;
xmlChar * * values2 ;
int ret = 0 ;
xmlNodeSetPtr ns1 ;
xmlNodeSetPtr ns2 ;
if ( ( arg1 = = NULL ) | |
( ( arg1 - > type ! = XPATH_NODESET ) & & ( arg1 - > type ! = XPATH_XSLT_TREE ) ) )
return ( 0 ) ;
if ( ( arg2 = = NULL ) | |
( ( arg2 - > type ! = XPATH_NODESET ) & & ( arg2 - > type ! = XPATH_XSLT_TREE ) ) )
return ( 0 ) ;
ns1 = arg1 - > nodesetval ;
ns2 = arg2 - > nodesetval ;
2001-04-07 15:39:35 +00:00
if ( ( ns1 = = NULL ) | | ( ns1 - > nodeNr < = 0 ) )
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
2001-04-07 15:39:35 +00:00
if ( ( ns2 = = NULL ) | | ( ns2 - > nodeNr < = 0 ) )
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
/*
2002-07-12 00:56:01 +00:00
* for equal , check if there is a node pertaining to both sets
2001-02-23 17:55:21 +00:00
*/
2002-07-12 00:56:01 +00:00
if ( neq = = 0 )
for ( i = 0 ; i < ns1 - > nodeNr ; i + + )
for ( j = 0 ; j < ns2 - > nodeNr ; j + + )
if ( ns1 - > nodeTab [ i ] = = ns2 - > nodeTab [ j ] )
return ( 1 ) ;
2001-02-23 17:55:21 +00:00
values1 = ( xmlChar * * ) xmlMalloc ( ns1 - > nodeNr * sizeof ( xmlChar * ) ) ;
2003-10-07 21:25:12 +00:00
if ( values1 = = NULL ) {
xmlXPathErrMemory ( NULL , " comparing nodesets \n " ) ;
2001-02-23 17:55:21 +00:00
return ( 0 ) ;
2003-10-07 21:25:12 +00:00
}
2001-07-03 10:35:50 +00:00
hashs1 = ( unsigned int * ) xmlMalloc ( ns1 - > nodeNr * sizeof ( unsigned int ) ) ;
if ( hashs1 = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " comparing nodesets \n " ) ;
2001-07-03 10:35:50 +00:00
xmlFree ( values1 ) ;
return ( 0 ) ;
}
2001-02-23 17:55:21 +00:00
memset ( values1 , 0 , ns1 - > nodeNr * sizeof ( xmlChar * ) ) ;
values2 = ( xmlChar * * ) xmlMalloc ( ns2 - > nodeNr * sizeof ( xmlChar * ) ) ;
if ( values2 = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " comparing nodesets \n " ) ;
2001-07-03 10:35:50 +00:00
xmlFree ( hashs1 ) ;
2001-02-23 17:55:21 +00:00
xmlFree ( values1 ) ;
return ( 0 ) ;
}
2001-07-03 10:35:50 +00:00
hashs2 = ( unsigned int * ) xmlMalloc ( ns2 - > nodeNr * sizeof ( unsigned int ) ) ;
if ( hashs2 = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathErrMemory ( NULL , " comparing nodesets \n " ) ;
2001-07-03 10:35:50 +00:00
xmlFree ( hashs1 ) ;
xmlFree ( values1 ) ;
xmlFree ( values2 ) ;
return ( 0 ) ;
}
2001-02-23 17:55:21 +00:00
memset ( values2 , 0 , ns2 - > nodeNr * sizeof ( xmlChar * ) ) ;
for ( i = 0 ; i < ns1 - > nodeNr ; i + + ) {
2001-07-03 10:35:50 +00:00
hashs1 [ i ] = xmlXPathNodeValHash ( ns1 - > nodeTab [ i ] ) ;
2001-02-23 17:55:21 +00:00
for ( j = 0 ; j < ns2 - > nodeNr ; j + + ) {
if ( i = = 0 )
2001-07-03 10:35:50 +00:00
hashs2 [ j ] = xmlXPathNodeValHash ( ns2 - > nodeTab [ j ] ) ;
2002-07-12 00:56:01 +00:00
if ( hashs1 [ i ] ! = hashs2 [ j ] ) {
if ( neq ) {
ret = 1 ;
break ;
}
}
else {
2001-07-03 10:35:50 +00:00
if ( values1 [ i ] = = NULL )
values1 [ i ] = xmlNodeGetContent ( ns1 - > nodeTab [ i ] ) ;
if ( values2 [ j ] = = NULL )
values2 [ j ] = xmlNodeGetContent ( ns2 - > nodeTab [ j ] ) ;
2002-07-12 00:56:01 +00:00
ret = xmlStrEqual ( values1 [ i ] , values2 [ j ] ) ^ neq ;
2001-07-03 10:35:50 +00:00
if ( ret )
break ;
}
2001-02-23 17:55:21 +00:00
}
if ( ret )
break ;
}
for ( i = 0 ; i < ns1 - > nodeNr ; i + + )
if ( values1 [ i ] ! = NULL )
xmlFree ( values1 [ i ] ) ;
for ( j = 0 ; j < ns2 - > nodeNr ; j + + )
if ( values2 [ j ] ! = NULL )
xmlFree ( values2 [ j ] ) ;
xmlFree ( values1 ) ;
xmlFree ( values2 ) ;
2001-07-03 10:35:50 +00:00
xmlFree ( hashs1 ) ;
xmlFree ( hashs2 ) ;
2001-02-23 17:55:21 +00:00
return ( ret ) ;
}
2002-07-12 00:56:01 +00:00
static int
xmlXPathEqualValuesCommon ( xmlXPathParserContextPtr ctxt ,
xmlXPathObjectPtr arg1 , xmlXPathObjectPtr arg2 ) {
2001-02-23 17:55:21 +00:00
int ret = 0 ;
2002-07-12 00:56:01 +00:00
/*
* At this point we are assured neither arg1 nor arg2
* is a nodeset , so we can just pick the appropriate routine .
*/
2001-02-23 17:55:21 +00:00
switch ( arg1 - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" Equal: undefined \n " ) ;
# endif
break ;
case XPATH_BOOLEAN :
switch ( arg2 - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" Equal: undefined \n " ) ;
# endif
break ;
case XPATH_BOOLEAN :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" Equal: %d boolean %d \n " ,
arg1 - > boolval , arg2 - > boolval ) ;
# endif
ret = ( arg1 - > boolval = = arg2 - > boolval ) ;
break ;
case XPATH_NUMBER :
2002-07-19 08:32:00 +00:00
ret = ( arg1 - > boolval = =
xmlXPathCastNumberToBoolean ( arg2 - > floatval ) ) ;
2001-02-23 17:55:21 +00:00
break ;
case XPATH_STRING :
if ( ( arg2 - > stringval = = NULL ) | |
( arg2 - > stringval [ 0 ] = = 0 ) ) ret = 0 ;
else
ret = 1 ;
ret = ( arg1 - > boolval = = ret ) ;
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO
break ;
2002-07-12 00:56:01 +00:00
case XPATH_NODESET :
case XPATH_XSLT_TREE :
break ;
2001-02-23 17:55:21 +00:00
}
break ;
case XPATH_NUMBER :
switch ( arg2 - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" Equal: undefined \n " ) ;
# endif
break ;
case XPATH_BOOLEAN :
2002-07-19 08:32:00 +00:00
ret = ( arg2 - > boolval = =
xmlXPathCastNumberToBoolean ( arg1 - > floatval ) ) ;
2001-02-23 17:55:21 +00:00
break ;
case XPATH_STRING :
valuePush ( ctxt , arg2 ) ;
xmlXPathNumberFunction ( ctxt , 1 ) ;
arg2 = valuePop ( ctxt ) ;
/* no break on purpose */
case XPATH_NUMBER :
2002-03-28 18:25:31 +00:00
/* Hand check NaN and Infinity equalities */
2002-03-27 16:12:22 +00:00
if ( xmlXPathIsNaN ( arg1 - > floatval ) | | xmlXPathIsNaN ( arg2 - > floatval ) ) {
ret = 0 ;
2002-03-28 18:25:31 +00:00
} else if ( xmlXPathIsInf ( arg1 - > floatval ) = = 1 ) {
if ( xmlXPathIsInf ( arg2 - > floatval ) = = 1 )
ret = 1 ;
else
ret = 0 ;
} else if ( xmlXPathIsInf ( arg1 - > floatval ) = = - 1 ) {
if ( xmlXPathIsInf ( arg2 - > floatval ) = = - 1 )
ret = 1 ;
else
ret = 0 ;
} else if ( xmlXPathIsInf ( arg2 - > floatval ) = = 1 ) {
if ( xmlXPathIsInf ( arg1 - > floatval ) = = 1 )
ret = 1 ;
else
ret = 0 ;
} else if ( xmlXPathIsInf ( arg2 - > floatval ) = = - 1 ) {
if ( xmlXPathIsInf ( arg1 - > floatval ) = = - 1 )
ret = 1 ;
else
ret = 0 ;
2002-03-27 16:12:22 +00:00
} else {
ret = ( arg1 - > floatval = = arg2 - > floatval ) ;
}
2001-02-23 17:55:21 +00:00
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO
break ;
2002-07-12 00:56:01 +00:00
case XPATH_NODESET :
case XPATH_XSLT_TREE :
break ;
2001-02-23 17:55:21 +00:00
}
break ;
case XPATH_STRING :
switch ( arg2 - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" Equal: undefined \n " ) ;
# endif
break ;
case XPATH_BOOLEAN :
if ( ( arg1 - > stringval = = NULL ) | |
( arg1 - > stringval [ 0 ] = = 0 ) ) ret = 0 ;
else
ret = 1 ;
ret = ( arg2 - > boolval = = ret ) ;
break ;
case XPATH_STRING :
ret = xmlStrEqual ( arg1 - > stringval , arg2 - > stringval ) ;
break ;
case XPATH_NUMBER :
valuePush ( ctxt , arg1 ) ;
xmlXPathNumberFunction ( ctxt , 1 ) ;
arg1 = valuePop ( ctxt ) ;
2002-03-28 18:25:31 +00:00
/* Hand check NaN and Infinity equalities */
2002-03-27 16:12:22 +00:00
if ( xmlXPathIsNaN ( arg1 - > floatval ) | | xmlXPathIsNaN ( arg2 - > floatval ) ) {
ret = 0 ;
2002-03-28 18:25:31 +00:00
} else if ( xmlXPathIsInf ( arg1 - > floatval ) = = 1 ) {
if ( xmlXPathIsInf ( arg2 - > floatval ) = = 1 )
ret = 1 ;
else
ret = 0 ;
} else if ( xmlXPathIsInf ( arg1 - > floatval ) = = - 1 ) {
if ( xmlXPathIsInf ( arg2 - > floatval ) = = - 1 )
ret = 1 ;
else
ret = 0 ;
} else if ( xmlXPathIsInf ( arg2 - > floatval ) = = 1 ) {
if ( xmlXPathIsInf ( arg1 - > floatval ) = = 1 )
ret = 1 ;
else
ret = 0 ;
} else if ( xmlXPathIsInf ( arg2 - > floatval ) = = - 1 ) {
if ( xmlXPathIsInf ( arg1 - > floatval ) = = - 1 )
ret = 1 ;
else
ret = 0 ;
2002-03-27 16:12:22 +00:00
} else {
ret = ( arg1 - > floatval = = arg2 - > floatval ) ;
}
2001-02-23 17:55:21 +00:00
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO
break ;
2002-07-12 00:56:01 +00:00
case XPATH_NODESET :
case XPATH_XSLT_TREE :
break ;
2001-02-23 17:55:21 +00:00
}
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO
break ;
2002-07-12 00:56:01 +00:00
case XPATH_NODESET :
case XPATH_XSLT_TREE :
break ;
2001-02-23 17:55:21 +00:00
}
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
return ( ret ) ;
}
2002-07-12 00:56:01 +00:00
/**
* xmlXPathEqualValues :
* @ ctxt : the XPath Parser context
*
* Implement the equal operation on XPath objects content : @ arg1 = = @ arg2
*
* Returns 0 or 1 depending on the results of the test .
*/
int
xmlXPathEqualValues ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr arg1 , arg2 , argtmp ;
int ret = 0 ;
arg2 = valuePop ( ctxt ) ;
arg1 = valuePop ( ctxt ) ;
if ( ( arg1 = = NULL ) | | ( arg2 = = NULL ) ) {
if ( arg1 ! = NULL )
xmlXPathFreeObject ( arg1 ) ;
else
xmlXPathFreeObject ( arg2 ) ;
XP_ERROR0 ( XPATH_INVALID_OPERAND ) ;
}
if ( arg1 = = arg2 ) {
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" Equal: by pointer \n " ) ;
# endif
return ( 1 ) ;
}
/*
* If either argument is a nodeset , it ' s a ' special case '
*/
if ( ( arg2 - > type = = XPATH_NODESET ) | | ( arg2 - > type = = XPATH_XSLT_TREE ) | |
( arg1 - > type = = XPATH_NODESET ) | | ( arg1 - > type = = XPATH_XSLT_TREE ) ) {
/*
* Hack it to assure arg1 is the nodeset
*/
if ( ( arg1 - > type ! = XPATH_NODESET ) & & ( arg1 - > type ! = XPATH_XSLT_TREE ) ) {
argtmp = arg2 ;
arg2 = arg1 ;
arg1 = argtmp ;
}
switch ( arg2 - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" Equal: undefined \n " ) ;
# endif
break ;
case XPATH_NODESET :
case XPATH_XSLT_TREE :
ret = xmlXPathEqualNodeSets ( arg1 , arg2 , 0 ) ;
break ;
case XPATH_BOOLEAN :
if ( ( arg1 - > nodesetval = = NULL ) | |
( arg1 - > nodesetval - > nodeNr = = 0 ) ) ret = 0 ;
else
ret = 1 ;
ret = ( ret = = arg2 - > boolval ) ;
break ;
case XPATH_NUMBER :
ret = xmlXPathEqualNodeSetFloat ( ctxt , arg1 , arg2 - > floatval , 0 ) ;
break ;
case XPATH_STRING :
ret = xmlXPathEqualNodeSetString ( arg1 , arg2 - > stringval , 0 ) ;
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO
break ;
}
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
return ( ret ) ;
}
return ( xmlXPathEqualValuesCommon ( ctxt , arg1 , arg2 ) ) ;
}
/**
* xmlXPathNotEqualValues :
* @ ctxt : the XPath Parser context
*
* Implement the equal operation on XPath objects content : @ arg1 = = @ arg2
*
* Returns 0 or 1 depending on the results of the test .
*/
int
xmlXPathNotEqualValues ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr arg1 , arg2 , argtmp ;
int ret = 0 ;
arg2 = valuePop ( ctxt ) ;
arg1 = valuePop ( ctxt ) ;
if ( ( arg1 = = NULL ) | | ( arg2 = = NULL ) ) {
if ( arg1 ! = NULL )
xmlXPathFreeObject ( arg1 ) ;
else
xmlXPathFreeObject ( arg2 ) ;
XP_ERROR0 ( XPATH_INVALID_OPERAND ) ;
}
if ( arg1 = = arg2 ) {
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" NotEqual: by pointer \n " ) ;
# endif
return ( 0 ) ;
}
/*
* If either argument is a nodeset , it ' s a ' special case '
*/
if ( ( arg2 - > type = = XPATH_NODESET ) | | ( arg2 - > type = = XPATH_XSLT_TREE ) | |
( arg1 - > type = = XPATH_NODESET ) | | ( arg1 - > type = = XPATH_XSLT_TREE ) ) {
/*
* Hack it to assure arg1 is the nodeset
*/
if ( ( arg1 - > type ! = XPATH_NODESET ) & & ( arg1 - > type ! = XPATH_XSLT_TREE ) ) {
argtmp = arg2 ;
arg2 = arg1 ;
arg1 = argtmp ;
}
switch ( arg2 - > type ) {
case XPATH_UNDEFINED :
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" NotEqual: undefined \n " ) ;
# endif
break ;
case XPATH_NODESET :
case XPATH_XSLT_TREE :
ret = xmlXPathEqualNodeSets ( arg1 , arg2 , 1 ) ;
break ;
case XPATH_BOOLEAN :
if ( ( arg1 - > nodesetval = = NULL ) | |
( arg1 - > nodesetval - > nodeNr = = 0 ) ) ret = 0 ;
else
ret = 1 ;
2002-07-19 08:32:00 +00:00
ret = ( ret ! = arg2 - > boolval ) ;
2002-07-12 00:56:01 +00:00
break ;
case XPATH_NUMBER :
ret = xmlXPathEqualNodeSetFloat ( ctxt , arg1 , arg2 - > floatval , 1 ) ;
break ;
case XPATH_STRING :
ret = xmlXPathEqualNodeSetString ( arg1 , arg2 - > stringval , 1 ) ;
break ;
case XPATH_USERS :
case XPATH_POINT :
case XPATH_RANGE :
case XPATH_LOCATIONSET :
TODO
break ;
}
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
return ( ret ) ;
}
return ( ! xmlXPathEqualValuesCommon ( ctxt , arg1 , arg2 ) ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathCompareValues :
* @ ctxt : the XPath Parser context
* @ inf : less than ( 1 ) or greater than ( 0 )
* @ strict : is the comparison strict
*
* Implement the compare operation on XPath objects :
* @ arg1 < @ arg2 ( 1 , 1 , . . .
* @ arg1 < = @ arg2 ( 1 , 0 , . . .
* @ arg1 > @ arg2 ( 0 , 1 , . . .
* @ arg1 > = @ arg2 ( 0 , 0 , . . .
*
* When neither object to be compared is a node - set and the operator is
* < = , < , > = , > , then the objects are compared by converted both objects
* to numbers and comparing the numbers according to IEEE 754. The <
* comparison will be true if and only if the first number is less than the
* second number . The < = comparison will be true if and only if the first
* number is less than or equal to the second number . The > comparison
* will be true if and only if the first number is greater than the second
* number . The > = comparison will be true if and only if the first number
* is greater than or equal to the second number .
*
2001-12-31 16:16:02 +00:00
* Returns 1 if the comparison succeeded , 0 if it failed
2001-02-23 17:55:21 +00:00
*/
int
xmlXPathCompareValues ( xmlXPathParserContextPtr ctxt , int inf , int strict ) {
2002-03-28 18:25:31 +00:00
int ret = 0 , arg1i = 0 , arg2i = 0 ;
2001-02-23 17:55:21 +00:00
xmlXPathObjectPtr arg1 , arg2 ;
2002-07-12 00:56:01 +00:00
arg2 = valuePop ( ctxt ) ;
2001-02-23 17:55:21 +00:00
arg1 = valuePop ( ctxt ) ;
2002-07-12 00:56:01 +00:00
if ( ( arg1 = = NULL ) | | ( arg2 = = NULL ) ) {
if ( arg1 ! = NULL )
xmlXPathFreeObject ( arg1 ) ;
else
xmlXPathFreeObject ( arg2 ) ;
2001-02-23 17:55:21 +00:00
XP_ERROR0 ( XPATH_INVALID_OPERAND ) ;
}
2002-07-12 00:56:01 +00:00
if ( ( arg2 - > type = = XPATH_NODESET ) | | ( arg2 - > type = = XPATH_XSLT_TREE ) | |
( arg1 - > type = = XPATH_NODESET ) | | ( arg1 - > type = = XPATH_XSLT_TREE ) ) {
if ( ( ( arg2 - > type = = XPATH_NODESET ) | | ( arg2 - > type = = XPATH_XSLT_TREE ) ) & &
( ( arg1 - > type = = XPATH_NODESET ) | | ( arg1 - > type = = XPATH_XSLT_TREE ) ) ) {
2001-03-24 17:00:36 +00:00
ret = xmlXPathCompareNodeSets ( inf , strict , arg1 , arg2 ) ;
2001-02-23 17:55:21 +00:00
} else {
2002-07-12 00:56:01 +00:00
if ( ( arg1 - > type = = XPATH_NODESET ) | | ( arg1 - > type = = XPATH_XSLT_TREE ) ) {
2001-03-06 08:33:38 +00:00
ret = xmlXPathCompareNodeSetValue ( ctxt , inf , strict ,
arg1 , arg2 ) ;
2001-02-23 17:55:21 +00:00
} else {
2001-03-06 08:33:38 +00:00
ret = xmlXPathCompareNodeSetValue ( ctxt , ! inf , strict ,
arg2 , arg1 ) ;
2001-02-23 17:55:21 +00:00
}
}
return ( ret ) ;
}
if ( arg1 - > type ! = XPATH_NUMBER ) {
valuePush ( ctxt , arg1 ) ;
xmlXPathNumberFunction ( ctxt , 1 ) ;
arg1 = valuePop ( ctxt ) ;
}
if ( arg1 - > type ! = XPATH_NUMBER ) {
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
XP_ERROR0 ( XPATH_INVALID_OPERAND ) ;
}
if ( arg2 - > type ! = XPATH_NUMBER ) {
valuePush ( ctxt , arg2 ) ;
xmlXPathNumberFunction ( ctxt , 1 ) ;
arg2 = valuePop ( ctxt ) ;
}
if ( arg2 - > type ! = XPATH_NUMBER ) {
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
XP_ERROR0 ( XPATH_INVALID_OPERAND ) ;
}
/*
* Add tests for infinity and nan
* = > feedback on 3.4 for Inf and NaN
*/
2002-03-28 18:25:31 +00:00
/* Hand check NaN and Infinity comparisons */
2002-03-27 16:12:22 +00:00
if ( xmlXPathIsNaN ( arg1 - > floatval ) | | xmlXPathIsNaN ( arg2 - > floatval ) ) {
2002-03-28 18:25:31 +00:00
ret = 0 ;
2002-03-27 16:12:22 +00:00
} else {
2002-03-28 18:25:31 +00:00
arg1i = xmlXPathIsInf ( arg1 - > floatval ) ;
arg2i = xmlXPathIsInf ( arg2 - > floatval ) ;
if ( inf & & strict ) {
if ( ( arg1i = = - 1 & & arg2i ! = - 1 ) | |
( arg2i = = 1 & & arg1i ! = 1 ) ) {
ret = 1 ;
} else if ( arg1i = = 0 & & arg2i = = 0 ) {
ret = ( arg1 - > floatval < arg2 - > floatval ) ;
} else {
ret = 0 ;
}
}
else if ( inf & & ! strict ) {
if ( arg1i = = - 1 | | arg2i = = 1 ) {
ret = 1 ;
} else if ( arg1i = = 0 & & arg2i = = 0 ) {
ret = ( arg1 - > floatval < = arg2 - > floatval ) ;
} else {
ret = 0 ;
}
}
else if ( ! inf & & strict ) {
if ( ( arg1i = = 1 & & arg2i ! = 1 ) | |
( arg2i = = - 1 & & arg1i ! = - 1 ) ) {
ret = 1 ;
} else if ( arg1i = = 0 & & arg2i = = 0 ) {
ret = ( arg1 - > floatval > arg2 - > floatval ) ;
} else {
ret = 0 ;
}
}
else if ( ! inf & & ! strict ) {
if ( arg1i = = 1 | | arg2i = = - 1 ) {
ret = 1 ;
} else if ( arg1i = = 0 & & arg2i = = 0 ) {
ret = ( arg1 - > floatval > = arg2 - > floatval ) ;
} else {
ret = 0 ;
}
}
2002-03-27 16:12:22 +00:00
}
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
return ( ret ) ;
}
/**
* xmlXPathValueFlipSign :
* @ ctxt : the XPath Parser context
*
* Implement the unary - operation on an XPath object
* The numeric operators convert their operands to numbers as if
* by calling the number function .
*/
void
xmlXPathValueFlipSign ( xmlXPathParserContextPtr ctxt ) {
2001-05-15 09:43:47 +00:00
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
2002-04-24 11:42:02 +00:00
if ( xmlXPathIsNaN ( ctxt - > value - > floatval ) )
ctxt - > value - > floatval = xmlXPathNAN ;
else if ( xmlXPathIsInf ( ctxt - > value - > floatval ) = = 1 )
ctxt - > value - > floatval = xmlXPathNINF ;
else if ( xmlXPathIsInf ( ctxt - > value - > floatval ) = = - 1 )
ctxt - > value - > floatval = xmlXPathPINF ;
else if ( ctxt - > value - > floatval = = 0 ) {
2002-03-27 09:05:40 +00:00
if ( xmlXPathGetSign ( ctxt - > value - > floatval ) = = 0 )
ctxt - > value - > floatval = xmlXPathNZERO ;
else
ctxt - > value - > floatval = 0 ;
}
else
ctxt - > value - > floatval = - ctxt - > value - > floatval ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathAddValues :
* @ ctxt : the XPath Parser context
*
* Implement the add operation on XPath objects :
* The numeric operators convert their operands to numbers as if
* by calling the number function .
*/
void
xmlXPathAddValues ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr arg ;
double val ;
2001-05-15 09:43:47 +00:00
arg = valuePop ( ctxt ) ;
if ( arg = = NULL )
XP_ERROR ( XPATH_INVALID_OPERAND ) ;
val = xmlXPathCastToNumber ( arg ) ;
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( arg ) ;
2001-05-15 09:43:47 +00:00
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
ctxt - > value - > floatval + = val ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathSubValues :
* @ ctxt : the XPath Parser context
*
2001-12-31 16:16:02 +00:00
* Implement the subtraction operation on XPath objects :
2001-02-23 17:55:21 +00:00
* The numeric operators convert their operands to numbers as if
* by calling the number function .
*/
void
xmlXPathSubValues ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr arg ;
double val ;
2001-05-15 09:43:47 +00:00
arg = valuePop ( ctxt ) ;
if ( arg = = NULL )
XP_ERROR ( XPATH_INVALID_OPERAND ) ;
val = xmlXPathCastToNumber ( arg ) ;
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( arg ) ;
2001-05-15 09:43:47 +00:00
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
ctxt - > value - > floatval - = val ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathMultValues :
* @ ctxt : the XPath Parser context
*
* Implement the multiply operation on XPath objects :
* The numeric operators convert their operands to numbers as if
* by calling the number function .
*/
void
xmlXPathMultValues ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr arg ;
double val ;
2001-05-15 09:43:47 +00:00
arg = valuePop ( ctxt ) ;
if ( arg = = NULL )
XP_ERROR ( XPATH_INVALID_OPERAND ) ;
val = xmlXPathCastToNumber ( arg ) ;
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( arg ) ;
2001-05-15 09:43:47 +00:00
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
ctxt - > value - > floatval * = val ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathDivValues :
* @ ctxt : the XPath Parser context
*
* Implement the div operation on XPath objects @ arg1 / @ arg2 :
* The numeric operators convert their operands to numbers as if
* by calling the number function .
*/
void
xmlXPathDivValues ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr arg ;
double val ;
2001-05-15 09:43:47 +00:00
arg = valuePop ( ctxt ) ;
if ( arg = = NULL )
XP_ERROR ( XPATH_INVALID_OPERAND ) ;
val = xmlXPathCastToNumber ( arg ) ;
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( arg ) ;
2001-05-15 09:43:47 +00:00
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
2002-04-24 11:42:02 +00:00
if ( xmlXPathIsNaN ( val ) | | xmlXPathIsNaN ( ctxt - > value - > floatval ) )
ctxt - > value - > floatval = xmlXPathNAN ;
else if ( val = = 0 & & xmlXPathGetSign ( val ) ! = 0 ) {
2002-03-27 09:05:40 +00:00
if ( ctxt - > value - > floatval = = 0 )
ctxt - > value - > floatval = xmlXPathNAN ;
else if ( ctxt - > value - > floatval > 0 )
ctxt - > value - > floatval = xmlXPathNINF ;
else if ( ctxt - > value - > floatval < 0 )
ctxt - > value - > floatval = xmlXPathPINF ;
}
else if ( val = = 0 ) {
2002-02-20 10:22:49 +00:00
if ( ctxt - > value - > floatval = = 0 )
ctxt - > value - > floatval = xmlXPathNAN ;
else if ( ctxt - > value - > floatval > 0 )
ctxt - > value - > floatval = xmlXPathPINF ;
else if ( ctxt - > value - > floatval < 0 )
ctxt - > value - > floatval = xmlXPathNINF ;
} else
ctxt - > value - > floatval / = val ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathModValues :
* @ ctxt : the XPath Parser context
*
* Implement the mod operation on XPath objects : @ arg1 / @ arg2
* The numeric operators convert their operands to numbers as if
* by calling the number function .
*/
void
xmlXPathModValues ( xmlXPathParserContextPtr ctxt ) {
xmlXPathObjectPtr arg ;
2002-07-01 21:52:03 +00:00
double arg1 , arg2 ;
2001-02-23 17:55:21 +00:00
2001-05-15 09:43:47 +00:00
arg = valuePop ( ctxt ) ;
if ( arg = = NULL )
XP_ERROR ( XPATH_INVALID_OPERAND ) ;
2002-03-27 09:05:40 +00:00
arg2 = xmlXPathCastToNumber ( arg ) ;
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( arg ) ;
2001-05-15 09:43:47 +00:00
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
2002-03-27 09:05:40 +00:00
arg1 = ctxt - > value - > floatval ;
2001-08-26 18:46:36 +00:00
if ( arg2 = = 0 )
ctxt - > value - > floatval = xmlXPathNAN ;
2002-03-27 09:05:40 +00:00
else {
2002-07-01 21:52:03 +00:00
ctxt - > value - > floatval = fmod ( arg1 , arg2 ) ;
2002-03-27 09:05:40 +00:00
}
2001-02-23 17:55:21 +00:00
}
/************************************************************************
* *
* The traversal functions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* A traversal function enumerates nodes along an axis .
* Initially it must be called with NULL , and it indicates
* termination on the axis by returning NULL .
*/
typedef xmlNodePtr ( * xmlXPathTraversalFunction )
( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) ;
/**
* xmlXPathNextSelf :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " self " direction
* The self axis contains just the context node itself
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextSelf ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( cur = = NULL )
return ( ctxt - > context - > node ) ;
return ( NULL ) ;
}
/**
* xmlXPathNextChild :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " child " direction
* The child axis contains the children of the context node in document order .
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextChild ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( cur = = NULL ) {
if ( ctxt - > context - > node = = NULL ) return ( NULL ) ;
switch ( ctxt - > context - > node - > type ) {
case XML_ELEMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
case XML_ENTITY_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_NOTATION_NODE :
case XML_DTD_NODE :
return ( ctxt - > context - > node - > children ) ;
case XML_DOCUMENT_NODE :
case XML_DOCUMENT_TYPE_NODE :
case XML_DOCUMENT_FRAG_NODE :
case XML_HTML_DOCUMENT_NODE :
2001-04-23 13:41:34 +00:00
# ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE :
2001-02-23 17:55:21 +00:00
# endif
return ( ( ( xmlDocPtr ) ctxt - > context - > node ) - > children ) ;
case XML_ELEMENT_DECL :
case XML_ATTRIBUTE_DECL :
case XML_ENTITY_DECL :
case XML_ATTRIBUTE_NODE :
case XML_NAMESPACE_DECL :
case XML_XINCLUDE_START :
case XML_XINCLUDE_END :
return ( NULL ) ;
}
return ( NULL ) ;
}
if ( ( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) )
return ( NULL ) ;
return ( cur - > next ) ;
}
/**
* xmlXPathNextDescendant :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " descendant " direction
* the descendant axis contains the descendants of the context node in document
* order ; a descendant is a child or a child of a child and so on .
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextDescendant ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( cur = = NULL ) {
if ( ctxt - > context - > node = = NULL )
return ( NULL ) ;
if ( ( ctxt - > context - > node - > type = = XML_ATTRIBUTE_NODE ) | |
( ctxt - > context - > node - > type = = XML_NAMESPACE_DECL ) )
return ( NULL ) ;
if ( ctxt - > context - > node = = ( xmlNodePtr ) ctxt - > context - > doc )
return ( ctxt - > context - > doc - > children ) ;
return ( ctxt - > context - > node - > children ) ;
}
2001-08-01 15:53:47 +00:00
if ( cur - > children ! = NULL ) {
2002-11-16 15:35:11 +00:00
/*
* Do not descend on entities declarations
*/
if ( cur - > children - > type ! = XML_ENTITY_DECL ) {
cur = cur - > children ;
/*
* Skip DTDs
*/
if ( cur - > type ! = XML_DTD_NODE )
return ( cur ) ;
}
2001-08-01 15:53:47 +00:00
}
if ( cur = = ctxt - > context - > node ) return ( NULL ) ;
2002-11-16 15:35:11 +00:00
while ( cur - > next ! = NULL ) {
cur = cur - > next ;
if ( ( cur - > type ! = XML_ENTITY_DECL ) & &
( cur - > type ! = XML_DTD_NODE ) )
return ( cur ) ;
}
2001-02-23 17:55:21 +00:00
do {
cur = cur - > parent ;
if ( cur = = NULL ) return ( NULL ) ;
if ( cur = = ctxt - > context - > node ) return ( NULL ) ;
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
return ( cur ) ;
}
} while ( cur ! = NULL ) ;
return ( cur ) ;
}
/**
* xmlXPathNextDescendantOrSelf :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " descendant-or-self " direction
* the descendant - or - self axis contains the context node and the descendants
* of the context node in document order ; thus the context node is the first
* node on the axis , and the first child of the context node is the second node
* on the axis
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextDescendantOrSelf ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( cur = = NULL ) {
if ( ctxt - > context - > node = = NULL )
return ( NULL ) ;
if ( ( ctxt - > context - > node - > type = = XML_ATTRIBUTE_NODE ) | |
( ctxt - > context - > node - > type = = XML_NAMESPACE_DECL ) )
return ( NULL ) ;
return ( ctxt - > context - > node ) ;
}
return ( xmlXPathNextDescendant ( ctxt , cur ) ) ;
}
/**
* xmlXPathNextParent :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " parent " direction
* The parent axis contains the parent of the context node , if there is one .
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextParent ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
/*
* the parent of an attribute or namespace node is the element
* to which the attribute or namespace node is attached
* Namespace handling ! ! !
*/
if ( cur = = NULL ) {
if ( ctxt - > context - > node = = NULL ) return ( NULL ) ;
switch ( ctxt - > context - > node - > type ) {
case XML_ELEMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
case XML_ENTITY_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_NOTATION_NODE :
case XML_DTD_NODE :
case XML_ELEMENT_DECL :
case XML_ATTRIBUTE_DECL :
case XML_XINCLUDE_START :
case XML_XINCLUDE_END :
case XML_ENTITY_DECL :
if ( ctxt - > context - > node - > parent = = NULL )
return ( ( xmlNodePtr ) ctxt - > context - > doc ) ;
2003-01-10 17:06:09 +00:00
if ( ( ctxt - > context - > node - > parent - > type = = XML_ELEMENT_NODE ) & &
2003-02-04 19:28:49 +00:00
( ( ctxt - > context - > node - > parent - > name [ 0 ] = = ' ' ) | |
( xmlStrEqual ( ctxt - > context - > node - > parent - > name ,
BAD_CAST " fake node libxslt " ) ) ) )
2003-01-10 17:06:09 +00:00
return ( NULL ) ;
2001-02-23 17:55:21 +00:00
return ( ctxt - > context - > node - > parent ) ;
case XML_ATTRIBUTE_NODE : {
xmlAttrPtr att = ( xmlAttrPtr ) ctxt - > context - > node ;
return ( att - > parent ) ;
}
case XML_DOCUMENT_NODE :
case XML_DOCUMENT_TYPE_NODE :
case XML_DOCUMENT_FRAG_NODE :
case XML_HTML_DOCUMENT_NODE :
2001-04-23 13:41:34 +00:00
# ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE :
2001-02-23 17:55:21 +00:00
# endif
return ( NULL ) ;
2002-03-04 17:09:44 +00:00
case XML_NAMESPACE_DECL : {
xmlNsPtr ns = ( xmlNsPtr ) ctxt - > context - > node ;
if ( ( ns - > next ! = NULL ) & &
( ns - > next - > type ! = XML_NAMESPACE_DECL ) )
return ( ( xmlNodePtr ) ns - > next ) ;
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
2002-03-04 17:09:44 +00:00
}
2001-02-23 17:55:21 +00:00
}
}
return ( NULL ) ;
}
/**
* xmlXPathNextAncestor :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " ancestor " direction
* the ancestor axis contains the ancestors of the context node ; the ancestors
* of the context node consist of the parent of context node and the parent ' s
* parent and so on ; the nodes are ordered in reverse document order ; thus the
* parent is the first node on the axis , and the parent ' s parent is the second
* node on the axis
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextAncestor ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
/*
* the parent of an attribute or namespace node is the element
* to which the attribute or namespace node is attached
* ! ! ! ! ! ! ! ! ! ! ! ! !
*/
if ( cur = = NULL ) {
if ( ctxt - > context - > node = = NULL ) return ( NULL ) ;
switch ( ctxt - > context - > node - > type ) {
case XML_ELEMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
case XML_ENTITY_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_DTD_NODE :
case XML_ELEMENT_DECL :
case XML_ATTRIBUTE_DECL :
case XML_ENTITY_DECL :
case XML_NOTATION_NODE :
case XML_XINCLUDE_START :
case XML_XINCLUDE_END :
if ( ctxt - > context - > node - > parent = = NULL )
return ( ( xmlNodePtr ) ctxt - > context - > doc ) ;
2003-01-10 17:06:09 +00:00
if ( ( ctxt - > context - > node - > parent - > type = = XML_ELEMENT_NODE ) & &
2003-02-04 19:28:49 +00:00
( ( ctxt - > context - > node - > parent - > name [ 0 ] = = ' ' ) | |
( xmlStrEqual ( ctxt - > context - > node - > parent - > name ,
BAD_CAST " fake node libxslt " ) ) ) )
2003-01-10 17:06:09 +00:00
return ( NULL ) ;
2001-02-23 17:55:21 +00:00
return ( ctxt - > context - > node - > parent ) ;
case XML_ATTRIBUTE_NODE : {
2001-03-24 17:00:36 +00:00
xmlAttrPtr tmp = ( xmlAttrPtr ) ctxt - > context - > node ;
2001-02-23 17:55:21 +00:00
2001-03-24 17:00:36 +00:00
return ( tmp - > parent ) ;
2001-02-23 17:55:21 +00:00
}
case XML_DOCUMENT_NODE :
case XML_DOCUMENT_TYPE_NODE :
case XML_DOCUMENT_FRAG_NODE :
case XML_HTML_DOCUMENT_NODE :
2001-04-23 13:41:34 +00:00
# ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE :
2001-02-23 17:55:21 +00:00
# endif
return ( NULL ) ;
2002-03-04 17:09:44 +00:00
case XML_NAMESPACE_DECL : {
xmlNsPtr ns = ( xmlNsPtr ) ctxt - > context - > node ;
if ( ( ns - > next ! = NULL ) & &
( ns - > next - > type ! = XML_NAMESPACE_DECL ) )
return ( ( xmlNodePtr ) ns - > next ) ;
/* Bad, how did that namespace ended-up there ? */
2001-02-23 17:55:21 +00:00
return ( NULL ) ;
2002-03-04 17:09:44 +00:00
}
2001-02-23 17:55:21 +00:00
}
return ( NULL ) ;
}
if ( cur = = ctxt - > context - > doc - > children )
return ( ( xmlNodePtr ) ctxt - > context - > doc ) ;
if ( cur = = ( xmlNodePtr ) ctxt - > context - > doc )
return ( NULL ) ;
switch ( cur - > type ) {
case XML_ELEMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
case XML_ENTITY_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_NOTATION_NODE :
case XML_DTD_NODE :
case XML_ELEMENT_DECL :
case XML_ATTRIBUTE_DECL :
case XML_ENTITY_DECL :
case XML_XINCLUDE_START :
case XML_XINCLUDE_END :
2003-01-10 17:06:09 +00:00
if ( cur - > parent = = NULL )
return ( NULL ) ;
if ( ( cur - > parent - > type = = XML_ELEMENT_NODE ) & &
2003-02-04 19:28:49 +00:00
( ( cur - > parent - > name [ 0 ] = = ' ' ) | |
( xmlStrEqual ( cur - > parent - > name ,
BAD_CAST " fake node libxslt " ) ) ) )
2003-01-10 17:06:09 +00:00
return ( NULL ) ;
2001-02-23 17:55:21 +00:00
return ( cur - > parent ) ;
case XML_ATTRIBUTE_NODE : {
xmlAttrPtr att = ( xmlAttrPtr ) ctxt - > context - > node ;
return ( att - > parent ) ;
}
2002-05-31 04:24:13 +00:00
case XML_NAMESPACE_DECL : {
xmlNsPtr ns = ( xmlNsPtr ) ctxt - > context - > node ;
if ( ( ns - > next ! = NULL ) & &
( ns - > next - > type ! = XML_NAMESPACE_DECL ) )
return ( ( xmlNodePtr ) ns - > next ) ;
/* Bad, how did that namespace ended-up there ? */
return ( NULL ) ;
}
2001-02-23 17:55:21 +00:00
case XML_DOCUMENT_NODE :
case XML_DOCUMENT_TYPE_NODE :
case XML_DOCUMENT_FRAG_NODE :
case XML_HTML_DOCUMENT_NODE :
2001-04-23 13:41:34 +00:00
# ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE :
2001-02-23 17:55:21 +00:00
# endif
return ( NULL ) ;
}
return ( NULL ) ;
}
/**
* xmlXPathNextAncestorOrSelf :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " ancestor-or-self " direction
* he ancestor - or - self axis contains the context node and ancestors of
* the context node in reverse document order ; thus the context node is
* the first node on the axis , and the context node ' s parent the second ;
* parent here is defined the same as with the parent axis .
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextAncestorOrSelf ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( cur = = NULL )
return ( ctxt - > context - > node ) ;
return ( xmlXPathNextAncestor ( ctxt , cur ) ) ;
}
/**
* xmlXPathNextFollowingSibling :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " following-sibling " direction
* The following - sibling axis contains the following siblings of the context
* node in document order .
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextFollowingSibling ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( ( ctxt - > context - > node - > type = = XML_ATTRIBUTE_NODE ) | |
( ctxt - > context - > node - > type = = XML_NAMESPACE_DECL ) )
return ( NULL ) ;
if ( cur = = ( xmlNodePtr ) ctxt - > context - > doc )
return ( NULL ) ;
if ( cur = = NULL )
return ( ctxt - > context - > node - > next ) ;
return ( cur - > next ) ;
}
/**
* xmlXPathNextPrecedingSibling :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " preceding-sibling " direction
* The preceding - sibling axis contains the preceding siblings of the context
* node in reverse document order ; the first preceding sibling is first on the
* axis ; the sibling preceding that node is the second on the axis and so on .
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextPrecedingSibling ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( ( ctxt - > context - > node - > type = = XML_ATTRIBUTE_NODE ) | |
( ctxt - > context - > node - > type = = XML_NAMESPACE_DECL ) )
return ( NULL ) ;
if ( cur = = ( xmlNodePtr ) ctxt - > context - > doc )
return ( NULL ) ;
if ( cur = = NULL )
return ( ctxt - > context - > node - > prev ) ;
2001-07-03 10:35:50 +00:00
if ( ( cur - > prev ! = NULL ) & & ( cur - > prev - > type = = XML_DTD_NODE ) ) {
cur = cur - > prev ;
if ( cur = = NULL )
return ( ctxt - > context - > node - > prev ) ;
}
2001-02-23 17:55:21 +00:00
return ( cur - > prev ) ;
}
/**
* xmlXPathNextFollowing :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " following " direction
* The following axis contains all nodes in the same document as the context
* node that are after the context node in document order , excluding any
* descendants and excluding attribute nodes and namespace nodes ; the nodes
* are ordered in document order
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextFollowing ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( cur ! = NULL & & cur - > children ! = NULL )
return cur - > children ;
if ( cur = = NULL ) cur = ctxt - > context - > node ;
if ( cur = = NULL ) return ( NULL ) ; /* ERROR */
if ( cur - > next ! = NULL ) return ( cur - > next ) ;
do {
cur = cur - > parent ;
if ( cur = = NULL ) return ( NULL ) ;
if ( cur = = ( xmlNodePtr ) ctxt - > context - > doc ) return ( NULL ) ;
if ( cur - > next ! = NULL ) return ( cur - > next ) ;
} while ( cur ! = NULL ) ;
return ( cur ) ;
}
/*
* xmlXPathIsAncestor :
* @ ancestor : the ancestor node
* @ node : the current node
*
* Check that @ ancestor is a @ node ' s ancestor
*
* returns 1 if @ ancestor is a @ node ' s ancestor , 0 otherwise .
*/
static int
xmlXPathIsAncestor ( xmlNodePtr ancestor , xmlNodePtr node ) {
if ( ( ancestor = = NULL ) | | ( node = = NULL ) ) return ( 0 ) ;
/* nodes need to be in the same document */
if ( ancestor - > doc ! = node - > doc ) return ( 0 ) ;
/* avoid searching if ancestor or node is the root node */
if ( ancestor = = ( xmlNodePtr ) node - > doc ) return ( 1 ) ;
if ( node = = ( xmlNodePtr ) ancestor - > doc ) return ( 0 ) ;
while ( node - > parent ! = NULL ) {
if ( node - > parent = = ancestor )
return ( 1 ) ;
node = node - > parent ;
}
return ( 0 ) ;
}
/**
* xmlXPathNextPreceding :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " preceding " direction
* the preceding axis contains all nodes in the same document as the context
* node that are before the context node in document order , excluding any
* ancestors and excluding attribute nodes and namespace nodes ; the nodes are
* ordered in reverse document order
*
* Returns the next element following that axis
*/
xmlNodePtr
2001-07-03 10:35:50 +00:00
xmlXPathNextPreceding ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur )
{
if ( cur = = NULL )
cur = ctxt - > context - > node ;
2001-02-23 17:55:21 +00:00
if ( cur = = NULL )
2001-07-03 10:35:50 +00:00
return ( NULL ) ;
if ( ( cur - > prev ! = NULL ) & & ( cur - > prev - > type = = XML_DTD_NODE ) )
cur = cur - > prev ;
2001-02-23 17:55:21 +00:00
do {
if ( cur - > prev ! = NULL ) {
2001-07-03 10:35:50 +00:00
for ( cur = cur - > prev ; cur - > last ! = NULL ; cur = cur - > last ) ;
return ( cur ) ;
2001-02-23 17:55:21 +00:00
}
cur = cur - > parent ;
2001-07-03 10:35:50 +00:00
if ( cur = = NULL )
return ( NULL ) ;
if ( cur = = ctxt - > context - > doc - > children )
return ( NULL ) ;
2001-02-23 17:55:21 +00:00
} while ( xmlXPathIsAncestor ( cur , ctxt - > context - > node ) ) ;
2001-07-03 10:35:50 +00:00
return ( cur ) ;
}
/**
* xmlXPathNextPrecedingInternal :
* @ ctxt : the XPath Parser context
* @ cur : the current node in the traversal
*
* Traversal function for the " preceding " direction
* the preceding axis contains all nodes in the same document as the context
* node that are before the context node in document order , excluding any
* ancestors and excluding attribute nodes and namespace nodes ; the nodes are
* ordered in reverse document order
* This is a faster implementation but internal only since it requires a
* state kept in the parser context : ctxt - > ancestor .
*
* Returns the next element following that axis
*/
static xmlNodePtr
xmlXPathNextPrecedingInternal ( xmlXPathParserContextPtr ctxt ,
xmlNodePtr cur )
{
if ( cur = = NULL ) {
cur = ctxt - > context - > node ;
if ( cur = = NULL )
return ( NULL ) ;
2003-10-10 03:58:39 +00:00
if ( cur - > type = = XML_NAMESPACE_DECL )
cur = ( xmlNodePtr ) ( ( xmlNsPtr ) cur ) - > next ;
2001-07-03 10:35:50 +00:00
ctxt - > ancestor = cur - > parent ;
}
if ( ( cur - > prev ! = NULL ) & & ( cur - > prev - > type = = XML_DTD_NODE ) )
cur = cur - > prev ;
while ( cur - > prev = = NULL ) {
cur = cur - > parent ;
if ( cur = = NULL )
return ( NULL ) ;
if ( cur = = ctxt - > context - > doc - > children )
return ( NULL ) ;
if ( cur ! = ctxt - > ancestor )
return ( cur ) ;
ctxt - > ancestor = cur - > parent ;
}
cur = cur - > prev ;
while ( cur - > last ! = NULL )
cur = cur - > last ;
return ( cur ) ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathNextNamespace :
* @ ctxt : the XPath Parser context
* @ cur : the current attribute in the traversal
*
* Traversal function for the " namespace " direction
* the namespace axis contains the namespace nodes of the context node ;
* the order of nodes on this axis is implementation - defined ; the axis will
* be empty unless the context node is an element
*
2001-10-05 09:18:14 +00:00
* We keep the XML namespace node at the end of the list .
*
2001-02-23 17:55:21 +00:00
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextNamespace ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
if ( ctxt - > context - > node - > type ! = XML_ELEMENT_NODE ) return ( NULL ) ;
2002-07-01 21:52:03 +00:00
if ( ctxt - > context - > tmpNsList = = NULL & & cur ! = ( xmlNodePtr ) xmlXPathXMLNamespace ) {
2001-07-30 13:42:13 +00:00
if ( ctxt - > context - > tmpNsList ! = NULL )
xmlFree ( ctxt - > context - > tmpNsList ) ;
ctxt - > context - > tmpNsList =
2001-02-23 17:55:21 +00:00
xmlGetNsList ( ctxt - > context - > doc , ctxt - > context - > node ) ;
2001-07-30 13:42:13 +00:00
ctxt - > context - > tmpNsNr = 0 ;
2002-07-01 21:52:03 +00:00
if ( ctxt - > context - > tmpNsList ! = NULL ) {
while ( ctxt - > context - > tmpNsList [ ctxt - > context - > tmpNsNr ] ! = NULL ) {
ctxt - > context - > tmpNsNr + + ;
}
}
return ( ( xmlNodePtr ) xmlXPathXMLNamespace ) ;
2001-07-30 13:42:13 +00:00
}
2002-07-01 21:52:03 +00:00
if ( ctxt - > context - > tmpNsNr > 0 ) {
return ( xmlNodePtr ) ctxt - > context - > tmpNsList [ - - ctxt - > context - > tmpNsNr ] ;
} else {
if ( ctxt - > context - > tmpNsList ! = NULL )
xmlFree ( ctxt - > context - > tmpNsList ) ;
2001-07-30 13:42:13 +00:00
ctxt - > context - > tmpNsList = NULL ;
2002-07-01 21:52:03 +00:00
return ( NULL ) ;
2001-02-23 17:55:21 +00:00
}
}
/**
* xmlXPathNextAttribute :
* @ ctxt : the XPath Parser context
* @ cur : the current attribute in the traversal
*
* Traversal function for the " attribute " direction
* TODO : support DTD inherited default attributes
*
* Returns the next element following that axis
*/
xmlNodePtr
xmlXPathNextAttribute ( xmlXPathParserContextPtr ctxt , xmlNodePtr cur ) {
2001-04-18 21:41:07 +00:00
if ( ctxt - > context - > node = = NULL )
return ( NULL ) ;
if ( ctxt - > context - > node - > type ! = XML_ELEMENT_NODE )
return ( NULL ) ;
2001-02-23 17:55:21 +00:00
if ( cur = = NULL ) {
if ( ctxt - > context - > node = = ( xmlNodePtr ) ctxt - > context - > doc )
return ( NULL ) ;
return ( ( xmlNodePtr ) ctxt - > context - > node - > properties ) ;
}
return ( ( xmlNodePtr ) cur - > next ) ;
}
/************************************************************************
* *
* NodeTest Functions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define IS_FUNCTION 200
2001-04-05 16:54:14 +00:00
/************************************************************************
* *
* Implicit tree core function library *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-02-23 17:55:21 +00:00
/**
2001-04-05 16:54:14 +00:00
* xmlXPathRoot :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
2001-04-05 16:54:14 +00:00
* Initialize the context to the root of the document
2001-02-23 17:55:21 +00:00
*/
2001-04-05 16:54:14 +00:00
void
xmlXPathRoot ( xmlXPathParserContextPtr ctxt ) {
ctxt - > context - > node = ( xmlNodePtr ) ctxt - > context - > doc ;
valuePush ( ctxt , xmlXPathNewNodeSet ( ctxt - > context - > node ) ) ;
}
2001-02-23 17:55:21 +00:00
2001-04-05 16:54:14 +00:00
/************************************************************************
* *
* The explicit core function library *
* http : //www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-02-23 17:55:21 +00:00
2001-04-05 16:54:14 +00:00
/**
* xmlXPathLastFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the last ( ) XPath function
* number last ( )
* The last function returns the number of nodes in the context node list .
*/
void
xmlXPathLastFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
CHECK_ARITY ( 0 ) ;
if ( ctxt - > context - > contextSize > = 0 ) {
valuePush ( ctxt , xmlXPathNewFloat ( ( double ) ctxt - > context - > contextSize ) ) ;
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext ,
" last() : %d \n " , ctxt - > context - > contextSize ) ;
2001-02-23 17:55:21 +00:00
# endif
2001-04-05 16:54:14 +00:00
} else {
XP_ERROR ( XPATH_INVALID_CTXT_SIZE ) ;
2001-02-23 17:55:21 +00:00
}
2001-04-05 16:54:14 +00:00
}
2001-02-23 17:55:21 +00:00
2001-04-05 16:54:14 +00:00
/**
* xmlXPathPositionFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the position ( ) XPath function
* number position ( )
* The position function returns the position of the context node in the
2001-12-31 16:16:02 +00:00
* context node list . The first position is 1 , and so the last position
2001-04-05 16:54:14 +00:00
* will be equal to last ( ) .
*/
void
xmlXPathPositionFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
CHECK_ARITY ( 0 ) ;
if ( ctxt - > context - > proximityPosition > = 0 ) {
valuePush ( ctxt ,
xmlXPathNewFloat ( ( double ) ctxt - > context - > proximityPosition ) ) ;
# ifdef DEBUG_EXPR
xmlGenericError ( xmlGenericErrorContext , " position() : %d \n " ,
ctxt - > context - > proximityPosition ) ;
2001-02-23 17:55:21 +00:00
# endif
2001-04-05 16:54:14 +00:00
} else {
XP_ERROR ( XPATH_INVALID_CTXT_POSITION ) ;
}
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathCountFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the count ( ) XPath function
* number count ( node - set )
*/
void
xmlXPathCountFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_NODESET ) & &
( ctxt - > value - > type ! = XPATH_XSLT_TREE ) ) )
XP_ERROR ( XPATH_INVALID_TYPE ) ;
cur = valuePop ( ctxt ) ;
2001-04-07 15:39:35 +00:00
if ( ( cur = = NULL ) | | ( cur - > nodesetval = = NULL ) )
valuePush ( ctxt , xmlXPathNewFloat ( ( double ) 0 ) ) ;
2002-07-12 00:56:01 +00:00
else if ( ( cur - > type = = XPATH_NODESET ) | | ( cur - > type = = XPATH_XSLT_TREE ) ) {
2001-04-07 15:39:35 +00:00
valuePush ( ctxt , xmlXPathNewFloat ( ( double ) cur - > nodesetval - > nodeNr ) ) ;
2001-08-14 12:18:09 +00:00
} else {
if ( ( cur - > nodesetval - > nodeNr ! = 1 ) | |
( cur - > nodesetval - > nodeTab = = NULL ) ) {
valuePush ( ctxt , xmlXPathNewFloat ( ( double ) 0 ) ) ;
} else {
xmlNodePtr tmp ;
int i = 0 ;
tmp = cur - > nodesetval - > nodeTab [ 0 ] ;
if ( tmp ! = NULL ) {
tmp = tmp - > children ;
while ( tmp ! = NULL ) {
tmp = tmp - > next ;
i + + ;
}
}
valuePush ( ctxt , xmlXPathNewFloat ( ( double ) i ) ) ;
}
}
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( cur ) ;
}
2001-05-15 09:43:47 +00:00
/**
* xmlXPathGetElementsByIds :
* @ doc : the document
* @ ids : a whitespace separated list of IDs
*
* Selects elements by their unique ID .
*
* Returns a node - set of selected elements .
*/
static xmlNodeSetPtr
xmlXPathGetElementsByIds ( xmlDocPtr doc , const xmlChar * ids ) {
xmlNodeSetPtr ret ;
const xmlChar * cur = ids ;
xmlChar * ID ;
xmlAttrPtr attr ;
xmlNodePtr elem = NULL ;
2003-07-06 17:57:42 +00:00
if ( ids = = NULL ) return ( NULL ) ;
2001-05-15 09:43:47 +00:00
ret = xmlXPathNodeSetCreate ( NULL ) ;
2003-10-18 16:20:14 +00:00
while ( IS_BLANK_CH ( * cur ) ) cur + + ;
2001-05-15 09:43:47 +00:00
while ( * cur ! = 0 ) {
2003-10-18 16:20:14 +00:00
while ( ( ! IS_BLANK_CH ( * cur ) ) & & ( * cur ! = 0 ) )
2003-03-26 21:40:13 +00:00
cur + + ;
2001-05-15 09:43:47 +00:00
ID = xmlStrndup ( ids , cur - ids ) ;
2003-03-26 21:40:13 +00:00
if ( ID ! = NULL ) {
if ( xmlValidateNCName ( ID , 1 ) = = 0 ) {
attr = xmlGetID ( doc , ID ) ;
if ( attr ! = NULL ) {
if ( attr - > type = = XML_ATTRIBUTE_NODE )
elem = attr - > parent ;
else if ( attr - > type = = XML_ELEMENT_NODE )
elem = ( xmlNodePtr ) attr ;
else
elem = NULL ;
if ( elem ! = NULL )
xmlXPathNodeSetAdd ( ret , elem ) ;
}
}
2001-05-15 09:43:47 +00:00
xmlFree ( ID ) ;
2003-03-26 21:40:13 +00:00
}
2001-05-15 09:43:47 +00:00
2003-10-18 16:20:14 +00:00
while ( IS_BLANK_CH ( * cur ) ) cur + + ;
2001-05-15 09:43:47 +00:00
ids = cur ;
}
return ( ret ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathIdFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the id ( ) XPath function
* node - set id ( object )
* 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 ,
* then the result is the union of the result of applying id to the
* string value of each of the nodes in the argument node - set . When the
* argument to id is of any other type , the argument is converted to a
* string as if by a call to the string function ; the string is split
* into a whitespace - separated list of tokens ( whitespace is any sequence
* of characters matching the production S ) ; the result is a node - set
* containing the elements in the same document as the context node that
* have a unique ID equal to any of the tokens in the list .
*/
void
xmlXPathIdFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2001-05-15 09:43:47 +00:00
xmlChar * tokens ;
xmlNodeSetPtr ret ;
xmlXPathObjectPtr obj ;
2001-02-23 17:55:21 +00:00
CHECK_ARITY ( 1 ) ;
obj = valuePop ( ctxt ) ;
if ( obj = = NULL ) XP_ERROR ( XPATH_INVALID_OPERAND ) ;
2002-07-12 00:56:01 +00:00
if ( ( obj - > type = = XPATH_NODESET ) | | ( obj - > type = = XPATH_XSLT_TREE ) ) {
2001-05-15 09:43:47 +00:00
xmlNodeSetPtr ns ;
2001-02-23 17:55:21 +00:00
int i ;
2001-05-15 09:43:47 +00:00
ret = xmlXPathNodeSetCreate ( NULL ) ;
2001-02-23 17:55:21 +00:00
2001-04-07 15:39:35 +00:00
if ( obj - > nodesetval ! = NULL ) {
for ( i = 0 ; i < obj - > nodesetval - > nodeNr ; i + + ) {
2001-05-15 09:43:47 +00:00
tokens =
xmlXPathCastNodeToString ( obj - > nodesetval - > nodeTab [ i ] ) ;
ns = xmlXPathGetElementsByIds ( ctxt - > context - > doc , tokens ) ;
ret = xmlXPathNodeSetMerge ( ret , ns ) ;
xmlXPathFreeNodeSet ( ns ) ;
if ( tokens ! = NULL )
xmlFree ( tokens ) ;
2001-04-07 15:39:35 +00:00
}
2001-02-23 17:55:21 +00:00
}
xmlXPathFreeObject ( obj ) ;
2001-05-15 09:43:47 +00:00
valuePush ( ctxt , xmlXPathWrapNodeSet ( ret ) ) ;
2001-02-23 17:55:21 +00:00
return ;
}
2001-05-15 09:43:47 +00:00
obj = xmlXPathConvertString ( obj ) ;
2001-02-23 17:55:21 +00:00
2001-05-15 09:43:47 +00:00
ret = xmlXPathGetElementsByIds ( ctxt - > context - > doc , obj - > stringval ) ;
valuePush ( ctxt , xmlXPathWrapNodeSet ( ret ) ) ;
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( obj ) ;
return ;
}
/**
* xmlXPathLocalNameFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the local - name ( ) XPath function
* string local - name ( node - set ? )
* 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
* document order . If the node - set is empty or the first node has no
* name , an empty string is returned . If the argument is omitted it
* defaults to the context node .
*/
void
xmlXPathLocalNameFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
if ( nargs = = 0 ) {
valuePush ( ctxt , xmlXPathNewNodeSet ( ctxt - > context - > node ) ) ;
nargs = 1 ;
}
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_NODESET ) & &
( ctxt - > value - > type ! = XPATH_XSLT_TREE ) ) )
XP_ERROR ( XPATH_INVALID_TYPE ) ;
cur = valuePop ( ctxt ) ;
2001-04-07 15:39:35 +00:00
if ( ( cur - > nodesetval = = NULL ) | | ( cur - > nodesetval - > nodeNr = = 0 ) ) {
2001-02-23 17:55:21 +00:00
valuePush ( ctxt , xmlXPathNewCString ( " " ) ) ;
} else {
int i = 0 ; /* Should be first in document order !!!!! */
switch ( cur - > nodesetval - > nodeTab [ i ] - > type ) {
case XML_ELEMENT_NODE :
case XML_ATTRIBUTE_NODE :
case XML_PI_NODE :
2003-02-04 19:28:49 +00:00
if ( cur - > nodesetval - > nodeTab [ i ] - > name [ 0 ] = = ' ' )
valuePush ( ctxt , xmlXPathNewCString ( " " ) ) ;
else
valuePush ( ctxt ,
2001-02-23 17:55:21 +00:00
xmlXPathNewString ( cur - > nodesetval - > nodeTab [ i ] - > name ) ) ;
break ;
case XML_NAMESPACE_DECL :
valuePush ( ctxt , xmlXPathNewString (
( ( xmlNsPtr ) cur - > nodesetval - > nodeTab [ i ] ) - > prefix ) ) ;
break ;
default :
valuePush ( ctxt , xmlXPathNewCString ( " " ) ) ;
}
}
xmlXPathFreeObject ( cur ) ;
}
/**
* xmlXPathNamespaceURIFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the namespace - uri ( ) XPath function
* string namespace - uri ( node - set ? )
* The namespace - uri function returns a string containing the
* 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 ,
* the first node has no name , or the expanded name has no namespace
* URI , an empty string is returned . If the argument is omitted it
* defaults to the context node .
*/
void
xmlXPathNamespaceURIFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
if ( nargs = = 0 ) {
valuePush ( ctxt , xmlXPathNewNodeSet ( ctxt - > context - > node ) ) ;
nargs = 1 ;
}
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_NODESET ) & &
( ctxt - > value - > type ! = XPATH_XSLT_TREE ) ) )
XP_ERROR ( XPATH_INVALID_TYPE ) ;
cur = valuePop ( ctxt ) ;
2001-04-07 15:39:35 +00:00
if ( ( cur - > nodesetval = = NULL ) | | ( cur - > nodesetval - > nodeNr = = 0 ) ) {
2001-02-23 17:55:21 +00:00
valuePush ( ctxt , xmlXPathNewCString ( " " ) ) ;
} else {
int i = 0 ; /* Should be first in document order !!!!! */
switch ( cur - > nodesetval - > nodeTab [ i ] - > type ) {
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 ( " " ) ) ;
}
}
xmlXPathFreeObject ( cur ) ;
}
/**
* xmlXPathNameFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the name ( ) XPath function
* string name ( node - set ? )
* The name function returns a string containing a QName representing
2001-12-31 16:16:02 +00:00
* the name of the node in the argument node - set that is first in document
2001-02-23 17:55:21 +00:00
* order . The QName must represent the name with respect to the namespace
* declarations in effect on the node whose name is being represented .
* Typically , this will be the form in which the name occurred in the XML
* source . This need not be the case if there are namespace declarations
* in effect on the node that associate multiple prefixes with the same
* namespace . However , an implementation may include information about
* the original prefix in its representation of nodes ; in this case , an
* implementation can ensure that the returned string is always the same
* as the QName used in the XML source . If the argument it omitted it
* defaults to the context node .
* Libxml keep the original prefix so the " real qualified name " used is
* returned .
*/
2001-03-24 17:00:36 +00:00
static void
2001-07-08 14:27:15 +00:00
xmlXPathNameFunction ( xmlXPathParserContextPtr ctxt , int nargs )
{
2001-02-23 17:55:21 +00:00
xmlXPathObjectPtr cur ;
if ( nargs = = 0 ) {
2001-07-08 14:27:15 +00:00
valuePush ( ctxt , xmlXPathNewNodeSet ( ctxt - > context - > node ) ) ;
nargs = 1 ;
2001-02-23 17:55:21 +00:00
}
CHECK_ARITY ( 1 ) ;
2001-07-08 14:27:15 +00:00
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_NODESET ) & &
( ctxt - > value - > type ! = XPATH_XSLT_TREE ) ) )
XP_ERROR ( XPATH_INVALID_TYPE ) ;
2001-02-23 17:55:21 +00:00
cur = valuePop ( ctxt ) ;
2001-04-07 15:39:35 +00:00
if ( ( cur - > nodesetval = = NULL ) | | ( cur - > nodesetval - > nodeNr = = 0 ) ) {
2001-07-08 14:27:15 +00:00
valuePush ( ctxt , xmlXPathNewCString ( " " ) ) ;
2001-02-23 17:55:21 +00:00
} else {
2001-07-08 14:27:15 +00:00
int i = 0 ; /* Should be first in document order !!!!! */
2001-02-23 17:55:21 +00:00
2001-07-08 14:27:15 +00:00
switch ( cur - > nodesetval - > nodeTab [ i ] - > type ) {
case XML_ELEMENT_NODE :
case XML_ATTRIBUTE_NODE :
2003-02-04 19:28:49 +00:00
if ( cur - > nodesetval - > nodeTab [ i ] - > name [ 0 ] = = ' ' )
valuePush ( ctxt , xmlXPathNewCString ( " " ) ) ;
else if ( ( cur - > nodesetval - > nodeTab [ i ] - > ns = = NULL ) | |
( cur - > nodesetval - > nodeTab [ i ] - > ns - > prefix = = NULL ) ) {
2001-07-08 14:27:15 +00:00
valuePush ( ctxt ,
2003-04-07 10:22:39 +00:00
xmlXPathNewString ( cur - > nodesetval - > nodeTab [ i ] - > name ) ) ;
2001-07-08 14:27:15 +00:00
2003-02-04 19:28:49 +00:00
} else {
2003-04-07 10:22:39 +00:00
xmlChar * fullname ;
fullname = xmlBuildQName ( cur - > nodesetval - > nodeTab [ i ] - > name ,
cur - > nodesetval - > nodeTab [ i ] - > ns - > prefix ,
NULL , 0 ) ;
if ( fullname = = cur - > nodesetval - > nodeTab [ i ] - > name )
fullname = xmlStrdup ( cur - > nodesetval - > nodeTab [ i ] - > name ) ;
if ( fullname = = NULL ) {
XP_ERROR ( XPATH_MEMORY_ERROR ) ;
}
valuePush ( ctxt , xmlXPathWrapString ( fullname ) ) ;
2001-07-08 14:27:15 +00:00
}
break ;
default :
valuePush ( ctxt ,
xmlXPathNewNodeSet ( cur - > nodesetval - > nodeTab [ i ] ) ) ;
xmlXPathLocalNameFunction ( ctxt , 1 ) ;
}
2001-02-23 17:55:21 +00:00
}
xmlXPathFreeObject ( cur ) ;
}
2001-03-19 15:58:54 +00:00
2001-02-23 17:55:21 +00:00
/**
* xmlXPathStringFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the string ( ) XPath function
* string string ( object ? )
* he string function converts an object to a string as follows :
* - 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 .
* If the node - set is empty , an empty string is returned .
* - A number is converted to a string as follows
* + NaN is converted to the string NaN
* + positive zero is converted to the string 0
* + negative zero is converted to the string 0
* + positive infinity is converted to the string Infinity
* + negative infinity is converted to the string - Infinity
* + if the number is an integer , the number is represented in
* decimal form as a Number with no decimal point and no leading
* zeros , preceded by a minus sign ( - ) if the number is negative
* + otherwise , the number is represented in decimal form as a
* Number including a decimal point with at least one digit
* before the decimal point and at least one digit after the
* decimal point , preceded by a minus sign ( - ) if the number
* is negative ; there must be no leading zeros before the decimal
2001-12-31 16:16:02 +00:00
* point apart possibly from the one required digit immediately
2001-02-23 17:55:21 +00:00
* before the decimal point ; beyond the one required digit
* after the decimal point there must be as many , but only as
* many , more digits as are needed to uniquely distinguish the
* number from all other IEEE 754 numeric values .
* - The boolean false value is converted to the string false .
* The boolean true value is converted to the string true .
*
* If the argument is omitted , it defaults to a node - set with the
* context node as its only member .
*/
void
xmlXPathStringFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
if ( nargs = = 0 ) {
2001-05-15 09:43:47 +00:00
valuePush ( ctxt ,
xmlXPathWrapString (
xmlXPathCastNodeToString ( ctxt - > context - > node ) ) ) ;
return ;
2001-02-23 17:55:21 +00:00
}
CHECK_ARITY ( 1 ) ;
cur = valuePop ( ctxt ) ;
if ( cur = = NULL ) XP_ERROR ( XPATH_INVALID_OPERAND ) ;
2001-03-19 15:58:54 +00:00
cur = xmlXPathConvertString ( cur ) ;
valuePush ( ctxt , cur ) ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathStringLengthFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the string - length ( ) XPath function
* number string - length ( string ? )
* The string - length returns the number of characters in the string
* ( see [ 3.6 Strings ] ) . If the argument is omitted , it defaults to
* the context node converted to a string , in other words the value
* of the context node .
*/
void
xmlXPathStringLengthFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
if ( nargs = = 0 ) {
if ( ctxt - > context - > node = = NULL ) {
valuePush ( ctxt , xmlXPathNewFloat ( 0 ) ) ;
} else {
xmlChar * content ;
2001-05-15 09:43:47 +00:00
content = xmlXPathCastNodeToString ( ctxt - > context - > node ) ;
2001-04-16 14:08:07 +00:00
valuePush ( ctxt , xmlXPathNewFloat ( xmlUTF8Strlen ( content ) ) ) ;
2001-02-23 17:55:21 +00:00
xmlFree ( content ) ;
}
return ;
}
CHECK_ARITY ( 1 ) ;
CAST_TO_STRING ;
CHECK_TYPE ( XPATH_STRING ) ;
cur = valuePop ( ctxt ) ;
2001-04-16 14:08:07 +00:00
valuePush ( ctxt , xmlXPathNewFloat ( xmlUTF8Strlen ( cur - > stringval ) ) ) ;
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( cur ) ;
}
/**
* xmlXPathConcatFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the concat ( ) XPath function
* string concat ( string , string , string * )
* The concat function returns the concatenation of its arguments .
*/
void
xmlXPathConcatFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur , newobj ;
xmlChar * tmp ;
if ( nargs < 2 ) {
CHECK_ARITY ( 2 ) ;
}
CAST_TO_STRING ;
cur = valuePop ( ctxt ) ;
if ( ( cur = = NULL ) | | ( cur - > type ! = XPATH_STRING ) ) {
xmlXPathFreeObject ( cur ) ;
return ;
}
nargs - - ;
while ( nargs > 0 ) {
CAST_TO_STRING ;
newobj = valuePop ( ctxt ) ;
if ( ( newobj = = NULL ) | | ( newobj - > type ! = XPATH_STRING ) ) {
xmlXPathFreeObject ( newobj ) ;
xmlXPathFreeObject ( cur ) ;
XP_ERROR ( XPATH_INVALID_TYPE ) ;
}
tmp = xmlStrcat ( newobj - > stringval , cur - > stringval ) ;
newobj - > stringval = cur - > stringval ;
cur - > stringval = tmp ;
xmlXPathFreeObject ( newobj ) ;
nargs - - ;
}
valuePush ( ctxt , cur ) ;
}
/**
* xmlXPathContainsFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the contains ( ) XPath function
* boolean contains ( string , string )
* The contains function returns true if the first argument string
* contains the second argument string , and otherwise returns false .
*/
void
xmlXPathContainsFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr hay , needle ;
CHECK_ARITY ( 2 ) ;
CAST_TO_STRING ;
CHECK_TYPE ( XPATH_STRING ) ;
needle = valuePop ( ctxt ) ;
CAST_TO_STRING ;
hay = valuePop ( ctxt ) ;
if ( ( hay = = NULL ) | | ( hay - > type ! = XPATH_STRING ) ) {
xmlXPathFreeObject ( hay ) ;
xmlXPathFreeObject ( needle ) ;
XP_ERROR ( XPATH_INVALID_TYPE ) ;
}
if ( xmlStrstr ( hay - > stringval , needle - > stringval ) )
valuePush ( ctxt , xmlXPathNewBoolean ( 1 ) ) ;
else
valuePush ( ctxt , xmlXPathNewBoolean ( 0 ) ) ;
xmlXPathFreeObject ( hay ) ;
xmlXPathFreeObject ( needle ) ;
}
/**
* xmlXPathStartsWithFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the starts - with ( ) XPath function
* boolean starts - with ( string , string )
* The starts - with function returns true if the first argument string
* starts with the second argument string , and otherwise returns false .
*/
void
xmlXPathStartsWithFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr hay , needle ;
int n ;
CHECK_ARITY ( 2 ) ;
CAST_TO_STRING ;
CHECK_TYPE ( XPATH_STRING ) ;
needle = valuePop ( ctxt ) ;
CAST_TO_STRING ;
hay = valuePop ( ctxt ) ;
if ( ( hay = = NULL ) | | ( hay - > type ! = XPATH_STRING ) ) {
xmlXPathFreeObject ( hay ) ;
xmlXPathFreeObject ( needle ) ;
XP_ERROR ( XPATH_INVALID_TYPE ) ;
}
n = xmlStrlen ( needle - > stringval ) ;
if ( xmlStrncmp ( hay - > stringval , needle - > stringval , n ) )
valuePush ( ctxt , xmlXPathNewBoolean ( 0 ) ) ;
else
valuePush ( ctxt , xmlXPathNewBoolean ( 1 ) ) ;
xmlXPathFreeObject ( hay ) ;
xmlXPathFreeObject ( needle ) ;
}
/**
* xmlXPathSubstringFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the substring ( ) XPath function
* string substring ( string , number , number ? )
* The substring function returns the substring of the first argument
* starting at the position specified in the second argument with
* length specified in the third argument . For example ,
* substring ( " 12345 " , 2 , 3 ) returns " 234 " . If the third argument is not
* specified , it returns the substring starting at the position specified
* in the second argument and continuing to the end of the string . For
* example , substring ( " 12345 " , 2 ) returns " 2345 " . More precisely , each
* character in the string ( see [ 3.6 Strings ] ) is considered to have a
* numeric position : the position of the first character is 1 , the position
* of the second character is 2 and so on . The returned substring contains
* those characters for which the position of the character is greater than
* or equal to the second argument and , if the third argument is specified ,
* less than the sum of the second and third arguments ; the comparisons
* and addition used for the above follow the standard IEEE 754 rules . Thus :
* - substring ( " 12345 " , 1.5 , 2.6 ) returns " 234 "
* - substring ( " 12345 " , 0 , 3 ) returns " 12 "
* - substring ( " 12345 " , 0 div 0 , 3 ) returns " "
* - substring ( " 12345 " , 1 , 0 div 0 ) returns " "
* - substring ( " 12345 " , - 42 , 1 div 0 ) returns " 12345 "
* - substring ( " 12345 " , - 1 div 0 , 1 div 0 ) returns " "
*/
void
xmlXPathSubstringFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr str , start , len ;
2001-05-30 19:14:17 +00:00
double le = 0 , in ;
int i , l , m ;
2001-02-23 17:55:21 +00:00
xmlChar * ret ;
if ( nargs < 2 ) {
CHECK_ARITY ( 2 ) ;
}
if ( nargs > 3 ) {
CHECK_ARITY ( 3 ) ;
}
2001-05-30 19:14:17 +00:00
/*
* take care of possible last ( position ) argument
*/
2001-02-23 17:55:21 +00:00
if ( nargs = = 3 ) {
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
len = valuePop ( ctxt ) ;
le = len - > floatval ;
xmlXPathFreeObject ( len ) ;
}
2001-05-30 19:14:17 +00:00
2001-02-23 17:55:21 +00:00
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
start = valuePop ( ctxt ) ;
in = start - > floatval ;
xmlXPathFreeObject ( start ) ;
CAST_TO_STRING ;
CHECK_TYPE ( XPATH_STRING ) ;
str = valuePop ( ctxt ) ;
2001-05-30 19:14:17 +00:00
m = xmlUTF8Strlen ( ( const unsigned char * ) str - > stringval ) ;
/*
* If last pos not present , calculate last position
*/
2002-06-10 15:59:44 +00:00
if ( nargs ! = 3 ) {
le = ( double ) m ;
if ( in < 1.0 )
in = 1.0 ;
}
2001-05-30 19:14:17 +00:00
2002-04-10 16:14:34 +00:00
/* Need to check for the special cases where either
* the index is NaN , the length is NaN , or both
* arguments are infinity ( relying on Inf + - Inf = NaN )
2001-05-30 19:14:17 +00:00
*/
2002-06-10 15:59:44 +00:00
if ( ! xmlXPathIsNaN ( in + le ) & & ! xmlXPathIsInf ( in ) ) {
2002-04-10 16:14:34 +00:00
/*
2002-06-10 15:59:44 +00:00
* To meet the requirements of the spec , the arguments
* must be converted to integer format before
* initial index calculations are done
2002-04-10 16:14:34 +00:00
*
2002-06-10 15:59:44 +00:00
* First we go to integer form , rounding up
* and checking for special cases
2002-04-10 16:14:34 +00:00
*/
i = ( int ) in ;
2002-06-10 15:59:44 +00:00
if ( ( ( double ) i ) + 0.5 < = in ) i + + ;
if ( xmlXPathIsInf ( le ) = = 1 ) {
l = m ;
if ( i < 1 )
i = 1 ;
}
else if ( xmlXPathIsInf ( le ) = = - 1 | | le < 0.0 )
l = 0 ;
else {
l = ( int ) le ;
if ( ( ( double ) l ) + 0.5 < = le ) l + + ;
}
2002-04-10 16:14:34 +00:00
2002-06-10 15:59:44 +00:00
/* Now we normalize inidices */
i - = 1 ;
l + = i ;
if ( i < 0 )
i = 0 ;
if ( l > m )
l = m ;
2001-02-23 17:55:21 +00:00
2002-04-10 16:14:34 +00:00
/* number of chars to copy */
l - = i ;
2001-02-23 17:55:21 +00:00
2002-04-10 16:14:34 +00:00
ret = xmlUTF8Strsub ( str - > stringval , i , l ) ;
}
else {
ret = NULL ;
}
2001-02-23 17:55:21 +00:00
if ( ret = = NULL )
valuePush ( ctxt , xmlXPathNewCString ( " " ) ) ;
else {
valuePush ( ctxt , xmlXPathNewString ( ret ) ) ;
xmlFree ( ret ) ;
}
2001-05-30 19:14:17 +00:00
2001-02-23 17:55:21 +00:00
xmlXPathFreeObject ( str ) ;
}
/**
* xmlXPathSubstringBeforeFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the substring - before ( ) XPath function
* string substring - before ( string , string )
* The substring - before function returns the substring of the first
* argument string that precedes the first occurrence of the second
* argument string in the first argument string , or the empty string
* if the first argument string does not contain the second argument
* string . For example , substring - before ( " 1999/04/01 " , " / " ) returns 1999.
*/
void
xmlXPathSubstringBeforeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr str ;
xmlXPathObjectPtr find ;
xmlBufferPtr target ;
const xmlChar * point ;
int offset ;
CHECK_ARITY ( 2 ) ;
CAST_TO_STRING ;
find = valuePop ( ctxt ) ;
CAST_TO_STRING ;
str = valuePop ( ctxt ) ;
target = xmlBufferCreate ( ) ;
if ( target ) {
point = xmlStrstr ( str - > stringval , find - > stringval ) ;
if ( point ) {
offset = ( int ) ( point - str - > stringval ) ;
xmlBufferAdd ( target , str - > stringval , offset ) ;
}
valuePush ( ctxt , xmlXPathNewString ( xmlBufferContent ( target ) ) ) ;
xmlBufferFree ( target ) ;
}
xmlXPathFreeObject ( str ) ;
xmlXPathFreeObject ( find ) ;
}
/**
* xmlXPathSubstringAfterFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the substring - after ( ) XPath function
* string substring - after ( string , string )
* The substring - after function returns the substring of the first
* argument string that follows the first occurrence of the second
* argument string in the first argument string , or the empty stringi
* if the first argument string does not contain the second argument
* string . For example , substring - after ( " 1999/04/01 " , " / " ) returns 04 / 01 ,
* and substring - after ( " 1999/04/01 " , " 19 " ) returns 99 / 04 / 01.
*/
void
xmlXPathSubstringAfterFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr str ;
xmlXPathObjectPtr find ;
xmlBufferPtr target ;
const xmlChar * point ;
int offset ;
CHECK_ARITY ( 2 ) ;
CAST_TO_STRING ;
find = valuePop ( ctxt ) ;
CAST_TO_STRING ;
str = valuePop ( ctxt ) ;
target = xmlBufferCreate ( ) ;
if ( target ) {
point = xmlStrstr ( str - > stringval , find - > stringval ) ;
if ( point ) {
offset = ( int ) ( point - str - > stringval ) + xmlStrlen ( find - > stringval ) ;
xmlBufferAdd ( target , & str - > stringval [ offset ] ,
xmlStrlen ( str - > stringval ) - offset ) ;
}
valuePush ( ctxt , xmlXPathNewString ( xmlBufferContent ( target ) ) ) ;
xmlBufferFree ( target ) ;
}
xmlXPathFreeObject ( str ) ;
xmlXPathFreeObject ( find ) ;
}
/**
* xmlXPathNormalizeFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the normalize - space ( ) XPath function
* string normalize - space ( string ? )
* The normalize - space function returns the argument string with white
* space normalized by stripping leading and trailing whitespace
* and replacing sequences of whitespace characters by a single
* space . Whitespace characters are the same allowed by the S production
* in XML . If the argument is omitted , it defaults to the context
* node converted to a string , in other words the value of the context node .
*/
void
xmlXPathNormalizeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr obj = NULL ;
xmlChar * source = NULL ;
xmlBufferPtr target ;
xmlChar blank ;
if ( nargs = = 0 ) {
/* Use current context node */
2001-05-15 09:43:47 +00:00
valuePush ( ctxt ,
xmlXPathWrapString (
xmlXPathCastNodeToString ( ctxt - > context - > node ) ) ) ;
2001-02-23 17:55:21 +00:00
nargs = 1 ;
}
CHECK_ARITY ( 1 ) ;
CAST_TO_STRING ;
CHECK_TYPE ( XPATH_STRING ) ;
obj = valuePop ( ctxt ) ;
source = obj - > stringval ;
target = xmlBufferCreate ( ) ;
if ( target & & source ) {
/* Skip leading whitespaces */
2003-10-18 16:20:14 +00:00
while ( IS_BLANK_CH ( * source ) )
2001-02-23 17:55:21 +00:00
source + + ;
/* Collapse intermediate whitespaces, and skip trailing whitespaces */
blank = 0 ;
while ( * source ) {
2003-10-18 16:20:14 +00:00
if ( IS_BLANK_CH ( * source ) ) {
2001-05-30 19:14:17 +00:00
blank = 0x20 ;
2001-02-23 17:55:21 +00:00
} else {
if ( blank ) {
xmlBufferAdd ( target , & blank , 1 ) ;
blank = 0 ;
}
xmlBufferAdd ( target , source , 1 ) ;
}
source + + ;
}
valuePush ( ctxt , xmlXPathNewString ( xmlBufferContent ( target ) ) ) ;
xmlBufferFree ( target ) ;
}
xmlXPathFreeObject ( obj ) ;
}
/**
* xmlXPathTranslateFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the translate ( ) XPath function
* string translate ( string , string , string )
* The translate function returns the first argument string with
* occurrences of characters in the second argument string replaced
* by the character at the corresponding position in the third argument
* string . For example , translate ( " bar " , " abc " , " ABC " ) returns the string
* BAr . If there is a character in the second argument string with no
* character at a corresponding position in the third argument string
* ( because the second argument string is longer than the third argument
* string ) , then occurrences of that character in the first argument
* string are removed . For example , translate ( " --aaa-- " , " abc- " , " ABC " )
* returns " AAA " . If a character occurs more than once in second
* argument string , then the first occurrence determines the replacement
* character . If the third argument string is longer than the second
* argument string , then excess characters are ignored .
*/
void
xmlXPathTranslateFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2001-04-16 14:08:07 +00:00
xmlXPathObjectPtr str ;
xmlXPathObjectPtr from ;
xmlXPathObjectPtr to ;
xmlBufferPtr target ;
2001-05-30 19:14:17 +00:00
int offset , max ;
2001-04-16 14:08:07 +00:00
xmlChar ch ;
2001-05-30 19:14:17 +00:00
xmlChar * point ;
xmlChar * cptr ;
2001-02-23 17:55:21 +00:00
2001-04-16 14:08:07 +00:00
CHECK_ARITY ( 3 ) ;
2001-02-23 17:55:21 +00:00
2001-04-16 14:08:07 +00:00
CAST_TO_STRING ;
to = valuePop ( ctxt ) ;
CAST_TO_STRING ;
from = valuePop ( ctxt ) ;
CAST_TO_STRING ;
str = valuePop ( ctxt ) ;
2001-02-23 17:55:21 +00:00
2001-04-16 14:08:07 +00:00
target = xmlBufferCreate ( ) ;
if ( target ) {
2001-05-30 19:14:17 +00:00
max = xmlUTF8Strlen ( to - > stringval ) ;
for ( cptr = str - > stringval ; ( ch = * cptr ) ; ) {
offset = xmlUTF8Strloc ( from - > stringval , cptr ) ;
if ( offset > = 0 ) {
if ( offset < max ) {
point = xmlUTF8Strpos ( to - > stringval , offset ) ;
if ( point )
xmlBufferAdd ( target , point , xmlUTF8Strsize ( point , 1 ) ) ;
}
} else
xmlBufferAdd ( target , cptr , xmlUTF8Strsize ( cptr , 1 ) ) ;
/* Step to next character in input */
cptr + + ;
if ( ch & 0x80 ) {
/* if not simple ascii, verify proper format */
if ( ( ch & 0xc0 ) ! = 0xc0 ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathTranslateFunction: Invalid UTF8 string \n " ) ;
break ;
}
/* then skip over remaining bytes for this char */
while ( ( ch < < = 1 ) & 0x80 )
if ( ( * cptr + + & 0xc0 ) ! = 0x80 ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathTranslateFunction: Invalid UTF8 string \n " ) ;
break ;
}
if ( ch & 0x80 ) /* must have had error encountered */
break ;
}
2001-04-16 14:08:07 +00:00
}
2001-02-23 17:55:21 +00:00
}
2001-04-16 14:08:07 +00:00
valuePush ( ctxt , xmlXPathNewString ( xmlBufferContent ( target ) ) ) ;
xmlBufferFree ( target ) ;
xmlXPathFreeObject ( str ) ;
xmlXPathFreeObject ( from ) ;
xmlXPathFreeObject ( to ) ;
2001-02-23 17:55:21 +00:00
}
2001-03-19 15:58:54 +00:00
/**
* xmlXPathBooleanFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the boolean ( ) XPath function
* boolean boolean ( object )
* he boolean function converts its argument to a boolean as follows :
* - a number is true if and only if it is neither positive or
* negative zero nor NaN
* - a node - set is true if and only if it is non - empty
* - a string is true if and only if its length is non - zero
*/
void
xmlXPathBooleanFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
CHECK_ARITY ( 1 ) ;
cur = valuePop ( ctxt ) ;
if ( cur = = NULL ) XP_ERROR ( XPATH_INVALID_OPERAND ) ;
cur = xmlXPathConvertBoolean ( cur ) ;
valuePush ( ctxt , cur ) ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathNotFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the not ( ) XPath function
* boolean not ( boolean )
* The not function returns true if its argument is false ,
* and false otherwise .
*/
void
xmlXPathNotFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
CHECK_ARITY ( 1 ) ;
CAST_TO_BOOLEAN ;
CHECK_TYPE ( XPATH_BOOLEAN ) ;
ctxt - > value - > boolval = ! ctxt - > value - > boolval ;
}
/**
* xmlXPathTrueFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the true ( ) XPath function
* boolean true ( )
*/
void
xmlXPathTrueFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
CHECK_ARITY ( 0 ) ;
valuePush ( ctxt , xmlXPathNewBoolean ( 1 ) ) ;
}
/**
* xmlXPathFalseFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the false ( ) XPath function
* boolean false ( )
*/
void
xmlXPathFalseFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
CHECK_ARITY ( 0 ) ;
valuePush ( ctxt , xmlXPathNewBoolean ( 0 ) ) ;
}
/**
* xmlXPathLangFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the lang ( ) XPath function
* boolean lang ( string )
* The lang function returns true or false depending on whether the
* language of the context node as specified by xml : lang attributes
* is the same as or is a sublanguage of the language specified by
* the argument string . The language of the context node is determined
* by the value of the xml : lang attribute on the context node , or , if
* the context node has no xml : lang attribute , by the value of the
* xml : lang attribute on the nearest ancestor of the context node that
* has an xml : lang attribute . If there is no such attribute , then lang
* returns false . If there is such an attribute , then lang returns
* true if the attribute value is equal to the argument ignoring case ,
* or if there is some suffix starting with - such that the attribute
* value is equal to the argument ignoring that suffix of the attribute
* value and ignoring case .
*/
void
xmlXPathLangFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr val ;
const xmlChar * theLang ;
const xmlChar * lang ;
int ret = 0 ;
int i ;
CHECK_ARITY ( 1 ) ;
CAST_TO_STRING ;
CHECK_TYPE ( XPATH_STRING ) ;
val = valuePop ( ctxt ) ;
lang = val - > stringval ;
theLang = xmlNodeGetLang ( ctxt - > context - > node ) ;
if ( ( theLang ! = NULL ) & & ( lang ! = NULL ) ) {
for ( i = 0 ; lang [ i ] ! = 0 ; i + + )
if ( toupper ( lang [ i ] ) ! = toupper ( theLang [ i ] ) )
goto not_equal ;
ret = 1 ;
}
not_equal :
xmlXPathFreeObject ( val ) ;
valuePush ( ctxt , xmlXPathNewBoolean ( ret ) ) ;
}
/**
* xmlXPathNumberFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the number ( ) XPath function
* number number ( object ? )
*/
void
xmlXPathNumberFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
double res ;
if ( nargs = = 0 ) {
if ( ctxt - > context - > node = = NULL ) {
valuePush ( ctxt , xmlXPathNewFloat ( 0.0 ) ) ;
} else {
xmlChar * content = xmlNodeGetContent ( ctxt - > context - > node ) ;
res = xmlXPathStringEvalNumber ( content ) ;
valuePush ( ctxt , xmlXPathNewFloat ( res ) ) ;
xmlFree ( content ) ;
}
return ;
}
CHECK_ARITY ( 1 ) ;
cur = valuePop ( ctxt ) ;
2001-03-19 15:58:54 +00:00
cur = xmlXPathConvertNumber ( cur ) ;
valuePush ( ctxt , cur ) ;
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathSumFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the sum ( ) XPath function
* number sum ( node - set )
* The sum function returns the sum of the values of the nodes in
* the argument node - set .
*/
void
xmlXPathSumFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr cur ;
int i ;
2001-05-15 09:43:47 +00:00
double res = 0.0 ;
2001-02-23 17:55:21 +00:00
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_NODESET ) & &
( ctxt - > value - > type ! = XPATH_XSLT_TREE ) ) )
XP_ERROR ( XPATH_INVALID_TYPE ) ;
cur = valuePop ( ctxt ) ;
2001-04-05 16:54:14 +00:00
if ( ( cur - > nodesetval = = NULL ) | | ( cur - > nodesetval - > nodeNr = = 0 ) ) {
2001-02-23 17:55:21 +00:00
valuePush ( ctxt , xmlXPathNewFloat ( 0.0 ) ) ;
} else {
2001-05-15 09:43:47 +00:00
for ( i = 0 ; i < cur - > nodesetval - > nodeNr ; i + + ) {
res + = xmlXPathCastNodeToNumber ( cur - > nodesetval - > nodeTab [ i ] ) ;
2001-02-23 17:55:21 +00:00
}
2001-05-15 09:43:47 +00:00
valuePush ( ctxt , xmlXPathNewFloat ( res ) ) ;
2001-02-23 17:55:21 +00:00
}
xmlXPathFreeObject ( cur ) ;
}
/**
* xmlXPathFloorFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the floor ( ) XPath function
* number floor ( number )
* The floor function returns the largest ( closest to positive infinity )
* number that is not greater than the argument and that is an integer .
*/
void
xmlXPathFloorFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2002-03-22 14:14:43 +00:00
double f ;
2001-02-23 17:55:21 +00:00
CHECK_ARITY ( 1 ) ;
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
2002-03-22 14:14:43 +00:00
f = ( double ) ( ( int ) ctxt - > value - > floatval ) ;
if ( f ! = ctxt - > value - > floatval ) {
if ( ctxt - > value - > floatval > 0 )
ctxt - > value - > floatval = f ;
else
ctxt - > value - > floatval = f - 1 ;
}
2001-02-23 17:55:21 +00:00
}
/**
* xmlXPathCeilingFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the ceiling ( ) XPath function
* number ceiling ( number )
* The ceiling function returns the smallest ( closest to negative infinity )
* number that is not less than the argument and that is an integer .
*/
void
xmlXPathCeilingFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
double f ;
CHECK_ARITY ( 1 ) ;
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
#if 0
ctxt - > value - > floatval = ceil ( ctxt - > value - > floatval ) ;
# else
f = ( double ) ( ( int ) ctxt - > value - > floatval ) ;
2002-03-22 14:14:43 +00:00
if ( f ! = ctxt - > value - > floatval ) {
if ( ctxt - > value - > floatval > 0 )
ctxt - > value - > floatval = f + 1 ;
2002-03-27 09:05:40 +00:00
else {
if ( ctxt - > value - > floatval < 0 & & f = = 0 )
ctxt - > value - > floatval = xmlXPathNZERO ;
else
ctxt - > value - > floatval = f ;
}
2002-03-22 14:14:43 +00:00
}
2001-02-23 17:55:21 +00:00
# endif
}
/**
* xmlXPathRoundFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the round ( ) XPath function
* number round ( number )
* The round function returns the number that is closest to the
* argument and that is an integer . If there are two such numbers ,
* then the one that is even is returned .
*/
void
xmlXPathRoundFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
double f ;
CHECK_ARITY ( 1 ) ;
CAST_TO_NUMBER ;
CHECK_TYPE ( XPATH_NUMBER ) ;
2001-08-21 10:56:31 +00:00
if ( ( xmlXPathIsNaN ( ctxt - > value - > floatval ) ) | |
( xmlXPathIsInf ( ctxt - > value - > floatval ) = = 1 ) | |
( xmlXPathIsInf ( ctxt - > value - > floatval ) = = - 1 ) | |
2001-02-23 17:55:21 +00:00
( ctxt - > value - > floatval = = 0.0 ) )
return ;
f = ( double ) ( ( int ) ctxt - > value - > floatval ) ;
2002-03-22 14:14:43 +00:00
if ( ctxt - > value - > floatval < 0 ) {
if ( ctxt - > value - > floatval < f - 0.5 )
ctxt - > value - > floatval = f - 1 ;
else
ctxt - > value - > floatval = f ;
2002-03-27 09:05:40 +00:00
if ( ctxt - > value - > floatval = = 0 )
ctxt - > value - > floatval = xmlXPathNZERO ;
2002-03-22 14:14:43 +00:00
} else {
if ( ctxt - > value - > floatval < f + 0.5 )
ctxt - > value - > floatval = f ;
else
ctxt - > value - > floatval = f + 1 ;
}
2001-02-23 17:55:21 +00:00
}
/************************************************************************
* *
* The Parser *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* a couple of forward declarations since we use a recursive call based
* implementation .
*/
2001-03-19 10:57:13 +00:00
static void xmlXPathCompileExpr ( xmlXPathParserContextPtr ctxt ) ;
2001-04-05 16:54:14 +00:00
static void xmlXPathCompPredicate ( xmlXPathParserContextPtr ctxt , int filter ) ;
2001-03-19 10:57:13 +00:00
static void xmlXPathCompLocationPath ( xmlXPathParserContextPtr ctxt ) ;
static void xmlXPathCompRelativeLocationPath ( xmlXPathParserContextPtr ctxt ) ;
2001-04-28 12:24:34 +00:00
static xmlChar * xmlXPathParseNameComplex ( xmlXPathParserContextPtr ctxt ,
int qualified ) ;
2001-02-23 17:55:21 +00:00
2001-04-27 17:13:01 +00:00
/**
* xmlXPathCurrentChar :
* @ ctxt : the XPath parser context
* @ cur : pointer to the beginning of the char
* @ len : pointer to the length of the char read
*
2001-12-31 16:16:02 +00:00
* The current char value , if using UTF - 8 this may actually span multiple
2001-04-27 17:13:01 +00:00
* bytes in the input buffer .
*
2001-10-10 09:45:09 +00:00
* Returns the current char value and its length
2001-04-27 17:13:01 +00:00
*/
static int
xmlXPathCurrentChar ( xmlXPathParserContextPtr ctxt , int * len ) {
unsigned char c ;
unsigned int val ;
const xmlChar * cur ;
if ( ctxt = = NULL )
return ( 0 ) ;
cur = ctxt - > cur ;
/*
* We are supposed to handle UTF8 , check it ' s valid
* From rfc2044 : encoding of the Unicode values on UTF - 8 :
*
* UCS - 4 range ( hex . ) UTF - 8 octet sequence ( binary )
* 0000 0000 - 0000 007F 0 xxxxxxx
* 0000 00 80 - 0000 07FF 110 xxxxx 10 xxxxxx
* 0000 0800 - 0000 FFFF 1110 xxxx 10 xxxxxx 10 xxxxxx
*
* Check for the 0x110000 limit too
*/
c = * cur ;
if ( c & 0x80 ) {
if ( ( cur [ 1 ] & 0xc0 ) ! = 0x80 )
goto encoding_error ;
if ( ( c & 0xe0 ) = = 0xe0 ) {
if ( ( cur [ 2 ] & 0xc0 ) ! = 0x80 )
goto encoding_error ;
if ( ( c & 0xf0 ) = = 0xf0 ) {
if ( ( ( c & 0xf8 ) ! = 0xf0 ) | |
( ( cur [ 3 ] & 0xc0 ) ! = 0x80 ) )
goto encoding_error ;
/* 4-byte code */
* len = 4 ;
val = ( cur [ 0 ] & 0x7 ) < < 18 ;
val | = ( cur [ 1 ] & 0x3f ) < < 12 ;
val | = ( cur [ 2 ] & 0x3f ) < < 6 ;
val | = cur [ 3 ] & 0x3f ;
} else {
/* 3-byte code */
* len = 3 ;
val = ( cur [ 0 ] & 0xf ) < < 12 ;
val | = ( cur [ 1 ] & 0x3f ) < < 6 ;
val | = cur [ 2 ] & 0x3f ;
}
} else {
/* 2-byte code */
* len = 2 ;
val = ( cur [ 0 ] & 0x1f ) < < 6 ;
val | = cur [ 1 ] & 0x3f ;
}
if ( ! IS_CHAR ( val ) ) {
XP_ERROR0 ( XPATH_INVALID_CHAR_ERROR ) ;
}
return ( val ) ;
} else {
/* 1-byte code */
* len = 1 ;
return ( ( int ) * cur ) ;
}
encoding_error :
/*
* If we detect an UTF8 error that probably mean that the
* input encoding didn ' t get properly advertized in the
* declaration header . Report the error and switch the encoding
* to ISO - Latin - 1 ( if you don ' t like this policy , just declare the
* encoding ! )
*/
2001-05-22 16:57:14 +00:00
* len = 0 ;
2001-04-27 17:13:01 +00:00
XP_ERROR0 ( XPATH_ENCODING_ERROR ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathParseNCName :
* @ ctxt : the XPath Parser context
*
* parse an XML namespace non qualified name .
*
* [ NS 3 ] NCName : : = ( Letter | ' _ ' ) ( NCNameChar ) *
*
* [ NS 4 ] NCNameChar : : = Letter | Digit | ' . ' | ' - ' | ' _ ' |
* CombiningChar | Extender
*
* Returns the namespace name or NULL
*/
xmlChar *
xmlXPathParseNCName ( xmlXPathParserContextPtr ctxt ) {
2001-04-28 12:24:34 +00:00
const xmlChar * in ;
xmlChar * ret ;
int count = 0 ;
2001-02-23 17:55:21 +00:00
2001-04-28 12:24:34 +00:00
/*
* Accelerator for simple ASCII names
*/
in = ctxt - > cur ;
if ( ( ( * in > = 0x61 ) & & ( * in < = 0x7A ) ) | |
( ( * in > = 0x41 ) & & ( * in < = 0x5A ) ) | |
( * in = = ' _ ' ) ) {
in + + ;
while ( ( ( * in > = 0x61 ) & & ( * in < = 0x7A ) ) | |
( ( * in > = 0x41 ) & & ( * in < = 0x5A ) ) | |
( ( * in > = 0x30 ) & & ( * in < = 0x39 ) ) | |
2001-06-27 11:13:35 +00:00
( * in = = ' _ ' ) | | ( * in = = ' . ' ) | |
( * in = = ' - ' ) )
2001-04-28 12:24:34 +00:00
in + + ;
if ( ( * in = = ' ' ) | | ( * in = = ' > ' ) | | ( * in = = ' / ' ) | |
( * in = = ' [ ' ) | | ( * in = = ' ] ' ) | | ( * in = = ' : ' ) | |
( * in = = ' @ ' ) | | ( * in = = ' * ' ) ) {
count = in - ctxt - > cur ;
if ( count = = 0 )
return ( NULL ) ;
ret = xmlStrndup ( ctxt - > cur , count ) ;
ctxt - > cur = in ;
return ( ret ) ;
}
}
return ( xmlXPathParseNameComplex ( ctxt , 0 ) ) ;
2001-02-23 17:55:21 +00:00
}
2001-04-28 12:24:34 +00:00
2001-02-23 17:55:21 +00:00
/**
* xmlXPathParseQName :
* @ ctxt : the XPath Parser context
* @ prefix : a xmlChar * *
*
* parse an XML qualified name
*
* [ NS 5 ] QName : : = ( Prefix ' : ' ) ? LocalPart
*
* [ NS 6 ] Prefix : : = NCName
*
* [ NS 7 ] LocalPart : : = NCName
*
* Returns the function returns the local part , and prefix is updated
* to get the Prefix if any .
*/
2001-03-24 17:00:36 +00:00
static xmlChar *
2001-02-23 17:55:21 +00:00
xmlXPathParseQName ( xmlXPathParserContextPtr ctxt , xmlChar * * prefix ) {
xmlChar * ret = NULL ;
* prefix = NULL ;
ret = xmlXPathParseNCName ( ctxt ) ;
if ( CUR = = ' : ' ) {
* prefix = ret ;
NEXT ;
ret = xmlXPathParseNCName ( ctxt ) ;
}
return ( ret ) ;
}
/**
* xmlXPathParseName :
* @ ctxt : the XPath 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 ) {
2001-04-27 17:13:01 +00:00
const xmlChar * in ;
xmlChar * ret ;
int count = 0 ;
2001-02-23 17:55:21 +00:00
2001-04-27 17:13:01 +00:00
/*
* Accelerator for simple ASCII names
*/
in = ctxt - > cur ;
if ( ( ( * in > = 0x61 ) & & ( * in < = 0x7A ) ) | |
( ( * in > = 0x41 ) & & ( * in < = 0x5A ) ) | |
( * in = = ' _ ' ) | | ( * in = = ' : ' ) ) {
in + + ;
while ( ( ( * in > = 0x61 ) & & ( * in < = 0x7A ) ) | |
( ( * in > = 0x41 ) & & ( * in < = 0x5A ) ) | |
( ( * in > = 0x30 ) & & ( * in < = 0x39 ) ) | |
2001-05-16 21:05:17 +00:00
( * in = = ' _ ' ) | | ( * in = = ' - ' ) | |
( * in = = ' : ' ) | | ( * in = = ' . ' ) )
2001-04-27 17:13:01 +00:00
in + + ;
2001-05-16 21:05:17 +00:00
if ( ( * in > 0 ) & & ( * in < 0x80 ) ) {
2001-04-27 17:13:01 +00:00
count = in - ctxt - > cur ;
ret = xmlStrndup ( ctxt - > cur , count ) ;
ctxt - > cur = in ;
return ( ret ) ;
}
}
2001-04-28 12:24:34 +00:00
return ( xmlXPathParseNameComplex ( ctxt , 1 ) ) ;
2001-04-27 17:13:01 +00:00
}
2001-02-23 17:55:21 +00:00
2001-04-27 17:13:01 +00:00
static xmlChar *
2001-04-28 12:24:34 +00:00
xmlXPathParseNameComplex ( xmlXPathParserContextPtr ctxt , int qualified ) {
2001-04-27 17:13:01 +00:00
xmlChar buf [ XML_MAX_NAMELEN + 5 ] ;
int len = 0 , l ;
int c ;
2001-02-23 17:55:21 +00:00
2001-04-27 17:13:01 +00:00
/*
* Handler for more complex cases
*/
c = CUR_CHAR ( l ) ;
if ( ( c = = ' ' ) | | ( c = = ' > ' ) | | ( c = = ' / ' ) | | /* accelerators */
2001-04-28 12:24:34 +00:00
( c = = ' [ ' ) | | ( c = = ' ] ' ) | | ( c = = ' @ ' ) | | /* accelerators */
( c = = ' * ' ) | | /* accelerators */
2001-04-27 17:13:01 +00:00
( ! IS_LETTER ( c ) & & ( c ! = ' _ ' ) & &
2001-04-28 12:24:34 +00:00
( ( qualified ) & & ( c ! = ' : ' ) ) ) ) {
2001-04-27 17:13:01 +00:00
return ( NULL ) ;
}
2001-02-23 17:55:21 +00:00
2001-04-27 17:13:01 +00:00
while ( ( c ! = ' ' ) & & ( c ! = ' > ' ) & & ( c ! = ' / ' ) & & /* test bigname.xml */
( ( IS_LETTER ( c ) ) | | ( IS_DIGIT ( c ) ) | |
( c = = ' . ' ) | | ( c = = ' - ' ) | |
2001-04-28 12:24:34 +00:00
( c = = ' _ ' ) | | ( ( qualified ) & & ( c = = ' : ' ) ) | |
2001-04-27 17:13:01 +00:00
( IS_COMBINING ( c ) ) | |
( IS_EXTENDER ( c ) ) ) ) {
COPY_BUF ( l , buf , len , c ) ;
NEXTL ( l ) ;
c = CUR_CHAR ( l ) ;
if ( len > = XML_MAX_NAMELEN ) {
/*
* Okay someone managed to make a huge name , so he ' s ready to pay
* for the processing speed .
*/
xmlChar * buffer ;
int max = len * 2 ;
2003-04-19 00:07:51 +00:00
buffer = ( xmlChar * ) xmlMallocAtomic ( max * sizeof ( xmlChar ) ) ;
2001-04-27 17:13:01 +00:00
if ( buffer = = NULL ) {
XP_ERROR0 ( XPATH_MEMORY_ERROR ) ;
}
memcpy ( buffer , buf , len ) ;
while ( ( IS_LETTER ( c ) ) | | ( IS_DIGIT ( c ) ) | | /* test bigname.xml */
( c = = ' . ' ) | | ( c = = ' - ' ) | |
2001-04-28 12:24:34 +00:00
( c = = ' _ ' ) | | ( ( qualified ) & & ( c = = ' : ' ) ) | |
2001-04-27 17:13:01 +00:00
( IS_COMBINING ( c ) ) | |
( IS_EXTENDER ( c ) ) ) {
if ( len + 10 > max ) {
max * = 2 ;
buffer = ( xmlChar * ) xmlRealloc ( buffer ,
max * sizeof ( xmlChar ) ) ;
if ( buffer = = NULL ) {
XP_ERROR0 ( XPATH_MEMORY_ERROR ) ;
}
}
COPY_BUF ( l , buffer , len , c ) ;
NEXTL ( l ) ;
c = CUR_CHAR ( l ) ;
}
buffer [ len ] = 0 ;
return ( buffer ) ;
}
}
2001-04-28 12:24:34 +00:00
if ( len = = 0 )
return ( NULL ) ;
2001-04-27 17:13:01 +00:00
return ( xmlStrndup ( buf , len ) ) ;
}
2002-05-13 10:33:30 +00:00
# define MAX_FRAC 20
static double my_pow10 [ MAX_FRAC ] = {
1.0 , 10.0 , 100.0 , 1000.0 , 10000.0 ,
100000.0 , 1000000.0 , 10000000.0 , 100000000.0 , 1000000000.0 ,
10000000000.0 , 100000000000.0 , 1000000000000.0 , 10000000000000.0 ,
100000000000000.0 ,
1000000000000000.0 , 10000000000000000.0 , 100000000000000000.0 ,
1000000000000000000.0 , 10000000000000000000.0
} ;
2001-02-23 17:55:21 +00:00
/**
* xmlXPathStringEvalNumber :
* @ str : A string to scan
*
2001-04-21 16:57:29 +00:00
* [ 30 a ] Float : : = Number ( ' e ' Digits ? ) ?
*
2001-02-23 17:55:21 +00:00
* [ 30 ] Number : : = Digits ( ' . ' Digits ? ) ?
* | ' . ' Digits
* [ 31 ] Digits : : = [ 0 - 9 ] +
*
2001-03-19 10:57:13 +00:00
* Compile a Number in the string
2001-02-23 17:55:21 +00:00
* In complement of the Number expression , this function also handles
* negative values : ' - ' Number .
*
* Returns the double value .
*/
double
xmlXPathStringEvalNumber ( const xmlChar * str ) {
const xmlChar * cur = str ;
2002-03-07 08:36:03 +00:00
double ret ;
2001-08-27 14:26:30 +00:00
int ok = 0 ;
2001-02-23 17:55:21 +00:00
int isneg = 0 ;
2001-04-21 16:57:29 +00:00
int exponent = 0 ;
int is_exponent_negative = 0 ;
2001-08-27 14:26:30 +00:00
# ifdef __GNUC__
unsigned long tmp = 0 ;
2002-03-07 08:36:03 +00:00
double temp ;
2001-08-27 14:26:30 +00:00
# endif
2002-04-24 11:42:02 +00:00
if ( cur = = NULL ) return ( 0 ) ;
2003-10-18 16:20:14 +00:00
while ( IS_BLANK_CH ( * cur ) ) cur + + ;
2001-02-23 17:55:21 +00:00
if ( ( * cur ! = ' . ' ) & & ( ( * cur < ' 0 ' ) | | ( * cur > ' 9 ' ) ) & & ( * cur ! = ' - ' ) ) {
return ( xmlXPathNAN ) ;
}
if ( * cur = = ' - ' ) {
isneg = 1 ;
cur + + ;
}
2001-08-27 14:26:30 +00:00
# ifdef __GNUC__
2001-06-21 22:07:42 +00:00
/*
2002-03-07 08:36:03 +00:00
* tmp / temp is a workaround against a gcc compiler bug
* http : //veillard.com/gcc.bug
2001-06-21 22:07:42 +00:00
*/
2002-03-07 08:36:03 +00:00
ret = 0 ;
2001-02-23 17:55:21 +00:00
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) ) {
2002-03-07 08:36:03 +00:00
ret = ret * 10 ;
tmp = ( * cur - ' 0 ' ) ;
2001-02-23 17:55:21 +00:00
ok = 1 ;
cur + + ;
2002-03-07 08:36:03 +00:00
temp = ( double ) tmp ;
ret = ret + temp ;
2001-02-23 17:55:21 +00:00
}
2001-08-27 14:26:30 +00:00
# else
2002-03-07 08:36:03 +00:00
ret = 0 ;
2001-08-27 14:26:30 +00:00
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) ) {
ret = ret * 10 + ( * cur - ' 0 ' ) ;
ok = 1 ;
cur + + ;
}
# endif
2001-06-21 22:07:42 +00:00
2001-02-23 17:55:21 +00:00
if ( * cur = = ' . ' ) {
2002-05-13 10:33:30 +00:00
int v , frac = 0 ;
double fraction = 0 ;
2001-02-23 17:55:21 +00:00
cur + + ;
if ( ( ( * cur < ' 0 ' ) | | ( * cur > ' 9 ' ) ) & & ( ! ok ) ) {
return ( xmlXPathNAN ) ;
}
2002-05-13 10:33:30 +00:00
while ( ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) ) & & ( frac < MAX_FRAC ) ) {
v = ( * cur - ' 0 ' ) ;
fraction = fraction * 10 + v ;
frac = frac + 1 ;
2001-02-23 17:55:21 +00:00
cur + + ;
}
2002-05-13 10:33:30 +00:00
fraction / = my_pow10 [ frac ] ;
ret = ret + fraction ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
cur + + ;
2001-02-23 17:55:21 +00:00
}
2001-04-21 16:57:29 +00:00
if ( ( * cur = = ' e ' ) | | ( * cur = = ' E ' ) ) {
cur + + ;
if ( * cur = = ' - ' ) {
is_exponent_negative = 1 ;
cur + + ;
}
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) ) {
exponent = exponent * 10 + ( * cur - ' 0 ' ) ;
cur + + ;
}
}
2003-10-18 16:20:14 +00:00
while ( IS_BLANK_CH ( * cur ) ) cur + + ;
2001-02-23 17:55:21 +00:00
if ( * cur ! = 0 ) return ( xmlXPathNAN ) ;
if ( isneg ) ret = - ret ;
2001-04-21 16:57:29 +00:00
if ( is_exponent_negative ) exponent = - exponent ;
ret * = pow ( 10.0 , ( double ) exponent ) ;
2001-02-23 17:55:21 +00:00
return ( ret ) ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompNumber :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 30 ] Number : : = Digits ( ' . ' Digits ? ) ?
* | ' . ' Digits
* [ 31 ] Digits : : = [ 0 - 9 ] +
*
2001-03-19 10:57:13 +00:00
* Compile a Number , then push it on the stack
2001-02-23 17:55:21 +00:00
*
*/
2001-03-19 10:57:13 +00:00
static void
2001-06-21 22:07:42 +00:00
xmlXPathCompNumber ( xmlXPathParserContextPtr ctxt )
{
2001-02-23 17:55:21 +00:00
double ret = 0.0 ;
double mult = 1 ;
2002-03-07 08:36:03 +00:00
int ok = 0 ;
2001-04-21 16:57:29 +00:00
int exponent = 0 ;
int is_exponent_negative = 0 ;
2002-03-07 08:36:03 +00:00
# ifdef __GNUC__
unsigned long tmp = 0 ;
double temp ;
# endif
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
if ( ( CUR ! = ' . ' ) & & ( ( CUR < ' 0 ' ) | | ( CUR > ' 9 ' ) ) ) {
XP_ERROR ( XPATH_NUMBER_ERROR ) ;
}
2002-03-07 08:36:03 +00:00
# ifdef __GNUC__
2001-06-21 22:07:42 +00:00
/*
2002-03-07 08:36:03 +00:00
* tmp / temp is a workaround against a gcc compiler bug
* http : //veillard.com/gcc.bug
2001-06-21 22:07:42 +00:00
*/
2002-03-07 08:36:03 +00:00
ret = 0 ;
2001-02-23 17:55:21 +00:00
while ( ( CUR > = ' 0 ' ) & & ( CUR < = ' 9 ' ) ) {
2002-03-07 08:36:03 +00:00
ret = ret * 10 ;
tmp = ( CUR - ' 0 ' ) ;
2001-06-21 22:07:42 +00:00
ok = 1 ;
NEXT ;
2002-03-07 08:36:03 +00:00
temp = ( double ) tmp ;
ret = ret + temp ;
2001-02-23 17:55:21 +00:00
}
2002-03-07 08:36:03 +00:00
# else
ret = 0 ;
while ( ( CUR > = ' 0 ' ) & & ( CUR < = ' 9 ' ) ) {
ret = ret * 10 + ( CUR - ' 0 ' ) ;
ok = 1 ;
NEXT ;
}
# endif
2001-02-23 17:55:21 +00:00
if ( CUR = = ' . ' ) {
NEXT ;
2001-06-21 22:07:42 +00:00
if ( ( ( CUR < ' 0 ' ) | | ( CUR > ' 9 ' ) ) & & ( ! ok ) ) {
XP_ERROR ( XPATH_NUMBER_ERROR ) ;
}
while ( ( CUR > = ' 0 ' ) & & ( CUR < = ' 9 ' ) ) {
mult / = 10 ;
ret = ret + ( CUR - ' 0 ' ) * mult ;
NEXT ;
}
2001-02-23 17:55:21 +00:00
}
2001-04-21 16:57:29 +00:00
if ( ( CUR = = ' e ' ) | | ( CUR = = ' E ' ) ) {
2001-06-21 22:07:42 +00:00
NEXT ;
if ( CUR = = ' - ' ) {
is_exponent_negative = 1 ;
NEXT ;
}
while ( ( CUR > = ' 0 ' ) & & ( CUR < = ' 9 ' ) ) {
exponent = exponent * 10 + ( CUR - ' 0 ' ) ;
NEXT ;
}
if ( is_exponent_negative )
exponent = - exponent ;
ret * = pow ( 10.0 , ( double ) exponent ) ;
2001-04-21 16:57:29 +00:00
}
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_VALUE , XPATH_NUMBER , 0 , 0 ,
2001-06-21 22:07:42 +00:00
xmlXPathNewFloat ( ret ) , NULL ) ;
2001-02-23 17:55:21 +00:00
}
2001-03-19 15:58:54 +00:00
/**
* xmlXPathParseLiteral :
* @ ctxt : the XPath Parser context
*
* Parse a Literal
*
* [ 29 ] Literal : : = ' " ' [ ^ " ]* ' " '
* | " ' " [ ^ ' ] * " ' "
*
* Returns the value found or NULL in case of error
*/
static xmlChar *
xmlXPathParseLiteral ( xmlXPathParserContextPtr ctxt ) {
const xmlChar * q ;
xmlChar * ret = NULL ;
if ( CUR = = ' " ' ) {
NEXT ;
q = CUR_PTR ;
2003-10-18 16:20:14 +00:00
while ( ( IS_CHAR_CH ( CUR ) ) & & ( CUR ! = ' " ' ) )
2001-03-19 15:58:54 +00:00
NEXT ;
2003-10-18 16:20:14 +00:00
if ( ! IS_CHAR_CH ( CUR ) ) {
2001-03-19 15:58:54 +00:00
XP_ERROR0 ( XPATH_UNFINISHED_LITERAL_ERROR ) ;
} else {
ret = xmlStrndup ( q , CUR_PTR - q ) ;
NEXT ;
}
} else if ( CUR = = ' \' ' ) {
NEXT ;
q = CUR_PTR ;
2003-10-18 16:20:14 +00:00
while ( ( IS_CHAR_CH ( CUR ) ) & & ( CUR ! = ' \' ' ) )
2001-03-19 15:58:54 +00:00
NEXT ;
2003-10-18 16:20:14 +00:00
if ( ! IS_CHAR_CH ( CUR ) ) {
2001-03-19 15:58:54 +00:00
XP_ERROR0 ( XPATH_UNFINISHED_LITERAL_ERROR ) ;
} else {
ret = xmlStrndup ( q , CUR_PTR - q ) ;
NEXT ;
}
} else {
XP_ERROR0 ( XPATH_START_LITERAL_ERROR ) ;
}
return ( ret ) ;
}
2001-02-23 17:55:21 +00:00
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompLiteral :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* Parse a Literal and push it on the stack .
*
* [ 29 ] Literal : : = ' " ' [ ^ " ]* ' " '
* | " ' " [ ^ ' ] * " ' "
*
2001-03-19 10:57:13 +00:00
* TODO : xmlXPathCompLiteral memory allocation could be improved .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompLiteral ( xmlXPathParserContextPtr ctxt ) {
2001-02-23 17:55:21 +00:00
const xmlChar * q ;
xmlChar * ret = NULL ;
if ( CUR = = ' " ' ) {
NEXT ;
q = CUR_PTR ;
2003-10-18 16:20:14 +00:00
while ( ( IS_CHAR_CH ( CUR ) ) & & ( CUR ! = ' " ' ) )
2001-02-23 17:55:21 +00:00
NEXT ;
2003-10-18 16:20:14 +00:00
if ( ! IS_CHAR_CH ( CUR ) ) {
2001-02-23 17:55:21 +00:00
XP_ERROR ( XPATH_UNFINISHED_LITERAL_ERROR ) ;
} else {
ret = xmlStrndup ( q , CUR_PTR - q ) ;
NEXT ;
}
} else if ( CUR = = ' \' ' ) {
NEXT ;
q = CUR_PTR ;
2003-10-18 16:20:14 +00:00
while ( ( IS_CHAR_CH ( CUR ) ) & & ( CUR ! = ' \' ' ) )
2001-02-23 17:55:21 +00:00
NEXT ;
2003-10-18 16:20:14 +00:00
if ( ! IS_CHAR_CH ( CUR ) ) {
2001-02-23 17:55:21 +00:00
XP_ERROR ( XPATH_UNFINISHED_LITERAL_ERROR ) ;
} else {
ret = xmlStrndup ( q , CUR_PTR - q ) ;
NEXT ;
}
} else {
XP_ERROR ( XPATH_START_LITERAL_ERROR ) ;
}
if ( ret = = NULL ) return ;
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_VALUE , XPATH_STRING , 0 , 0 ,
xmlXPathNewString ( ret ) , NULL ) ;
2001-02-23 17:55:21 +00:00
xmlFree ( ret ) ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompVariableReference :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* Parse a VariableReference , evaluate it and push it on the stack .
*
* The variable bindings consist of a mapping from variable names
* to variable values . The value of a variable is an object , which
* of any of the types that are possible for the value of an expression ,
* and may also be of additional types not specified here .
*
* Early evaluation is possible since :
* The variable bindings [ . . . ] used to evaluate a subexpression are
* always the same as those used to evaluate the containing expression .
*
* [ 36 ] VariableReference : : = ' $ ' QName
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompVariableReference ( xmlXPathParserContextPtr ctxt ) {
2001-02-23 17:55:21 +00:00
xmlChar * name ;
xmlChar * prefix ;
SKIP_BLANKS ;
if ( CUR ! = ' $ ' ) {
XP_ERROR ( XPATH_VARIABLE_REF_ERROR ) ;
}
NEXT ;
name = xmlXPathParseQName ( ctxt , & prefix ) ;
if ( name = = NULL ) {
XP_ERROR ( XPATH_VARIABLE_REF_ERROR ) ;
}
2001-03-19 15:58:54 +00:00
ctxt - > comp - > last = - 1 ;
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_VARIABLE , 0 , 0 , 0 ,
name , prefix ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
/**
* xmlXPathIsNodeType :
* @ name : a name string
*
* Is the name given a NodeType one .
*
* [ 38 ] NodeType : : = ' comment '
* | ' text '
* | ' processing - instruction '
* | ' node '
*
* Returns 1 if true 0 otherwise
*/
int
xmlXPathIsNodeType ( const xmlChar * name ) {
if ( name = = NULL )
return ( 0 ) ;
2002-01-31 20:29:19 +00:00
if ( xmlStrEqual ( name , BAD_CAST " node " ) )
2001-02-23 17:55:21 +00:00
return ( 1 ) ;
if ( xmlStrEqual ( name , BAD_CAST " text " ) )
return ( 1 ) ;
2002-01-31 20:29:19 +00:00
if ( xmlStrEqual ( name , BAD_CAST " comment " ) )
2001-02-23 17:55:21 +00:00
return ( 1 ) ;
2002-01-31 20:29:19 +00:00
if ( xmlStrEqual ( name , BAD_CAST " processing-instruction " ) )
2001-02-23 17:55:21 +00:00
return ( 1 ) ;
return ( 0 ) ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompFunctionCall :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 16 ] FunctionCall : : = FunctionName ' ( ' ( Argument ( ' , ' Argument ) * ) ? ' ) '
* [ 17 ] Argument : : = Expr
*
2001-03-19 10:57:13 +00:00
* Compile a function call , the evaluation of all arguments are
2001-02-23 17:55:21 +00:00
* pushed on the stack
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompFunctionCall ( xmlXPathParserContextPtr ctxt ) {
2001-02-23 17:55:21 +00:00
xmlChar * name ;
xmlChar * prefix ;
int nbargs = 0 ;
name = xmlXPathParseQName ( ctxt , & prefix ) ;
if ( name = = NULL ) {
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
SKIP_BLANKS ;
# ifdef DEBUG_EXPR
if ( prefix = = NULL )
xmlGenericError ( xmlGenericErrorContext , " Calling function %s \n " ,
name ) ;
else
xmlGenericError ( xmlGenericErrorContext , " Calling function %s:%s \n " ,
prefix , name ) ;
# endif
if ( CUR ! = ' ( ' ) {
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
2001-03-18 23:17:47 +00:00
ctxt - > comp - > last = - 1 ;
2003-01-14 16:07:16 +00:00
if ( CUR ! = ' ) ' ) {
while ( CUR ! = 0 ) {
int op1 = ctxt - > comp - > last ;
ctxt - > comp - > last = - 1 ;
xmlXPathCompileExpr ( ctxt ) ;
CHECK_ERROR ;
PUSH_BINARY_EXPR ( XPATH_OP_ARG , op1 , ctxt - > comp - > last , 0 , 0 ) ;
nbargs + + ;
if ( CUR = = ' ) ' ) break ;
if ( CUR ! = ' , ' ) {
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
2001-02-23 17:55:21 +00:00
}
}
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_FUNCTION , nbargs , 0 , 0 ,
name , prefix ) ;
2001-02-23 17:55:21 +00:00
NEXT ;
SKIP_BLANKS ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompPrimaryExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 15 ] PrimaryExpr : : = VariableReference
* | ' ( ' Expr ' ) '
* | Literal
* | Number
* | FunctionCall
*
2001-03-19 10:57:13 +00:00
* Compile a primary expression .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompPrimaryExpr ( xmlXPathParserContextPtr ctxt ) {
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
if ( CUR = = ' $ ' ) xmlXPathCompVariableReference ( ctxt ) ;
2001-02-23 17:55:21 +00:00
else if ( CUR = = ' ( ' ) {
NEXT ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompileExpr ( ctxt ) ;
2002-05-07 16:21:36 +00:00
CHECK_ERROR ;
2001-02-23 17:55:21 +00:00
if ( CUR ! = ' ) ' ) {
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
2003-10-18 16:20:14 +00:00
} else if ( IS_DIGIT_CH ( CUR ) | | ( CUR = = ' . ' & & IS_DIGIT_CH ( NXT ( 1 ) ) ) ) {
2001-03-19 10:57:13 +00:00
xmlXPathCompNumber ( ctxt ) ;
2001-02-23 17:55:21 +00:00
} else if ( ( CUR = = ' \' ' ) | | ( CUR = = ' " ' ) ) {
2001-03-19 10:57:13 +00:00
xmlXPathCompLiteral ( ctxt ) ;
2001-02-23 17:55:21 +00:00
} else {
2001-03-19 10:57:13 +00:00
xmlXPathCompFunctionCall ( ctxt ) ;
2001-02-23 17:55:21 +00:00
}
SKIP_BLANKS ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompFilterExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 20 ] FilterExpr : : = PrimaryExpr
* | FilterExpr Predicate
*
2001-03-19 10:57:13 +00:00
* Compile a filter expression .
2001-02-23 17:55:21 +00:00
* Square brackets are used to filter expressions in the same way that
* they are used in location paths . It is an error if the expression to
* be filtered does not evaluate to a node - set . The context node list
* used for evaluating the expression in square brackets is the node - set
* to be filtered listed in document order .
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompFilterExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompPrimaryExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( CUR = = ' [ ' ) {
2001-04-05 16:54:14 +00:00
xmlXPathCompPredicate ( ctxt , 1 ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
}
/**
* xmlXPathScanName :
* @ ctxt : the XPath Parser context
*
* Trickery : parse an XML name but without consuming the input flow
* Needed to avoid insanity in the parser state .
*
* [ 4 ] NameChar : : = Letter | Digit | ' . ' | ' - ' | ' _ ' | ' : ' |
* CombiningChar | Extender
*
* [ 5 ] Name : : = ( Letter | ' _ ' | ' : ' ) ( NameChar ) *
*
* [ 6 ] Names : : = Name ( S Name ) *
*
* Returns the Name parsed or NULL
*/
2001-03-24 17:00:36 +00:00
static xmlChar *
2001-02-23 17:55:21 +00:00
xmlXPathScanName ( xmlXPathParserContextPtr ctxt ) {
xmlChar buf [ XML_MAX_NAMELEN ] ;
int len = 0 ;
SKIP_BLANKS ;
2003-10-18 16:20:14 +00:00
if ( ! IS_LETTER_CH ( CUR ) & & ( CUR ! = ' _ ' ) & &
2001-02-23 17:55:21 +00:00
( CUR ! = ' : ' ) ) {
return ( NULL ) ;
}
2003-10-18 16:20:14 +00:00
while ( ( IS_LETTER_CH ( NXT ( len ) ) ) | | ( IS_DIGIT_CH ( NXT ( len ) ) ) | |
2001-02-23 17:55:21 +00:00
( NXT ( len ) = = ' . ' ) | | ( NXT ( len ) = = ' - ' ) | |
( NXT ( len ) = = ' _ ' ) | | ( NXT ( len ) = = ' : ' ) | |
2003-10-18 16:20:14 +00:00
( IS_COMBINING_CH ( NXT ( len ) ) ) | |
( IS_EXTENDER_CH ( NXT ( len ) ) ) ) {
2001-02-23 17:55:21 +00:00
buf [ len ] = NXT ( len ) ;
len + + ;
if ( len > = XML_MAX_NAMELEN ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlScanName: reached XML_MAX_NAMELEN limit \n " ) ;
2003-10-18 16:20:14 +00:00
while ( ( IS_LETTER_CH ( NXT ( len ) ) ) | | ( IS_DIGIT_CH ( NXT ( len ) ) ) | |
2001-02-23 17:55:21 +00:00
( NXT ( len ) = = ' . ' ) | | ( NXT ( len ) = = ' - ' ) | |
( NXT ( len ) = = ' _ ' ) | | ( NXT ( len ) = = ' : ' ) | |
2003-10-18 16:20:14 +00:00
( IS_COMBINING_CH ( NXT ( len ) ) ) | |
( IS_EXTENDER_CH ( NXT ( len ) ) ) )
2001-02-23 17:55:21 +00:00
len + + ;
break ;
}
}
return ( xmlStrndup ( buf , len ) ) ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompPathExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 19 ] PathExpr : : = LocationPath
* | FilterExpr
* | FilterExpr ' / ' RelativeLocationPath
* | FilterExpr ' //' RelativeLocationPath
*
2001-03-19 10:57:13 +00:00
* Compile a path expression .
2001-02-23 17:55:21 +00:00
* The / operator and // operators combine an arbitrary expression
* and a relative location path . It is an error if the expression
* does not evaluate to a node - set .
* The / operator does composition in the same way as when / is
* used in a location path . As in location paths , // is short for
* / descendant - or - self : : node ( ) / .
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompPathExpr ( xmlXPathParserContextPtr ctxt ) {
2001-02-23 17:55:21 +00:00
int lc = 1 ; /* Should we branch to LocationPath ? */
xmlChar * name = NULL ; /* we may have to preparse a name to find out */
SKIP_BLANKS ;
2003-10-18 16:20:14 +00:00
if ( ( CUR = = ' $ ' ) | | ( CUR = = ' ( ' ) | | ( IS_DIGIT_CH ( CUR ) ) | |
( CUR = = ' \' ' ) | | ( CUR = = ' " ' ) | | ( CUR = = ' . ' & & IS_DIGIT_CH ( NXT ( 1 ) ) ) ) {
2001-02-23 17:55:21 +00:00
lc = 0 ;
} else if ( CUR = = ' * ' ) {
/* relative or absolute location path */
lc = 1 ;
} else if ( CUR = = ' / ' ) {
/* relative or absolute location path */
lc = 1 ;
} else if ( CUR = = ' @ ' ) {
/* relative abbreviated attribute location path */
lc = 1 ;
} else if ( CUR = = ' . ' ) {
/* relative abbreviated attribute location path */
lc = 1 ;
} else {
/*
* Problem is finding if we have a name here whether it ' s :
* - a nodetype
* - a function call in which case it ' s followed by ' ( '
* - an axis in which case it ' s followed by ' : '
* - a element name
* We do an a priori analysis here rather than having to
* maintain parsed token content through the recursive function
* calls . This looks uglier but makes the code quite easier to
* read / write / debug .
*/
SKIP_BLANKS ;
name = xmlXPathScanName ( ctxt ) ;
if ( ( name ! = NULL ) & & ( xmlStrstr ( name , ( xmlChar * ) " :: " ) ! = NULL ) ) {
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" PathExpr: Axis \n " ) ;
# endif
lc = 1 ;
xmlFree ( name ) ;
} else if ( name ! = NULL ) {
int len = xmlStrlen ( name ) ;
while ( NXT ( len ) ! = 0 ) {
if ( NXT ( len ) = = ' / ' ) {
/* element name */
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" PathExpr: AbbrRelLocation \n " ) ;
# endif
lc = 1 ;
break ;
2003-10-18 16:20:14 +00:00
} else if ( IS_BLANK_CH ( NXT ( len ) ) ) {
2003-07-31 14:47:38 +00:00
/* ignore blanks */
;
2001-02-23 17:55:21 +00:00
} else if ( NXT ( len ) = = ' : ' ) {
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" PathExpr: AbbrRelLocation \n " ) ;
# endif
lc = 1 ;
break ;
} else if ( ( NXT ( len ) = = ' ( ' ) ) {
/* Note Type or Function */
if ( xmlXPathIsNodeType ( name ) ) {
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" PathExpr: Type search \n " ) ;
# endif
lc = 1 ;
} else {
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" PathExpr: function call \n " ) ;
# endif
lc = 0 ;
}
break ;
} else if ( ( NXT ( len ) = = ' [ ' ) ) {
/* element name */
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" PathExpr: AbbrRelLocation \n " ) ;
# endif
lc = 1 ;
break ;
} else if ( ( NXT ( len ) = = ' < ' ) | | ( NXT ( len ) = = ' > ' ) | |
( NXT ( len ) = = ' = ' ) ) {
lc = 1 ;
break ;
} else {
lc = 1 ;
break ;
}
len + + ;
}
if ( NXT ( len ) = = 0 ) {
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" PathExpr: AbbrRelLocation \n " ) ;
# endif
/* element name */
lc = 1 ;
}
xmlFree ( name ) ;
} else {
/* make sure all cases are covered explicitely */
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
}
if ( lc ) {
2001-03-18 23:17:47 +00:00
if ( CUR = = ' / ' ) {
PUSH_LEAVE_EXPR ( XPATH_OP_ROOT , 0 , 0 ) ;
} else {
PUSH_LEAVE_EXPR ( XPATH_OP_NODE , 0 , 0 ) ;
2001-02-23 17:55:21 +00:00
}
2001-03-19 10:57:13 +00:00
xmlXPathCompLocationPath ( ctxt ) ;
2001-02-23 17:55:21 +00:00
} else {
2001-03-19 10:57:13 +00:00
xmlXPathCompFilterExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
if ( ( CUR = = ' / ' ) & & ( NXT ( 1 ) = = ' / ' ) ) {
SKIP ( 2 ) ;
SKIP_BLANKS ;
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_COLLECT , AXIS_DESCENDANT_OR_SELF ,
NODE_TEST_TYPE , NODE_TYPE_NODE , NULL , NULL ) ;
PUSH_UNARY_EXPR ( XPATH_OP_RESET , ctxt - > comp - > last , 1 , 0 ) ;
2001-03-19 10:57:13 +00:00
xmlXPathCompRelativeLocationPath ( ctxt ) ;
2001-02-23 17:55:21 +00:00
} else if ( CUR = = ' / ' ) {
2001-03-19 10:57:13 +00:00
xmlXPathCompRelativeLocationPath ( ctxt ) ;
2001-02-23 17:55:21 +00:00
}
}
SKIP_BLANKS ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompUnionExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 18 ] UnionExpr : : = PathExpr
* | UnionExpr ' | ' PathExpr
*
2001-03-19 10:57:13 +00:00
* Compile an union expression .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompUnionExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompPathExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( CUR = = ' | ' ) {
2001-03-18 23:17:47 +00:00
int op1 = ctxt - > comp - > last ;
PUSH_LEAVE_EXPR ( XPATH_OP_NODE , 0 , 0 ) ;
2001-02-23 17:55:21 +00:00
NEXT ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompPathExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
2001-03-18 23:17:47 +00:00
PUSH_BINARY_EXPR ( XPATH_OP_UNION , op1 , ctxt - > comp - > last , 0 , 0 ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompUnaryExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 27 ] UnaryExpr : : = UnionExpr
* | ' - ' UnaryExpr
*
2001-03-19 10:57:13 +00:00
* Compile an unary expression .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompUnaryExpr ( xmlXPathParserContextPtr ctxt ) {
2001-02-23 17:55:21 +00:00
int minus = 0 ;
2001-03-18 23:17:47 +00:00
int found = 0 ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
2001-03-12 18:22:04 +00:00
while ( CUR = = ' - ' ) {
minus = 1 - minus ;
2001-03-18 23:17:47 +00:00
found = 1 ;
2001-02-23 17:55:21 +00:00
NEXT ;
SKIP_BLANKS ;
}
2001-03-18 23:17:47 +00:00
2001-03-19 10:57:13 +00:00
xmlXPathCompUnionExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
2001-03-18 23:17:47 +00:00
if ( found ) {
if ( minus )
PUSH_UNARY_EXPR ( XPATH_OP_PLUS , ctxt - > comp - > last , 2 , 0 ) ;
else
PUSH_UNARY_EXPR ( XPATH_OP_PLUS , ctxt - > comp - > last , 3 , 0 ) ;
2001-02-23 17:55:21 +00:00
}
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompMultiplicativeExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 26 ] MultiplicativeExpr : : = UnaryExpr
* | MultiplicativeExpr MultiplyOperator UnaryExpr
* | MultiplicativeExpr ' div ' UnaryExpr
* | MultiplicativeExpr ' mod ' UnaryExpr
* [ 34 ] MultiplyOperator : : = ' * '
*
2001-03-19 10:57:13 +00:00
* Compile an Additive expression .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompMultiplicativeExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompUnaryExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( ( CUR = = ' * ' ) | |
( ( CUR = = ' d ' ) & & ( NXT ( 1 ) = = ' i ' ) & & ( NXT ( 2 ) = = ' v ' ) ) | |
( ( CUR = = ' m ' ) & & ( NXT ( 1 ) = = ' o ' ) & & ( NXT ( 2 ) = = ' d ' ) ) ) {
int op = - 1 ;
2001-03-18 23:17:47 +00:00
int op1 = ctxt - > comp - > last ;
2001-02-23 17:55:21 +00:00
if ( CUR = = ' * ' ) {
op = 0 ;
NEXT ;
} else if ( CUR = = ' d ' ) {
op = 1 ;
SKIP ( 3 ) ;
} else if ( CUR = = ' m ' ) {
op = 2 ;
SKIP ( 3 ) ;
}
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompUnaryExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
2001-03-18 23:17:47 +00:00
PUSH_BINARY_EXPR ( XPATH_OP_MULT , op1 , ctxt - > comp - > last , op , 0 ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompAdditiveExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 25 ] AdditiveExpr : : = MultiplicativeExpr
* | AdditiveExpr ' + ' MultiplicativeExpr
* | AdditiveExpr ' - ' MultiplicativeExpr
*
2001-03-19 10:57:13 +00:00
* Compile an Additive expression .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompAdditiveExpr ( xmlXPathParserContextPtr ctxt ) {
2001-03-18 23:17:47 +00:00
2001-03-19 10:57:13 +00:00
xmlXPathCompMultiplicativeExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( ( CUR = = ' + ' ) | | ( CUR = = ' - ' ) ) {
int plus ;
2001-03-18 23:17:47 +00:00
int op1 = ctxt - > comp - > last ;
2001-02-23 17:55:21 +00:00
if ( CUR = = ' + ' ) plus = 1 ;
else plus = 0 ;
NEXT ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompMultiplicativeExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
2001-03-18 23:17:47 +00:00
PUSH_BINARY_EXPR ( XPATH_OP_PLUS , op1 , ctxt - > comp - > last , plus , 0 ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompRelationalExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 24 ] RelationalExpr : : = AdditiveExpr
* | RelationalExpr ' < ' AdditiveExpr
* | RelationalExpr ' > ' AdditiveExpr
* | RelationalExpr ' < = ' AdditiveExpr
* | RelationalExpr ' > = ' AdditiveExpr
*
* A < = B > C is allowed ? Answer from James , yes with
* ( AdditiveExpr < = AdditiveExpr ) > AdditiveExpr
* which is basically what got implemented .
*
2001-03-19 10:57:13 +00:00
* Compile a Relational expression , then push the result
2001-02-23 17:55:21 +00:00
* on the stack
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompRelationalExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompAdditiveExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( ( CUR = = ' < ' ) | |
( CUR = = ' > ' ) | |
( ( CUR = = ' < ' ) & & ( NXT ( 1 ) = = ' = ' ) ) | |
( ( CUR = = ' > ' ) & & ( NXT ( 1 ) = = ' = ' ) ) ) {
2001-03-18 23:17:47 +00:00
int inf , strict ;
int op1 = ctxt - > comp - > last ;
2001-02-23 17:55:21 +00:00
if ( CUR = = ' < ' ) inf = 1 ;
else inf = 0 ;
if ( NXT ( 1 ) = = ' = ' ) strict = 0 ;
else strict = 1 ;
NEXT ;
if ( ! strict ) NEXT ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompAdditiveExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
2001-03-18 23:17:47 +00:00
PUSH_BINARY_EXPR ( XPATH_OP_CMP , op1 , ctxt - > comp - > last , inf , strict ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompEqualityExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 23 ] EqualityExpr : : = RelationalExpr
* | EqualityExpr ' = ' RelationalExpr
* | EqualityExpr ' ! = ' RelationalExpr
*
* A ! = B ! = C is allowed ? Answer from James , yes with
* ( RelationalExpr = RelationalExpr ) = RelationalExpr
* ( RelationalExpr ! = RelationalExpr ) ! = RelationalExpr
* which is basically what got implemented .
*
2001-03-19 10:57:13 +00:00
* Compile an Equality expression .
2001-02-23 17:55:21 +00:00
*
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompEqualityExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompRelationalExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( ( CUR = = ' = ' ) | | ( ( CUR = = ' ! ' ) & & ( NXT ( 1 ) = = ' = ' ) ) ) {
2001-03-18 23:17:47 +00:00
int eq ;
int op1 = ctxt - > comp - > last ;
2001-02-23 17:55:21 +00:00
if ( CUR = = ' = ' ) eq = 1 ;
else eq = 0 ;
NEXT ;
if ( ! eq ) NEXT ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompRelationalExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
2001-03-18 23:17:47 +00:00
PUSH_BINARY_EXPR ( XPATH_OP_EQUAL , op1 , ctxt - > comp - > last , eq , 0 ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompAndExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 22 ] AndExpr : : = EqualityExpr
* | AndExpr ' and ' EqualityExpr
*
2001-03-19 10:57:13 +00:00
* Compile an AND expression .
2001-02-23 17:55:21 +00:00
*
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompAndExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompEqualityExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( ( CUR = = ' a ' ) & & ( NXT ( 1 ) = = ' n ' ) & & ( NXT ( 2 ) = = ' d ' ) ) {
2001-03-18 23:17:47 +00:00
int op1 = ctxt - > comp - > last ;
2001-02-23 17:55:21 +00:00
SKIP ( 3 ) ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompEqualityExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
2001-03-18 23:17:47 +00:00
PUSH_BINARY_EXPR ( XPATH_OP_AND , op1 , ctxt - > comp - > last , 0 , 0 ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
}
/**
2003-02-09 23:33:36 +00:00
* xmlXPathCompileExpr :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 14 ] Expr : : = OrExpr
* [ 21 ] OrExpr : : = AndExpr
* | OrExpr ' or ' AndExpr
*
2001-03-19 10:57:13 +00:00
* Parse and compile an expression
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompileExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompAndExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
while ( ( CUR = = ' o ' ) & & ( NXT ( 1 ) = = ' r ' ) ) {
2001-03-18 23:17:47 +00:00
int op1 = ctxt - > comp - > last ;
2001-02-23 17:55:21 +00:00
SKIP ( 2 ) ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompAndExpr ( ctxt ) ;
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
2001-03-18 23:17:47 +00:00
PUSH_BINARY_EXPR ( XPATH_OP_OR , op1 , ctxt - > comp - > last , 0 , 0 ) ;
op1 = ctxt - > comp - > nbStep ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
}
2001-03-18 23:17:47 +00:00
if ( ctxt - > comp - > steps [ ctxt - > comp - > last ] . op ! = XPATH_OP_VALUE ) {
/* more ops could be optimized too */
PUSH_UNARY_EXPR ( XPATH_OP_SORT , ctxt - > comp - > last , 0 , 0 ) ;
}
2001-02-23 17:55:21 +00:00
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompPredicate :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
2001-04-05 16:54:14 +00:00
* @ filter : act as a filter
2001-02-23 17:55:21 +00:00
*
* [ 8 ] Predicate : : = ' [ ' PredicateExpr ' ] '
* [ 9 ] PredicateExpr : : = Expr
*
2001-03-19 10:57:13 +00:00
* Compile a predicate expression
2001-03-18 23:17:47 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
2001-04-05 16:54:14 +00:00
xmlXPathCompPredicate ( xmlXPathParserContextPtr ctxt , int filter ) {
2001-03-18 23:17:47 +00:00
int op1 = ctxt - > comp - > last ;
SKIP_BLANKS ;
if ( CUR ! = ' [ ' ) {
XP_ERROR ( XPATH_INVALID_PREDICATE_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
ctxt - > comp - > last = - 1 ;
2001-03-19 10:57:13 +00:00
xmlXPathCompileExpr ( ctxt ) ;
2001-03-18 23:17:47 +00:00
CHECK_ERROR ;
if ( CUR ! = ' ] ' ) {
XP_ERROR ( XPATH_INVALID_PREDICATE_ERROR ) ;
}
2001-04-05 16:54:14 +00:00
if ( filter )
PUSH_BINARY_EXPR ( XPATH_OP_FILTER , op1 , ctxt - > comp - > last , 0 , 0 ) ;
else
PUSH_BINARY_EXPR ( XPATH_OP_PREDICATE , op1 , ctxt - > comp - > last , 0 , 0 ) ;
2001-03-18 23:17:47 +00:00
NEXT ;
SKIP_BLANKS ;
}
2001-02-23 17:55:21 +00:00
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompNodeTest :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
* @ test : pointer to a xmlXPathTestVal
* @ type : pointer to a xmlXPathTypeVal
* @ prefix : placeholder for a possible name prefix
*
* [ 7 ] NodeTest : : = NameTest
* | NodeType ' ( ' ' ) '
* | ' processing - instruction ' ' ( ' Literal ' ) '
*
* [ 37 ] NameTest : : = ' * '
* | NCName ' : ' ' * '
* | QName
* [ 38 ] NodeType : : = ' comment '
* | ' text '
* | ' processing - instruction '
* | ' node '
*
* Returns the name found and update @ test , @ type and @ prefix appropriately
*/
2001-03-24 17:00:36 +00:00
static xmlChar *
2001-03-19 10:57:13 +00:00
xmlXPathCompNodeTest ( xmlXPathParserContextPtr ctxt , xmlXPathTestVal * test ,
xmlXPathTypeVal * type , const xmlChar * * prefix ,
xmlChar * name ) {
2001-02-23 17:55:21 +00:00
int blanks ;
if ( ( test = = NULL ) | | ( type = = NULL ) | | ( prefix = = NULL ) ) {
STRANGE ;
return ( NULL ) ;
}
2003-07-31 14:47:38 +00:00
* type = ( xmlXPathTypeVal ) 0 ;
* test = ( xmlXPathTestVal ) 0 ;
2001-02-23 17:55:21 +00:00
* prefix = NULL ;
SKIP_BLANKS ;
if ( ( name = = NULL ) & & ( CUR = = ' * ' ) ) {
/*
* All elements
*/
NEXT ;
* test = NODE_TEST_ALL ;
return ( NULL ) ;
}
if ( name = = NULL )
name = xmlXPathParseNCName ( ctxt ) ;
if ( name = = NULL ) {
XP_ERROR0 ( XPATH_EXPR_ERROR ) ;
}
2003-10-18 16:20:14 +00:00
blanks = IS_BLANK_CH ( CUR ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
if ( CUR = = ' ( ' ) {
NEXT ;
/*
* NodeType or PI search
*/
if ( xmlStrEqual ( name , BAD_CAST " comment " ) )
* type = NODE_TYPE_COMMENT ;
else if ( xmlStrEqual ( name , BAD_CAST " node " ) )
* type = NODE_TYPE_NODE ;
else if ( xmlStrEqual ( name , BAD_CAST " processing-instruction " ) )
* type = NODE_TYPE_PI ;
else if ( xmlStrEqual ( name , BAD_CAST " text " ) )
* type = NODE_TYPE_TEXT ;
else {
if ( name ! = NULL )
xmlFree ( name ) ;
XP_ERROR0 ( XPATH_EXPR_ERROR ) ;
}
* test = NODE_TEST_TYPE ;
SKIP_BLANKS ;
if ( * type = = NODE_TYPE_PI ) {
/*
* Specific case : search a PI by name .
*/
if ( name ! = NULL )
xmlFree ( name ) ;
2001-04-26 14:38:03 +00:00
name = NULL ;
if ( CUR ! = ' ) ' ) {
name = xmlXPathParseLiteral ( ctxt ) ;
CHECK_ERROR 0 ;
2002-05-27 12:16:02 +00:00
* test = NODE_TEST_PI ;
2001-04-26 14:38:03 +00:00
SKIP_BLANKS ;
}
2001-02-23 17:55:21 +00:00
}
if ( CUR ! = ' ) ' ) {
if ( name ! = NULL )
xmlFree ( name ) ;
XP_ERROR0 ( XPATH_UNCLOSED_ERROR ) ;
}
NEXT ;
return ( name ) ;
}
* test = NODE_TEST_NAME ;
if ( ( ! blanks ) & & ( CUR = = ' : ' ) ) {
NEXT ;
/*
2001-03-19 15:58:54 +00:00
* Since currently the parser context don ' t have a
* namespace list associated :
* The namespace name for this prefix can be computed
* only at evaluation time . The compilation is done
* outside of any context .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 15:58:54 +00:00
#if 0
2001-02-23 17:55:21 +00:00
* prefix = xmlXPathNsLookup ( ctxt - > context , name ) ;
if ( name ! = NULL )
xmlFree ( name ) ;
if ( * prefix = = NULL ) {
XP_ERROR0 ( XPATH_UNDEF_PREFIX_ERROR ) ;
}
2001-03-19 15:58:54 +00:00
# else
* prefix = name ;
# endif
2001-02-23 17:55:21 +00:00
if ( CUR = = ' * ' ) {
/*
* All elements
*/
NEXT ;
* test = NODE_TEST_ALL ;
return ( NULL ) ;
}
name = xmlXPathParseNCName ( ctxt ) ;
if ( name = = NULL ) {
XP_ERROR0 ( XPATH_EXPR_ERROR ) ;
}
}
return ( name ) ;
}
/**
* xmlXPathIsAxisName :
* @ name : a preparsed name token
*
* [ 6 ] AxisName : : = ' ancestor '
* | ' ancestor - or - self '
* | ' attribute '
* | ' child '
* | ' descendant '
* | ' descendant - or - self '
* | ' following '
* | ' following - sibling '
* | ' namespace '
* | ' parent '
* | ' preceding '
* | ' preceding - sibling '
* | ' self '
*
* Returns the axis or 0
*/
2001-03-24 17:00:36 +00:00
static xmlXPathAxisVal
2001-02-23 17:55:21 +00:00
xmlXPathIsAxisName ( const xmlChar * name ) {
2003-07-31 14:47:38 +00:00
xmlXPathAxisVal ret = ( xmlXPathAxisVal ) 0 ;
2001-02-23 17:55:21 +00:00
switch ( name [ 0 ] ) {
case ' a ' :
if ( xmlStrEqual ( name , BAD_CAST " ancestor " ) )
ret = AXIS_ANCESTOR ;
if ( xmlStrEqual ( name , BAD_CAST " ancestor-or-self " ) )
ret = AXIS_ANCESTOR_OR_SELF ;
if ( xmlStrEqual ( name , BAD_CAST " attribute " ) )
ret = AXIS_ATTRIBUTE ;
break ;
case ' c ' :
if ( xmlStrEqual ( name , BAD_CAST " child " ) )
ret = AXIS_CHILD ;
break ;
case ' d ' :
if ( xmlStrEqual ( name , BAD_CAST " descendant " ) )
ret = AXIS_DESCENDANT ;
if ( xmlStrEqual ( name , BAD_CAST " descendant-or-self " ) )
ret = AXIS_DESCENDANT_OR_SELF ;
break ;
case ' f ' :
if ( xmlStrEqual ( name , BAD_CAST " following " ) )
ret = AXIS_FOLLOWING ;
if ( xmlStrEqual ( name , BAD_CAST " following-sibling " ) )
ret = AXIS_FOLLOWING_SIBLING ;
break ;
case ' n ' :
if ( xmlStrEqual ( name , BAD_CAST " namespace " ) )
ret = AXIS_NAMESPACE ;
break ;
case ' p ' :
if ( xmlStrEqual ( name , BAD_CAST " parent " ) )
ret = AXIS_PARENT ;
if ( xmlStrEqual ( name , BAD_CAST " preceding " ) )
ret = AXIS_PRECEDING ;
if ( xmlStrEqual ( name , BAD_CAST " preceding-sibling " ) )
ret = AXIS_PRECEDING_SIBLING ;
break ;
case ' s ' :
if ( xmlStrEqual ( name , BAD_CAST " self " ) )
ret = AXIS_SELF ;
break ;
}
return ( ret ) ;
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompStep :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 4 ] Step : : = AxisSpecifier NodeTest Predicate *
* | AbbreviatedStep
*
* [ 12 ] AbbreviatedStep : : = ' . ' | ' . . '
*
* [ 5 ] AxisSpecifier : : = AxisName ' : : '
* | AbbreviatedAxisSpecifier
*
* [ 13 ] AbbreviatedAxisSpecifier : : = ' @ ' ?
*
* Modified for XPtr range support as :
*
* [ 4 xptr ] Step : : = AxisSpecifier NodeTest Predicate *
* | AbbreviatedStep
* | ' range - to ' ' ( ' Expr ' ) ' Predicate *
*
2001-03-19 10:57:13 +00:00
* Compile one step in a Location Path
2001-02-23 17:55:21 +00:00
* A location step of . is short for self : : node ( ) . This is
* particularly useful in conjunction with //. For example, the
* location path . //para is short for
* self : : node ( ) / descendant - or - self : : node ( ) / child : : para
* and so will select all para descendant elements of the context
* node .
* Similarly , a location step of . . is short for parent : : node ( ) .
* For example , . . / title is short for parent : : node ( ) / child : : title
* and so will select the title children of the parent of the context
* node .
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompStep ( xmlXPathParserContextPtr ctxt ) {
2001-04-22 19:13:10 +00:00
# ifdef LIBXML_XPTR_ENABLED
int rangeto = 0 ;
int op2 = - 1 ;
# endif
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
if ( ( CUR = = ' . ' ) & & ( NXT ( 1 ) = = ' . ' ) ) {
SKIP ( 2 ) ;
SKIP_BLANKS ;
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_COLLECT , AXIS_PARENT ,
NODE_TEST_TYPE , NODE_TYPE_NODE , NULL , NULL ) ;
2001-02-23 17:55:21 +00:00
} else if ( CUR = = ' . ' ) {
NEXT ;
SKIP_BLANKS ;
} else {
xmlChar * name = NULL ;
const xmlChar * prefix = NULL ;
xmlXPathTestVal test ;
2003-07-31 14:47:38 +00:00
xmlXPathAxisVal axis = ( xmlXPathAxisVal ) 0 ;
2001-02-23 17:55:21 +00:00
xmlXPathTypeVal type ;
2001-04-05 16:54:14 +00:00
int op1 ;
2001-02-23 17:55:21 +00:00
/*
* The modification needed for XPointer change to the production
*/
# ifdef LIBXML_XPTR_ENABLED
2001-03-19 15:58:54 +00:00
if ( ctxt - > xptr ) {
2001-02-23 17:55:21 +00:00
name = xmlXPathParseNCName ( ctxt ) ;
if ( ( name ! = NULL ) & & ( xmlStrEqual ( name , BAD_CAST " range-to " ) ) ) {
2001-04-22 19:13:10 +00:00
op2 = ctxt - > comp - > last ;
2001-02-23 17:55:21 +00:00
xmlFree ( name ) ;
SKIP_BLANKS ;
if ( CUR ! = ' ( ' ) {
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
NEXT ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompileExpr ( ctxt ) ;
2001-04-22 19:13:10 +00:00
/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
2001-02-23 17:55:21 +00:00
CHECK_ERROR ;
SKIP_BLANKS ;
if ( CUR ! = ' ) ' ) {
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
NEXT ;
2001-04-22 19:13:10 +00:00
rangeto = 1 ;
2001-02-23 17:55:21 +00:00
goto eval_predicates ;
}
}
# endif
2001-04-28 12:24:34 +00:00
if ( CUR = = ' * ' ) {
axis = AXIS_CHILD ;
} else {
if ( name = = NULL )
name = xmlXPathParseNCName ( ctxt ) ;
if ( name ! = NULL ) {
axis = xmlXPathIsAxisName ( name ) ;
if ( axis ! = 0 ) {
SKIP_BLANKS ;
if ( ( CUR = = ' : ' ) & & ( NXT ( 1 ) = = ' : ' ) ) {
SKIP ( 2 ) ;
xmlFree ( name ) ;
name = NULL ;
} else {
/* an element name can conflict with an axis one :-\ */
axis = AXIS_CHILD ;
}
2001-02-23 17:55:21 +00:00
} else {
axis = AXIS_CHILD ;
}
2001-04-28 12:24:34 +00:00
} else if ( CUR = = ' @ ' ) {
NEXT ;
axis = AXIS_ATTRIBUTE ;
2001-02-23 17:55:21 +00:00
} else {
2001-04-28 12:24:34 +00:00
axis = AXIS_CHILD ;
2001-02-23 17:55:21 +00:00
}
}
CHECK_ERROR ;
2001-03-19 10:57:13 +00:00
name = xmlXPathCompNodeTest ( ctxt , & test , & type , & prefix , name ) ;
2001-02-23 17:55:21 +00:00
if ( test = = 0 )
return ;
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
" Basis : computing new set \n " ) ;
# endif
2001-03-18 23:17:47 +00:00
2001-02-23 17:55:21 +00:00
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext , " Basis : " ) ;
2001-04-22 19:13:10 +00:00
if ( ctxt - > value = = NULL )
xmlGenericError ( xmlGenericErrorContext , " no value \n " ) ;
else if ( ctxt - > value - > nodesetval = = NULL )
xmlGenericError ( xmlGenericErrorContext , " Empty \n " ) ;
else
xmlGenericErrorContextNodeSet ( stdout , ctxt - > value - > nodesetval ) ;
2001-02-23 17:55:21 +00:00
# endif
eval_predicates :
2001-04-05 16:54:14 +00:00
op1 = ctxt - > comp - > last ;
ctxt - > comp - > last = - 1 ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
while ( CUR = = ' [ ' ) {
2001-04-05 16:54:14 +00:00
xmlXPathCompPredicate ( ctxt , 0 ) ;
2001-02-23 17:55:21 +00:00
}
2001-04-05 16:54:14 +00:00
2001-04-22 19:13:10 +00:00
# ifdef LIBXML_XPTR_ENABLED
if ( rangeto ) {
PUSH_BINARY_EXPR ( XPATH_OP_RANGETO , op2 , op1 , 0 , 0 ) ;
} else
# endif
PUSH_FULL_EXPR ( XPATH_OP_COLLECT , op1 , ctxt - > comp - > last , axis ,
test , type , ( void * ) prefix , ( void * ) name ) ;
2001-04-05 16:54:14 +00:00
2001-02-23 17:55:21 +00:00
}
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext , " Step : " ) ;
2001-04-22 19:13:10 +00:00
if ( ctxt - > value = = NULL )
xmlGenericError ( xmlGenericErrorContext , " no value \n " ) ;
else if ( ctxt - > value - > nodesetval = = NULL )
xmlGenericError ( xmlGenericErrorContext , " Empty \n " ) ;
else
xmlGenericErrorContextNodeSet ( xmlGenericErrorContext ,
ctxt - > value - > nodesetval ) ;
2001-02-23 17:55:21 +00:00
# endif
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompRelativeLocationPath :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 3 ] RelativeLocationPath : : = Step
* | RelativeLocationPath ' / ' Step
* | AbbreviatedRelativeLocationPath
* [ 11 ] AbbreviatedRelativeLocationPath : : = RelativeLocationPath ' //' Step
*
2001-03-19 10:57:13 +00:00
* Compile a relative location path .
2001-02-23 17:55:21 +00:00
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompRelativeLocationPath
2001-02-23 17:55:21 +00:00
( xmlXPathParserContextPtr ctxt ) {
SKIP_BLANKS ;
if ( ( CUR = = ' / ' ) & & ( NXT ( 1 ) = = ' / ' ) ) {
SKIP ( 2 ) ;
SKIP_BLANKS ;
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_COLLECT , AXIS_DESCENDANT_OR_SELF ,
NODE_TEST_TYPE , NODE_TYPE_NODE , NULL , NULL ) ;
2001-02-23 17:55:21 +00:00
} else if ( CUR = = ' / ' ) {
NEXT ;
SKIP_BLANKS ;
}
2001-03-19 10:57:13 +00:00
xmlXPathCompStep ( ctxt ) ;
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
while ( CUR = = ' / ' ) {
if ( ( CUR = = ' / ' ) & & ( NXT ( 1 ) = = ' / ' ) ) {
SKIP ( 2 ) ;
SKIP_BLANKS ;
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_COLLECT , AXIS_DESCENDANT_OR_SELF ,
2001-02-23 17:55:21 +00:00
NODE_TEST_TYPE , NODE_TYPE_NODE , NULL , NULL ) ;
2001-03-19 10:57:13 +00:00
xmlXPathCompStep ( ctxt ) ;
2001-02-23 17:55:21 +00:00
} else if ( CUR = = ' / ' ) {
NEXT ;
SKIP_BLANKS ;
2001-03-19 10:57:13 +00:00
xmlXPathCompStep ( ctxt ) ;
2001-02-23 17:55:21 +00:00
}
SKIP_BLANKS ;
}
}
/**
2001-03-19 10:57:13 +00:00
* xmlXPathCompLocationPath :
2001-02-23 17:55:21 +00:00
* @ ctxt : the XPath Parser context
*
* [ 1 ] LocationPath : : = RelativeLocationPath
* | AbsoluteLocationPath
* [ 2 ] AbsoluteLocationPath : : = ' / ' RelativeLocationPath ?
* | AbbreviatedAbsoluteLocationPath
* [ 10 ] AbbreviatedAbsoluteLocationPath : : =
* ' //' RelativeLocationPath
*
2001-03-19 10:57:13 +00:00
* Compile a location path
*
2001-02-23 17:55:21 +00:00
* // is short for /descendant-or-self::node()/. For example,
* //para is short for /descendant-or-self::node()/child::para and
* so will select any para element in the document ( even a para element
* that is a document element will be selected by //para since the
* document element node is a child of the root node ) ; div //para is
* short for div / descendant - or - self : : node ( ) / child : : para and so will
* select all para descendants of div children .
*/
2001-03-19 10:57:13 +00:00
static void
xmlXPathCompLocationPath ( xmlXPathParserContextPtr ctxt ) {
2001-02-23 17:55:21 +00:00
SKIP_BLANKS ;
if ( CUR ! = ' / ' ) {
2001-03-19 10:57:13 +00:00
xmlXPathCompRelativeLocationPath ( ctxt ) ;
2001-02-23 17:55:21 +00:00
} else {
while ( CUR = = ' / ' ) {
if ( ( CUR = = ' / ' ) & & ( NXT ( 1 ) = = ' / ' ) ) {
SKIP ( 2 ) ;
SKIP_BLANKS ;
2001-03-18 23:17:47 +00:00
PUSH_LONG_EXPR ( XPATH_OP_COLLECT , AXIS_DESCENDANT_OR_SELF ,
NODE_TEST_TYPE , NODE_TYPE_NODE , NULL , NULL ) ;
2001-03-19 10:57:13 +00:00
xmlXPathCompRelativeLocationPath ( ctxt ) ;
2001-02-23 17:55:21 +00:00
} else if ( CUR = = ' / ' ) {
NEXT ;
2001-06-14 08:32:28 +00:00
SKIP_BLANKS ;
if ( ( CUR ! = 0 ) & &
2003-10-18 16:20:14 +00:00
( ( IS_LETTER_CH ( CUR ) ) | | ( CUR = = ' _ ' ) | | ( CUR = = ' . ' ) | |
2001-06-14 08:32:28 +00:00
( CUR = = ' @ ' ) | | ( CUR = = ' * ' ) ) )
2001-03-19 10:57:13 +00:00
xmlXPathCompRelativeLocationPath ( ctxt ) ;
2001-02-23 17:55:21 +00:00
}
}
}
}
2001-03-18 23:17:47 +00:00
/************************************************************************
* *
* XPath precompiled expression evaluation *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-07-03 10:35:50 +00:00
static int
2001-04-05 16:54:14 +00:00
xmlXPathCompOpEval ( xmlXPathParserContextPtr ctxt , xmlXPathStepOpPtr op ) ;
2001-03-18 23:17:47 +00:00
/**
2001-04-05 16:54:14 +00:00
* xmlXPathNodeCollectAndTest :
* @ ctxt : the XPath Parser context
* @ op : the XPath precompiled step operation
2001-07-03 10:35:50 +00:00
* @ first : pointer to the first element in document order
* @ last : pointer to the last element in document order
2001-03-18 23:17:47 +00:00
*
2001-04-05 16:54:14 +00:00
* This is the function implementing a step : based on the current list
* of nodes , it builds up a new list , looking at all nodes under that
* axis and selecting them it also do the predicate filtering
*
* Pushes the new NodeSet resulting from the search .
2001-07-03 10:35:50 +00:00
*
* Returns the number of node traversed
2001-03-18 23:17:47 +00:00
*/
2001-07-03 10:35:50 +00:00
static int
2001-04-05 16:54:14 +00:00
xmlXPathNodeCollectAndTest ( xmlXPathParserContextPtr ctxt ,
2001-07-03 10:35:50 +00:00
xmlXPathStepOpPtr op ,
xmlNodePtr * first , xmlNodePtr * last )
{
2003-07-31 14:47:38 +00:00
xmlXPathAxisVal axis = ( xmlXPathAxisVal ) op - > value ;
xmlXPathTestVal test = ( xmlXPathTestVal ) op - > value2 ;
xmlXPathTypeVal type = ( xmlXPathTypeVal ) op - > value3 ;
2001-04-05 16:54:14 +00:00
const xmlChar * prefix = op - > value4 ;
const xmlChar * name = op - > value5 ;
2001-04-16 14:08:07 +00:00
const xmlChar * URI = NULL ;
2001-03-18 23:17:47 +00:00
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
int n = 0 ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
int i , t = 0 ;
2001-04-05 16:54:14 +00:00
xmlNodeSetPtr ret , list ;
xmlXPathTraversalFunction next = NULL ;
2001-07-03 10:35:50 +00:00
void ( * addNode ) ( xmlNodeSetPtr , xmlNodePtr ) ;
2002-03-13 10:03:35 +00:00
xmlNodeSetPtr ( * mergeNodeSet ) ( xmlNodeSetPtr , xmlNodeSetPtr ) ;
2001-04-05 16:54:14 +00:00
xmlNodePtr cur = NULL ;
xmlXPathObjectPtr obj ;
xmlNodeSetPtr nodelist ;
xmlNodePtr tmp ;
2001-07-03 10:35:50 +00:00
CHECK_TYPE0 ( XPATH_NODESET ) ;
2001-04-05 16:54:14 +00:00
obj = valuePop ( ctxt ) ;
addNode = xmlXPathNodeSetAdd ;
2002-03-13 10:03:35 +00:00
mergeNodeSet = xmlXPathNodeSetMerge ;
2001-04-16 14:08:07 +00:00
if ( prefix ! = NULL ) {
2001-07-03 10:35:50 +00:00
URI = xmlXPathNsLookup ( ctxt - > context , prefix ) ;
if ( URI = = NULL )
XP_ERROR0 ( XPATH_UNDEF_PREFIX_ERROR ) ;
2001-04-16 14:08:07 +00:00
}
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " new step : " ) ;
2001-04-05 16:54:14 +00:00
# endif
switch ( axis ) {
case AXIS_ANCESTOR :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'ancestors' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
next = xmlXPathNextAncestor ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_ANCESTOR_OR_SELF :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext ,
" axis 'ancestors-or-self' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
next = xmlXPathNextAncestorOrSelf ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_ATTRIBUTE :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'attributes' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
last = NULL ;
next = xmlXPathNextAttribute ;
2002-03-13 10:03:35 +00:00
mergeNodeSet = xmlXPathNodeSetMergeUnique ;
2001-07-03 10:35:50 +00:00
break ;
2001-04-05 16:54:14 +00:00
case AXIS_CHILD :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'child' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
last = NULL ;
next = xmlXPathNextChild ;
2002-03-13 10:03:35 +00:00
mergeNodeSet = xmlXPathNodeSetMergeUnique ;
2001-07-03 10:35:50 +00:00
break ;
2001-04-05 16:54:14 +00:00
case AXIS_DESCENDANT :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'descendant' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
last = NULL ;
next = xmlXPathNextDescendant ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_DESCENDANT_OR_SELF :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext ,
" axis 'descendant-or-self' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
last = NULL ;
next = xmlXPathNextDescendantOrSelf ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_FOLLOWING :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'following' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
last = NULL ;
next = xmlXPathNextFollowing ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_FOLLOWING_SIBLING :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext ,
" axis 'following-siblings' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
last = NULL ;
next = xmlXPathNextFollowingSibling ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_NAMESPACE :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'namespace' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
last = NULL ;
next = ( xmlXPathTraversalFunction ) xmlXPathNextNamespace ;
2002-03-13 10:03:35 +00:00
mergeNodeSet = xmlXPathNodeSetMergeUnique ;
2001-07-03 10:35:50 +00:00
break ;
2001-04-05 16:54:14 +00:00
case AXIS_PARENT :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'parent' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
next = xmlXPathNextParent ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_PRECEDING :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'preceding' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
next = xmlXPathNextPrecedingInternal ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_PRECEDING_SIBLING :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext ,
" axis 'preceding-sibling' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
next = xmlXPathNextPrecedingSibling ;
break ;
2001-04-05 16:54:14 +00:00
case AXIS_SELF :
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
xmlGenericError ( xmlGenericErrorContext , " axis 'self' " ) ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
first = NULL ;
last = NULL ;
next = xmlXPathNextSelf ;
2002-03-13 10:03:35 +00:00
mergeNodeSet = xmlXPathNodeSetMergeUnique ;
2001-07-03 10:35:50 +00:00
break ;
2001-04-05 16:54:14 +00:00
}
if ( next = = NULL )
2001-07-03 10:35:50 +00:00
return ( 0 ) ;
2001-04-05 16:54:14 +00:00
nodelist = obj - > nodesetval ;
if ( nodelist = = NULL ) {
2001-07-03 10:35:50 +00:00
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPathWrapNodeSet ( NULL ) ) ;
return ( 0 ) ;
2001-04-05 16:54:14 +00:00
}
addNode = xmlXPathNodeSetAddUnique ;
ret = NULL ;
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
2001-07-03 10:35:50 +00:00
" context contains %d nodes \n " , nodelist - > nodeNr ) ;
2001-04-05 16:54:14 +00:00
switch ( test ) {
2001-07-03 10:35:50 +00:00
case NODE_TEST_NONE :
xmlGenericError ( xmlGenericErrorContext ,
" searching for none !!! \n " ) ;
break ;
case NODE_TEST_TYPE :
xmlGenericError ( xmlGenericErrorContext ,
" searching for type %d \n " , type ) ;
break ;
case NODE_TEST_PI :
xmlGenericError ( xmlGenericErrorContext ,
" searching for PI !!! \n " ) ;
break ;
case NODE_TEST_ALL :
xmlGenericError ( xmlGenericErrorContext ,
" searching for * \n " ) ;
break ;
case NODE_TEST_NS :
xmlGenericError ( xmlGenericErrorContext ,
" searching for namespace %s \n " ,
prefix ) ;
break ;
case NODE_TEST_NAME :
xmlGenericError ( xmlGenericErrorContext ,
" searching for name %s \n " , name ) ;
if ( prefix ! = NULL )
xmlGenericError ( xmlGenericErrorContext ,
" with namespace %s \n " , prefix ) ;
break ;
2001-04-05 16:54:14 +00:00
}
xmlGenericError ( xmlGenericErrorContext , " Testing : " ) ;
# endif
/*
* 2.3 Node Tests
* - For the attribute axis , the principal node type is attribute .
* - For the namespace axis , the principal node type is namespace .
* - For other axes , the principal node type is element .
*
* A node test * is true for any node of the
2001-12-31 16:16:02 +00:00
* principal node type . For example , child : : * will
2001-04-05 16:54:14 +00:00
* select all element children of the context node
*/
tmp = ctxt - > context - > node ;
2001-07-03 10:35:50 +00:00
for ( i = 0 ; i < nodelist - > nodeNr ; i + + ) {
2001-04-05 16:54:14 +00:00
ctxt - > context - > node = nodelist - > nodeTab [ i ] ;
2001-07-03 10:35:50 +00:00
cur = NULL ;
list = xmlXPathNodeSetCreate ( NULL ) ;
do {
cur = next ( ctxt , cur ) ;
if ( cur = = NULL )
break ;
if ( ( first ! = NULL ) & & ( * first = = cur ) )
break ;
if ( ( ( t % 256 ) = = 0 ) & &
( first ! = NULL ) & & ( * first ! = NULL ) & &
( xmlXPathCmpNodes ( * first , cur ) > = 0 ) )
break ;
if ( ( last ! = NULL ) & & ( * last = = cur ) )
break ;
if ( ( ( t % 256 ) = = 0 ) & &
( last ! = NULL ) & & ( * last ! = NULL ) & &
( xmlXPathCmpNodes ( cur , * last ) > = 0 ) )
break ;
2001-04-05 16:54:14 +00:00
t + + ;
2001-07-03 10:35:50 +00:00
# ifdef DEBUG_STEP
2001-04-05 16:54:14 +00:00
xmlGenericError ( xmlGenericErrorContext , " %s " , cur - > name ) ;
# endif
2001-07-03 10:35:50 +00:00
switch ( test ) {
2001-04-05 16:54:14 +00:00
case NODE_TEST_NONE :
2001-07-03 10:35:50 +00:00
ctxt - > context - > node = tmp ;
STRANGE return ( t ) ;
2001-04-05 16:54:14 +00:00
case NODE_TEST_TYPE :
2001-07-03 10:35:50 +00:00
if ( ( cur - > type = = type ) | |
( ( type = = NODE_TYPE_NODE ) & &
( ( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) | |
( cur - > type = = XML_ELEMENT_NODE ) | |
2002-06-04 04:27:06 +00:00
( cur - > type = = XML_NAMESPACE_DECL ) | |
( cur - > type = = XML_ATTRIBUTE_NODE ) | |
2001-07-03 10:35:50 +00:00
( cur - > type = = XML_PI_NODE ) | |
( cur - > type = = XML_COMMENT_NODE ) | |
( cur - > type = = XML_CDATA_SECTION_NODE ) | |
2001-07-08 13:15:55 +00:00
( cur - > type = = XML_TEXT_NODE ) ) ) | |
( ( type = = NODE_TYPE_TEXT ) & &
( cur - > type = = XML_CDATA_SECTION_NODE ) ) ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
n + + ;
# endif
2001-07-03 10:35:50 +00:00
addNode ( list , cur ) ;
}
break ;
2001-04-05 16:54:14 +00:00
case NODE_TEST_PI :
2001-07-03 10:35:50 +00:00
if ( cur - > type = = XML_PI_NODE ) {
if ( ( name ! = NULL ) & &
( ! xmlStrEqual ( name , cur - > name ) ) )
break ;
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list , cur ) ;
}
break ;
2001-04-05 16:54:14 +00:00
case NODE_TEST_ALL :
2001-07-03 10:35:50 +00:00
if ( axis = = AXIS_ATTRIBUTE ) {
if ( cur - > type = = XML_ATTRIBUTE_NODE ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list , cur ) ;
}
} else if ( axis = = AXIS_NAMESPACE ) {
if ( cur - > type = = XML_NAMESPACE_DECL ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2002-03-04 17:09:44 +00:00
xmlXPathNodeSetAddNs ( list , ctxt - > context - > node ,
( xmlNsPtr ) cur ) ;
2001-07-03 10:35:50 +00:00
}
} else {
if ( cur - > type = = XML_ELEMENT_NODE ) {
if ( prefix = = NULL ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list , cur ) ;
} else if ( ( cur - > ns ! = NULL ) & &
( xmlStrEqual ( URI , cur - > ns - > href ) ) ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list , cur ) ;
}
}
}
break ;
case NODE_TEST_NS : {
TODO ;
break ;
}
2001-04-05 16:54:14 +00:00
case NODE_TEST_NAME :
2001-07-03 10:35:50 +00:00
switch ( cur - > type ) {
case XML_ELEMENT_NODE :
if ( xmlStrEqual ( name , cur - > name ) ) {
if ( prefix = = NULL ) {
if ( cur - > ns = = NULL ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list , cur ) ;
}
} else {
if ( ( cur - > ns ! = NULL ) & &
( xmlStrEqual ( URI ,
cur - > ns - > href ) ) ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list , cur ) ;
}
}
}
break ;
case XML_ATTRIBUTE_NODE : {
xmlAttrPtr attr = ( xmlAttrPtr ) cur ;
if ( xmlStrEqual ( name , attr - > name ) ) {
if ( prefix = = NULL ) {
if ( ( attr - > ns = = NULL ) | |
( attr - > ns - > prefix = = NULL ) ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list ,
( xmlNodePtr ) attr ) ;
}
} else {
if ( ( attr - > ns ! = NULL ) & &
( xmlStrEqual ( URI ,
attr - > ns - >
href ) ) ) {
2001-04-05 16:54:14 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-04-05 16:54:14 +00:00
# endif
2001-07-03 10:35:50 +00:00
addNode ( list ,
( xmlNodePtr ) attr ) ;
}
}
}
break ;
}
case XML_NAMESPACE_DECL :
if ( cur - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns = ( xmlNsPtr ) cur ;
if ( ( ns - > prefix ! = NULL ) & & ( name ! = NULL )
& & ( xmlStrEqual ( ns - > prefix , name ) ) ) {
2001-06-16 21:24:56 +00:00
# ifdef DEBUG_STEP
2001-07-03 10:35:50 +00:00
n + + ;
2001-06-16 21:24:56 +00:00
# endif
2002-03-04 17:09:44 +00:00
xmlXPathNodeSetAddNs ( list ,
ctxt - > context - > node , ( xmlNsPtr ) cur ) ;
2001-07-03 10:35:50 +00:00
}
}
break ;
default :
break ;
}
break ;
break ;
}
} while ( cur ! = NULL ) ;
/*
* If there is some predicate filtering do it now
*/
2002-03-21 12:32:59 +00:00
if ( ( op - > ch2 ! = - 1 ) & & ( list ! = NULL ) & & ( list - > nodeNr > 0 ) ) {
2001-07-03 10:35:50 +00:00
xmlXPathObjectPtr obj2 ;
valuePush ( ctxt , xmlXPathWrapNodeSet ( list ) ) ;
xmlXPathCompOpEval ( ctxt , & ctxt - > comp - > steps [ op - > ch2 ] ) ;
CHECK_TYPE0 ( XPATH_NODESET ) ;
obj2 = valuePop ( ctxt ) ;
list = obj2 - > nodesetval ;
obj2 - > nodesetval = NULL ;
xmlXPathFreeObject ( obj2 ) ;
}
if ( ret = = NULL ) {
ret = list ;
} else {
2002-03-13 10:03:35 +00:00
ret = mergeNodeSet ( ret , list ) ;
2001-07-03 10:35:50 +00:00
xmlXPathFreeNodeSet ( list ) ;
}
2001-04-05 16:54:14 +00:00
}
ctxt - > context - > node = tmp ;
# ifdef DEBUG_STEP
xmlGenericError ( xmlGenericErrorContext ,
2001-07-03 10:35:50 +00:00
" \n Examined %d nodes, found %d nodes at that step \n " ,
t , n ) ;
2001-04-05 16:54:14 +00:00
# endif
valuePush ( ctxt , xmlXPathWrapNodeSet ( ret ) ) ;
2001-08-14 16:43:10 +00:00
if ( ( obj - > boolval ) & & ( obj - > user ! = NULL ) ) {
ctxt - > value - > boolval = 1 ;
ctxt - > value - > user = obj - > user ;
obj - > user = NULL ;
obj - > boolval = 0 ;
}
xmlXPathFreeObject ( obj ) ;
2001-07-03 10:35:50 +00:00
return ( t ) ;
2001-04-05 16:54:14 +00:00
}
/**
2001-07-03 10:35:50 +00:00
* xmlXPathNodeCollectAndTestNth :
* @ ctxt : the XPath Parser context
* @ op : the XPath precompiled step operation
* @ indx : the index to collect
* @ first : pointer to the first element in document order
* @ last : pointer to the last element in document order
*
* This is the function implementing a step : based on the current list
* of nodes , it builds up a new list , looking at all nodes under that
* axis and selecting them it also do the predicate filtering
*
* Pushes the new NodeSet resulting from the search .
* Returns the number of node traversed
*/
static int
xmlXPathNodeCollectAndTestNth ( xmlXPathParserContextPtr ctxt ,
xmlXPathStepOpPtr op , int indx ,
xmlNodePtr * first , xmlNodePtr * last )
{
2003-07-31 14:47:38 +00:00
xmlXPathAxisVal axis = ( xmlXPathAxisVal ) op - > value ;
xmlXPathTestVal test = ( xmlXPathTestVal ) op - > value2 ;
xmlXPathTypeVal type = ( xmlXPathTypeVal ) op - > value3 ;
2001-07-03 10:35:50 +00:00
const xmlChar * prefix = op - > value4 ;
const xmlChar * name = op - > value5 ;
const xmlChar * URI = NULL ;
int n = 0 , t = 0 ;
int i ;
xmlNodeSetPtr list ;
xmlXPathTraversalFunction next = NULL ;
void ( * addNode ) ( xmlNodeSetPtr , xmlNodePtr ) ;
xmlNodePtr cur = NULL ;
xmlXPathObjectPtr obj ;
xmlNodeSetPtr nodelist ;
xmlNodePtr tmp ;
CHECK_TYPE0 ( XPATH_NODESET ) ;
obj = valuePop ( ctxt ) ;
addNode = xmlXPathNodeSetAdd ;
if ( prefix ! = NULL ) {
URI = xmlXPathNsLookup ( ctxt - > context , prefix ) ;
if ( URI = = NULL )
XP_ERROR0 ( XPATH_UNDEF_PREFIX_ERROR ) ;
}
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " new step : " ) ;
if ( first ! = NULL ) {
if ( * first ! = NULL )
xmlGenericError ( xmlGenericErrorContext , " first = %s " ,
( * first ) - > name ) ;
else
xmlGenericError ( xmlGenericErrorContext , " first = NULL " ) ;
}
if ( last ! = NULL ) {
if ( * last ! = NULL )
xmlGenericError ( xmlGenericErrorContext , " last = %s " ,
( * last ) - > name ) ;
else
xmlGenericError ( xmlGenericErrorContext , " last = NULL " ) ;
}
# endif
switch ( axis ) {
case AXIS_ANCESTOR :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'ancestors' " ) ;
# endif
first = NULL ;
next = xmlXPathNextAncestor ;
break ;
case AXIS_ANCESTOR_OR_SELF :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext ,
" axis 'ancestors-or-self' " ) ;
# endif
first = NULL ;
next = xmlXPathNextAncestorOrSelf ;
break ;
case AXIS_ATTRIBUTE :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'attributes' " ) ;
# endif
first = NULL ;
last = NULL ;
next = xmlXPathNextAttribute ;
break ;
case AXIS_CHILD :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'child' " ) ;
# endif
last = NULL ;
next = xmlXPathNextChild ;
break ;
case AXIS_DESCENDANT :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'descendant' " ) ;
# endif
last = NULL ;
next = xmlXPathNextDescendant ;
break ;
case AXIS_DESCENDANT_OR_SELF :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext ,
" axis 'descendant-or-self' " ) ;
# endif
last = NULL ;
next = xmlXPathNextDescendantOrSelf ;
break ;
case AXIS_FOLLOWING :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'following' " ) ;
# endif
last = NULL ;
next = xmlXPathNextFollowing ;
break ;
case AXIS_FOLLOWING_SIBLING :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext ,
" axis 'following-siblings' " ) ;
# endif
last = NULL ;
next = xmlXPathNextFollowingSibling ;
break ;
case AXIS_NAMESPACE :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'namespace' " ) ;
# endif
last = NULL ;
first = NULL ;
next = ( xmlXPathTraversalFunction ) xmlXPathNextNamespace ;
break ;
case AXIS_PARENT :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'parent' " ) ;
# endif
first = NULL ;
next = xmlXPathNextParent ;
break ;
case AXIS_PRECEDING :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'preceding' " ) ;
# endif
first = NULL ;
next = xmlXPathNextPrecedingInternal ;
break ;
case AXIS_PRECEDING_SIBLING :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext ,
" axis 'preceding-sibling' " ) ;
# endif
first = NULL ;
next = xmlXPathNextPrecedingSibling ;
break ;
case AXIS_SELF :
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext , " axis 'self' " ) ;
# endif
first = NULL ;
last = NULL ;
next = xmlXPathNextSelf ;
break ;
}
if ( next = = NULL )
return ( 0 ) ;
nodelist = obj - > nodesetval ;
if ( nodelist = = NULL ) {
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPathWrapNodeSet ( NULL ) ) ;
return ( 0 ) ;
}
addNode = xmlXPathNodeSetAddUnique ;
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext ,
" context contains %d nodes \n " , nodelist - > nodeNr ) ;
switch ( test ) {
case NODE_TEST_NONE :
xmlGenericError ( xmlGenericErrorContext ,
" searching for none !!! \n " ) ;
break ;
case NODE_TEST_TYPE :
xmlGenericError ( xmlGenericErrorContext ,
" searching for type %d \n " , type ) ;
break ;
case NODE_TEST_PI :
xmlGenericError ( xmlGenericErrorContext ,
" searching for PI !!! \n " ) ;
break ;
case NODE_TEST_ALL :
xmlGenericError ( xmlGenericErrorContext ,
" searching for * \n " ) ;
break ;
case NODE_TEST_NS :
xmlGenericError ( xmlGenericErrorContext ,
" searching for namespace %s \n " ,
prefix ) ;
break ;
case NODE_TEST_NAME :
xmlGenericError ( xmlGenericErrorContext ,
" searching for name %s \n " , name ) ;
if ( prefix ! = NULL )
xmlGenericError ( xmlGenericErrorContext ,
" with namespace %s \n " , prefix ) ;
break ;
}
xmlGenericError ( xmlGenericErrorContext , " Testing : " ) ;
# endif
/*
* 2.3 Node Tests
* - For the attribute axis , the principal node type is attribute .
* - For the namespace axis , the principal node type is namespace .
* - For other axes , the principal node type is element .
*
* A node test * is true for any node of the
2001-12-31 16:16:02 +00:00
* principal node type . For example , child : : * will
2001-07-03 10:35:50 +00:00
* select all element children of the context node
*/
tmp = ctxt - > context - > node ;
list = xmlXPathNodeSetCreate ( NULL ) ;
for ( i = 0 ; i < nodelist - > nodeNr ; i + + ) {
ctxt - > context - > node = nodelist - > nodeTab [ i ] ;
cur = NULL ;
n = 0 ;
do {
cur = next ( ctxt , cur ) ;
if ( cur = = NULL )
break ;
if ( ( first ! = NULL ) & & ( * first = = cur ) )
break ;
if ( ( ( t % 256 ) = = 0 ) & &
( first ! = NULL ) & & ( * first ! = NULL ) & &
( xmlXPathCmpNodes ( * first , cur ) > = 0 ) )
break ;
if ( ( last ! = NULL ) & & ( * last = = cur ) )
break ;
if ( ( ( t % 256 ) = = 0 ) & &
( last ! = NULL ) & & ( * last ! = NULL ) & &
( xmlXPathCmpNodes ( cur , * last ) > = 0 ) )
break ;
t + + ;
switch ( test ) {
case NODE_TEST_NONE :
ctxt - > context - > node = tmp ;
STRANGE return ( 0 ) ;
case NODE_TEST_TYPE :
if ( ( cur - > type = = type ) | |
( ( type = = NODE_TYPE_NODE ) & &
( ( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) | |
( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_PI_NODE ) | |
( cur - > type = = XML_COMMENT_NODE ) | |
( cur - > type = = XML_CDATA_SECTION_NODE ) | |
2002-11-12 12:36:52 +00:00
( cur - > type = = XML_TEXT_NODE ) ) ) | |
( ( type = = NODE_TYPE_TEXT ) & &
( cur - > type = = XML_CDATA_SECTION_NODE ) ) ) {
2001-07-03 10:35:50 +00:00
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
break ;
case NODE_TEST_PI :
if ( cur - > type = = XML_PI_NODE ) {
if ( ( name ! = NULL ) & &
( ! xmlStrEqual ( name , cur - > name ) ) )
break ;
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
break ;
case NODE_TEST_ALL :
if ( axis = = AXIS_ATTRIBUTE ) {
if ( cur - > type = = XML_ATTRIBUTE_NODE ) {
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
} else if ( axis = = AXIS_NAMESPACE ) {
if ( cur - > type = = XML_NAMESPACE_DECL ) {
n + + ;
if ( n = = indx )
2002-03-04 17:09:44 +00:00
xmlXPathNodeSetAddNs ( list , ctxt - > context - > node ,
( xmlNsPtr ) cur ) ;
2001-07-03 10:35:50 +00:00
}
} else {
if ( cur - > type = = XML_ELEMENT_NODE ) {
if ( prefix = = NULL ) {
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
} else if ( ( cur - > ns ! = NULL ) & &
( xmlStrEqual ( URI , cur - > ns - > href ) ) ) {
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
}
}
break ;
case NODE_TEST_NS : {
TODO ;
break ;
}
case NODE_TEST_NAME :
switch ( cur - > type ) {
case XML_ELEMENT_NODE :
if ( xmlStrEqual ( name , cur - > name ) ) {
if ( prefix = = NULL ) {
if ( cur - > ns = = NULL ) {
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
} else {
if ( ( cur - > ns ! = NULL ) & &
( xmlStrEqual ( URI ,
cur - > ns - > href ) ) ) {
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
}
}
break ;
case XML_ATTRIBUTE_NODE : {
xmlAttrPtr attr = ( xmlAttrPtr ) cur ;
if ( xmlStrEqual ( name , attr - > name ) ) {
if ( prefix = = NULL ) {
if ( ( attr - > ns = = NULL ) | |
( attr - > ns - > prefix = = NULL ) ) {
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
} else {
if ( ( attr - > ns ! = NULL ) & &
( xmlStrEqual ( URI ,
attr - > ns - >
href ) ) ) {
n + + ;
if ( n = = indx )
addNode ( list , cur ) ;
}
}
}
break ;
}
case XML_NAMESPACE_DECL :
if ( cur - > type = = XML_NAMESPACE_DECL ) {
xmlNsPtr ns = ( xmlNsPtr ) cur ;
if ( ( ns - > prefix ! = NULL ) & & ( name ! = NULL )
& & ( xmlStrEqual ( ns - > prefix , name ) ) ) {
n + + ;
if ( n = = indx )
2002-03-04 17:09:44 +00:00
xmlXPathNodeSetAddNs ( list ,
ctxt - > context - > node , ( xmlNsPtr ) cur ) ;
2001-07-03 10:35:50 +00:00
}
}
break ;
default :
break ;
}
break ;
break ;
}
} while ( n < indx ) ;
}
ctxt - > context - > node = tmp ;
# ifdef DEBUG_STEP_NTH
xmlGenericError ( xmlGenericErrorContext ,
" \n Examined %d nodes, found %d nodes at that step \n " ,
t , list - > nodeNr ) ;
# endif
valuePush ( ctxt , xmlXPathWrapNodeSet ( list ) ) ;
2001-08-14 16:43:10 +00:00
if ( ( obj - > boolval ) & & ( obj - > user ! = NULL ) ) {
ctxt - > value - > boolval = 1 ;
ctxt - > value - > user = obj - > user ;
obj - > user = NULL ;
obj - > boolval = 0 ;
}
xmlXPathFreeObject ( obj ) ;
2001-07-03 10:35:50 +00:00
return ( t ) ;
}
/**
* xmlXPathCompOpEvalFirst :
2001-04-05 16:54:14 +00:00
* @ ctxt : the XPath parser context with the compiled expression
* @ op : an XPath compiled operation
2001-07-03 10:35:50 +00:00
* @ first : the first elem found so far
2001-04-05 16:54:14 +00:00
*
2001-07-03 10:35:50 +00:00
* Evaluate the Precompiled XPath operation searching only the first
* element in document order
*
* Returns the number of examined objects .
2001-04-05 16:54:14 +00:00
*/
2001-07-03 10:35:50 +00:00
static int
xmlXPathCompOpEvalFirst ( xmlXPathParserContextPtr ctxt ,
xmlXPathStepOpPtr op , xmlNodePtr * first )
{
int total = 0 , cur ;
2001-04-05 16:54:14 +00:00
xmlXPathCompExprPtr comp ;
xmlXPathObjectPtr arg1 , arg2 ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-04-05 16:54:14 +00:00
comp = ctxt - > comp ;
switch ( op - > op ) {
2001-07-03 10:35:50 +00:00
case XPATH_OP_END :
return ( 0 ) ;
case XPATH_OP_UNION :
total =
xmlXPathCompOpEvalFirst ( ctxt , & comp - > steps [ op - > ch1 ] ,
first ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( ( ctxt - > value ! = NULL )
& & ( ctxt - > value - > type = = XPATH_NODESET )
& & ( ctxt - > value - > nodesetval ! = NULL )
& & ( ctxt - > value - > nodesetval - > nodeNr > = 1 ) ) {
/*
* limit tree traversing to first node in the result
*/
xmlXPathNodeSetSort ( ctxt - > value - > nodesetval ) ;
* first = ctxt - > value - > nodesetval - > nodeTab [ 0 ] ;
}
cur =
xmlXPathCompOpEvalFirst ( ctxt , & comp - > steps [ op - > ch2 ] ,
first ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
CHECK_TYPE0 ( XPATH_NODESET ) ;
arg2 = valuePop ( ctxt ) ;
CHECK_TYPE0 ( XPATH_NODESET ) ;
arg1 = valuePop ( ctxt ) ;
arg1 - > nodesetval = xmlXPathNodeSetMerge ( arg1 - > nodesetval ,
arg2 - > nodesetval ) ;
valuePush ( ctxt , arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
/* optimizer */
if ( total > cur )
xmlXPathCompSwap ( op ) ;
return ( total + cur ) ;
case XPATH_OP_ROOT :
xmlXPathRoot ( ctxt ) ;
return ( 0 ) ;
case XPATH_OP_NODE :
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
valuePush ( ctxt , xmlXPathNewNodeSet ( ctxt - > context - > node ) ) ;
return ( total ) ;
case XPATH_OP_RESET :
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
ctxt - > context - > node = NULL ;
return ( total ) ;
case XPATH_OP_COLLECT : {
if ( op - > ch1 = = - 1 )
return ( total ) ;
total = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
/*
* Optimization for [ n ] selection where n is a number
*/
if ( ( op - > ch2 ! = - 1 ) & &
( comp - > steps [ op - > ch2 ] . op = = XPATH_OP_PREDICATE ) & &
( comp - > steps [ op - > ch2 ] . ch1 = = - 1 ) & &
( comp - > steps [ op - > ch2 ] . ch2 ! = - 1 ) & &
( comp - > steps [ comp - > steps [ op - > ch2 ] . ch2 ] . op = =
XPATH_OP_VALUE ) ) {
xmlXPathObjectPtr val ;
val = comp - > steps [ comp - > steps [ op - > ch2 ] . ch2 ] . value4 ;
if ( ( val ! = NULL ) & & ( val - > type = = XPATH_NUMBER ) ) {
int indx = ( int ) val - > floatval ;
if ( val - > floatval = = ( float ) indx ) {
xmlXPathNodeCollectAndTestNth ( ctxt , op , indx ,
first , NULL ) ;
return ( total ) ;
}
}
}
total + = xmlXPathNodeCollectAndTest ( ctxt , op , first , NULL ) ;
return ( total ) ;
}
case XPATH_OP_VALUE :
valuePush ( ctxt ,
xmlXPathObjectCopy ( ( xmlXPathObjectPtr ) op - > value4 ) ) ;
return ( 0 ) ;
case XPATH_OP_SORT :
if ( op - > ch1 ! = - 1 )
total + =
xmlXPathCompOpEvalFirst ( ctxt , & comp - > steps [ op - > ch1 ] ,
first ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( ( ctxt - > value ! = NULL )
& & ( ctxt - > value - > type = = XPATH_NODESET )
& & ( ctxt - > value - > nodesetval ! = NULL ) )
xmlXPathNodeSetSort ( ctxt - > value - > nodesetval ) ;
return ( total ) ;
default :
return ( xmlXPathCompOpEval ( ctxt , op ) ) ;
}
}
2001-05-22 16:57:14 +00:00
2001-07-03 10:35:50 +00:00
/**
* xmlXPathCompOpEvalLast :
* @ ctxt : the XPath parser context with the compiled expression
* @ op : an XPath compiled operation
* @ last : the last elem found so far
*
* Evaluate the Precompiled XPath operation searching only the last
* element in document order
*
* Returns the number of node traversed
*/
static int
xmlXPathCompOpEvalLast ( xmlXPathParserContextPtr ctxt , xmlXPathStepOpPtr op ,
xmlNodePtr * last )
{
int total = 0 , cur ;
xmlXPathCompExprPtr comp ;
xmlXPathObjectPtr arg1 , arg2 ;
2001-03-18 23:17:47 +00:00
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
comp = ctxt - > comp ;
switch ( op - > op ) {
case XPATH_OP_END :
return ( 0 ) ;
case XPATH_OP_UNION :
total =
xmlXPathCompOpEvalLast ( ctxt , & comp - > steps [ op - > ch1 ] , last ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( ( ctxt - > value ! = NULL )
& & ( ctxt - > value - > type = = XPATH_NODESET )
& & ( ctxt - > value - > nodesetval ! = NULL )
& & ( ctxt - > value - > nodesetval - > nodeNr > = 1 ) ) {
/*
* limit tree traversing to first node in the result
*/
xmlXPathNodeSetSort ( ctxt - > value - > nodesetval ) ;
* last =
ctxt - > value - > nodesetval - > nodeTab [ ctxt - > value - >
nodesetval - > nodeNr -
1 ] ;
}
cur =
xmlXPathCompOpEvalLast ( ctxt , & comp - > steps [ op - > ch2 ] , last ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( ( ctxt - > value ! = NULL )
& & ( ctxt - > value - > type = = XPATH_NODESET )
& & ( ctxt - > value - > nodesetval ! = NULL )
& & ( ctxt - > value - > nodesetval - > nodeNr > = 1 ) ) {
}
CHECK_TYPE0 ( XPATH_NODESET ) ;
arg2 = valuePop ( ctxt ) ;
CHECK_TYPE0 ( XPATH_NODESET ) ;
arg1 = valuePop ( ctxt ) ;
arg1 - > nodesetval = xmlXPathNodeSetMerge ( arg1 - > nodesetval ,
arg2 - > nodesetval ) ;
valuePush ( ctxt , arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
/* optimizer */
if ( total > cur )
xmlXPathCompSwap ( op ) ;
return ( total + cur ) ;
case XPATH_OP_ROOT :
xmlXPathRoot ( ctxt ) ;
return ( 0 ) ;
case XPATH_OP_NODE :
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
valuePush ( ctxt , xmlXPathNewNodeSet ( ctxt - > context - > node ) ) ;
return ( total ) ;
case XPATH_OP_RESET :
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
ctxt - > context - > node = NULL ;
return ( total ) ;
case XPATH_OP_COLLECT : {
if ( op - > ch1 = = - 1 )
return ( 0 ) ;
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
/*
* Optimization for [ n ] selection where n is a number
*/
if ( ( op - > ch2 ! = - 1 ) & &
( comp - > steps [ op - > ch2 ] . op = = XPATH_OP_PREDICATE ) & &
( comp - > steps [ op - > ch2 ] . ch1 = = - 1 ) & &
( comp - > steps [ op - > ch2 ] . ch2 ! = - 1 ) & &
( comp - > steps [ comp - > steps [ op - > ch2 ] . ch2 ] . op = =
XPATH_OP_VALUE ) ) {
xmlXPathObjectPtr val ;
val = comp - > steps [ comp - > steps [ op - > ch2 ] . ch2 ] . value4 ;
if ( ( val ! = NULL ) & & ( val - > type = = XPATH_NUMBER ) ) {
int indx = ( int ) val - > floatval ;
if ( val - > floatval = = ( float ) indx ) {
total + =
xmlXPathNodeCollectAndTestNth ( ctxt , op ,
indx , NULL ,
last ) ;
return ( total ) ;
}
}
}
total + = xmlXPathNodeCollectAndTest ( ctxt , op , NULL , last ) ;
return ( total ) ;
}
case XPATH_OP_VALUE :
valuePush ( ctxt ,
xmlXPathObjectCopy ( ( xmlXPathObjectPtr ) op - > value4 ) ) ;
return ( 0 ) ;
case XPATH_OP_SORT :
if ( op - > ch1 ! = - 1 )
total + =
xmlXPathCompOpEvalLast ( ctxt , & comp - > steps [ op - > ch1 ] ,
last ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( ( ctxt - > value ! = NULL )
& & ( ctxt - > value - > type = = XPATH_NODESET )
& & ( ctxt - > value - > nodesetval ! = NULL ) )
xmlXPathNodeSetSort ( ctxt - > value - > nodesetval ) ;
return ( total ) ;
default :
return ( xmlXPathCompOpEval ( ctxt , op ) ) ;
}
}
2001-03-18 23:17:47 +00:00
2001-07-03 10:35:50 +00:00
/**
* xmlXPathCompOpEval :
* @ ctxt : the XPath parser context with the compiled expression
* @ op : an XPath compiled operation
*
* Evaluate the Precompiled XPath operation
* Returns the number of node traversed
*/
static int
xmlXPathCompOpEval ( xmlXPathParserContextPtr ctxt , xmlXPathStepOpPtr op )
{
int total = 0 ;
int equal , ret ;
xmlXPathCompExprPtr comp ;
xmlXPathObjectPtr arg1 , arg2 ;
2002-03-29 17:28:10 +00:00
xmlNodePtr bak ;
xmlDocPtr bakd ;
2002-06-28 11:43:13 +00:00
int pp ;
2002-06-28 15:01:24 +00:00
int cs ;
2001-03-18 23:17:47 +00:00
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
comp = ctxt - > comp ;
switch ( op - > op ) {
case XPATH_OP_END :
return ( 0 ) ;
case XPATH_OP_AND :
2002-03-29 17:28:10 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2002-06-28 11:43:13 +00:00
pp = ctxt - > context - > proximityPosition ;
2002-06-28 15:01:24 +00:00
cs = ctxt - > context - > contextSize ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
xmlXPathBooleanFunction ( ctxt , 1 ) ;
if ( ( ctxt - > value = = NULL ) | | ( ctxt - > value - > boolval = = 0 ) )
return ( total ) ;
arg2 = valuePop ( ctxt ) ;
2002-03-29 17:28:10 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2002-06-28 11:43:13 +00:00
ctxt - > context - > proximityPosition = pp ;
2002-06-28 15:01:24 +00:00
ctxt - > context - > contextSize = cs ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
if ( ctxt - > error ) {
xmlXPathFreeObject ( arg2 ) ;
return ( 0 ) ;
}
2001-07-03 10:35:50 +00:00
xmlXPathBooleanFunction ( ctxt , 1 ) ;
arg1 = valuePop ( ctxt ) ;
arg1 - > boolval & = arg2 - > boolval ;
valuePush ( ctxt , arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
return ( total ) ;
case XPATH_OP_OR :
2002-03-29 17:28:10 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2002-06-28 11:43:13 +00:00
pp = ctxt - > context - > proximityPosition ;
2002-06-28 15:01:24 +00:00
cs = ctxt - > context - > contextSize ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
xmlXPathBooleanFunction ( ctxt , 1 ) ;
if ( ( ctxt - > value = = NULL ) | | ( ctxt - > value - > boolval = = 1 ) )
return ( total ) ;
arg2 = valuePop ( ctxt ) ;
2002-03-29 17:28:10 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2002-06-28 11:43:13 +00:00
ctxt - > context - > proximityPosition = pp ;
2002-06-28 15:01:24 +00:00
ctxt - > context - > contextSize = cs ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
if ( ctxt - > error ) {
xmlXPathFreeObject ( arg2 ) ;
return ( 0 ) ;
}
2001-07-03 10:35:50 +00:00
xmlXPathBooleanFunction ( ctxt , 1 ) ;
arg1 = valuePop ( ctxt ) ;
arg1 - > boolval | = arg2 - > boolval ;
valuePush ( ctxt , arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
return ( total ) ;
case XPATH_OP_EQUAL :
2002-03-29 17:28:10 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2002-06-28 11:43:13 +00:00
pp = ctxt - > context - > proximityPosition ;
2002-06-28 15:01:24 +00:00
cs = ctxt - > context - > contextSize ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2002-03-29 17:28:10 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2002-06-28 11:43:13 +00:00
ctxt - > context - > proximityPosition = pp ;
2002-06-28 15:01:24 +00:00
ctxt - > context - > contextSize = cs ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2002-07-12 00:56:01 +00:00
if ( op - > value )
equal = xmlXPathEqualValues ( ctxt ) ;
else
equal = xmlXPathNotEqualValues ( ctxt ) ;
valuePush ( ctxt , xmlXPathNewBoolean ( equal ) ) ;
2001-07-03 10:35:50 +00:00
return ( total ) ;
case XPATH_OP_CMP :
2002-03-29 17:28:10 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2002-06-28 11:43:13 +00:00
pp = ctxt - > context - > proximityPosition ;
2002-06-28 15:01:24 +00:00
cs = ctxt - > context - > contextSize ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2002-03-29 17:28:10 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2002-06-28 11:43:13 +00:00
ctxt - > context - > proximityPosition = pp ;
2002-06-28 15:01:24 +00:00
ctxt - > context - > contextSize = cs ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
ret = xmlXPathCompareValues ( ctxt , op - > value , op - > value2 ) ;
valuePush ( ctxt , xmlXPathNewBoolean ( ret ) ) ;
return ( total ) ;
case XPATH_OP_PLUS :
2002-03-29 17:28:10 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2002-06-28 11:43:13 +00:00
pp = ctxt - > context - > proximityPosition ;
2002-06-28 15:01:24 +00:00
cs = ctxt - > context - > contextSize ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2002-03-29 17:28:10 +00:00
if ( op - > ch2 ! = - 1 ) {
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2002-06-28 11:43:13 +00:00
ctxt - > context - > proximityPosition = pp ;
2002-06-28 15:01:24 +00:00
ctxt - > context - > contextSize = cs ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2002-03-29 17:28:10 +00:00
}
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > value = = 0 )
xmlXPathSubValues ( ctxt ) ;
else if ( op - > value = = 1 )
xmlXPathAddValues ( ctxt ) ;
else if ( op - > value = = 2 )
xmlXPathValueFlipSign ( ctxt ) ;
else if ( op - > value = = 3 ) {
CAST_TO_NUMBER ;
CHECK_TYPE0 ( XPATH_NUMBER ) ;
}
return ( total ) ;
case XPATH_OP_MULT :
2002-03-29 17:28:10 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2002-06-28 11:43:13 +00:00
pp = ctxt - > context - > proximityPosition ;
2002-06-28 15:01:24 +00:00
cs = ctxt - > context - > contextSize ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2002-03-29 17:28:10 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2002-06-28 11:43:13 +00:00
ctxt - > context - > proximityPosition = pp ;
2002-06-28 15:01:24 +00:00
ctxt - > context - > contextSize = cs ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > value = = 0 )
xmlXPathMultValues ( ctxt ) ;
else if ( op - > value = = 1 )
xmlXPathDivValues ( ctxt ) ;
else if ( op - > value = = 2 )
xmlXPathModValues ( ctxt ) ;
return ( total ) ;
case XPATH_OP_UNION :
2002-03-29 17:28:10 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2002-06-28 11:43:13 +00:00
pp = ctxt - > context - > proximityPosition ;
2002-06-28 15:01:24 +00:00
cs = ctxt - > context - > contextSize ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2002-03-29 17:28:10 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2002-06-28 11:43:13 +00:00
ctxt - > context - > proximityPosition = pp ;
2002-06-28 15:01:24 +00:00
ctxt - > context - > contextSize = cs ;
2001-07-03 10:35:50 +00:00
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
CHECK_TYPE0 ( XPATH_NODESET ) ;
arg2 = valuePop ( ctxt ) ;
CHECK_TYPE0 ( XPATH_NODESET ) ;
arg1 = valuePop ( ctxt ) ;
arg1 - > nodesetval = xmlXPathNodeSetMerge ( arg1 - > nodesetval ,
arg2 - > nodesetval ) ;
valuePush ( ctxt , arg1 ) ;
xmlXPathFreeObject ( arg2 ) ;
return ( total ) ;
case XPATH_OP_ROOT :
xmlXPathRoot ( ctxt ) ;
return ( total ) ;
case XPATH_OP_NODE :
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
valuePush ( ctxt , xmlXPathNewNodeSet ( ctxt - > context - > node ) ) ;
return ( total ) ;
case XPATH_OP_RESET :
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
ctxt - > context - > node = NULL ;
return ( total ) ;
case XPATH_OP_COLLECT : {
if ( op - > ch1 = = - 1 )
return ( total ) ;
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
/*
* Optimization for [ n ] selection where n is a number
*/
if ( ( op - > ch2 ! = - 1 ) & &
( comp - > steps [ op - > ch2 ] . op = = XPATH_OP_PREDICATE ) & &
( comp - > steps [ op - > ch2 ] . ch1 = = - 1 ) & &
( comp - > steps [ op - > ch2 ] . ch2 ! = - 1 ) & &
( comp - > steps [ comp - > steps [ op - > ch2 ] . ch2 ] . op = =
XPATH_OP_VALUE ) ) {
xmlXPathObjectPtr val ;
val = comp - > steps [ comp - > steps [ op - > ch2 ] . ch2 ] . value4 ;
if ( ( val ! = NULL ) & & ( val - > type = = XPATH_NUMBER ) ) {
int indx = ( int ) val - > floatval ;
if ( val - > floatval = = ( float ) indx ) {
total + =
xmlXPathNodeCollectAndTestNth ( ctxt , op ,
indx , NULL ,
NULL ) ;
return ( total ) ;
}
}
}
total + = xmlXPathNodeCollectAndTest ( ctxt , op , NULL , NULL ) ;
return ( total ) ;
}
case XPATH_OP_VALUE :
valuePush ( ctxt ,
xmlXPathObjectCopy ( ( xmlXPathObjectPtr ) op - > value4 ) ) ;
return ( total ) ;
case XPATH_OP_VARIABLE : {
2001-10-06 09:59:51 +00:00
xmlXPathObjectPtr val ;
2001-07-03 10:35:50 +00:00
if ( op - > ch1 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
if ( op - > value5 = = NULL ) {
val = xmlXPathVariableLookup ( ctxt - > context , op - > value4 ) ;
if ( val = = NULL ) {
ctxt - > error = XPATH_UNDEF_VARIABLE_ERROR ;
return ( 0 ) ;
}
valuePush ( ctxt , val ) ;
} else {
2001-07-03 10:35:50 +00:00
const xmlChar * URI ;
URI = xmlXPathNsLookup ( ctxt - > context , op - > value5 ) ;
if ( URI = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
2001-12-31 16:16:02 +00:00
" xmlXPathCompOpEval: variable %s bound to undefined prefix %s \n " ,
2001-07-03 10:35:50 +00:00
op - > value4 , op - > value5 ) ;
return ( total ) ;
}
2001-10-06 09:59:51 +00:00
val = xmlXPathVariableLookupNS ( ctxt - > context ,
op - > value4 , URI ) ;
if ( val = = NULL ) {
ctxt - > error = XPATH_UNDEF_VARIABLE_ERROR ;
return ( 0 ) ;
}
valuePush ( ctxt , val ) ;
2001-07-03 10:35:50 +00:00
}
return ( total ) ;
}
case XPATH_OP_FUNCTION : {
xmlXPathFunction func ;
const xmlChar * oldFunc , * oldFuncURI ;
2001-10-06 09:59:51 +00:00
int i ;
2001-07-03 10:35:50 +00:00
if ( op - > ch1 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
if ( ctxt - > valueNr < op - > value ) {
xmlGenericError ( xmlGenericErrorContext ,
2001-12-31 16:16:02 +00:00
" xmlXPathCompOpEval: parameter error \n " ) ;
2001-10-06 09:59:51 +00:00
ctxt - > error = XPATH_INVALID_OPERAND ;
return ( total ) ;
}
for ( i = 0 ; i < op - > value ; i + + )
if ( ctxt - > valueTab [ ( ctxt - > valueNr - 1 ) - i ] = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
2001-12-31 16:16:02 +00:00
" xmlXPathCompOpEval: parameter error \n " ) ;
2001-10-06 09:59:51 +00:00
ctxt - > error = XPATH_INVALID_OPERAND ;
return ( total ) ;
}
2001-07-03 10:35:50 +00:00
if ( op - > cache ! = NULL )
func = ( xmlXPathFunction ) op - > cache ;
else {
const xmlChar * URI = NULL ;
if ( op - > value5 = = NULL )
func =
xmlXPathFunctionLookup ( ctxt - > context ,
op - > value4 ) ;
else {
URI = xmlXPathNsLookup ( ctxt - > context , op - > value5 ) ;
if ( URI = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
2001-12-31 16:16:02 +00:00
" xmlXPathCompOpEval: function %s bound to undefined prefix %s \n " ,
2001-07-03 10:35:50 +00:00
op - > value4 , op - > value5 ) ;
return ( total ) ;
}
func = xmlXPathFunctionLookupNS ( ctxt - > context ,
op - > value4 , URI ) ;
}
if ( func = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
2001-12-31 16:16:02 +00:00
" xmlXPathCompOpEval: function %s not found \n " ,
2001-07-03 10:35:50 +00:00
op - > value4 ) ;
XP_ERROR0 ( XPATH_UNKNOWN_FUNC_ERROR ) ;
}
op - > cache = ( void * ) func ;
op - > cacheURI = ( void * ) URI ;
}
oldFunc = ctxt - > context - > function ;
oldFuncURI = ctxt - > context - > functionURI ;
ctxt - > context - > function = op - > value4 ;
ctxt - > context - > functionURI = op - > cacheURI ;
func ( ctxt , op - > value ) ;
ctxt - > context - > function = oldFunc ;
ctxt - > context - > functionURI = oldFuncURI ;
return ( total ) ;
}
case XPATH_OP_ARG :
2002-05-14 11:03:59 +00:00
bakd = ctxt - > context - > doc ;
bak = ctxt - > context - > node ;
2001-07-03 10:35:50 +00:00
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2002-05-14 11:03:59 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch2 ] ) ;
2002-05-14 11:03:59 +00:00
ctxt - > context - > doc = bakd ;
ctxt - > context - > node = bak ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
return ( total ) ;
case XPATH_OP_PREDICATE :
case XPATH_OP_FILTER : {
xmlXPathObjectPtr res ;
xmlXPathObjectPtr obj , tmp ;
xmlNodeSetPtr newset = NULL ;
xmlNodeSetPtr oldset ;
xmlNodePtr oldnode ;
int i ;
/*
* Optimization for ( ) [ 1 ] selection i . e . the first elem
*/
if ( ( op - > ch1 ! = - 1 ) & & ( op - > ch2 ! = - 1 ) & &
( comp - > steps [ op - > ch1 ] . op = = XPATH_OP_SORT ) & &
( comp - > steps [ op - > ch2 ] . op = = XPATH_OP_VALUE ) ) {
xmlXPathObjectPtr val ;
val = comp - > steps [ op - > ch2 ] . value4 ;
if ( ( val ! = NULL ) & & ( val - > type = = XPATH_NUMBER ) & &
( val - > floatval = = 1.0 ) ) {
xmlNodePtr first = NULL ;
total + =
xmlXPathCompOpEvalFirst ( ctxt ,
& comp - > steps [ op - > ch1 ] ,
& first ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
/*
* The nodeset should be in document order ,
* Keep only the first value
*/
if ( ( ctxt - > value ! = NULL ) & &
( ctxt - > value - > type = = XPATH_NODESET ) & &
( ctxt - > value - > nodesetval ! = NULL ) & &
( ctxt - > value - > nodesetval - > nodeNr > 1 ) )
ctxt - > value - > nodesetval - > nodeNr = 1 ;
return ( total ) ;
}
}
/*
* Optimization for ( ) [ last ( ) ] selection i . e . the last elem
*/
if ( ( op - > ch1 ! = - 1 ) & & ( op - > ch2 ! = - 1 ) & &
( comp - > steps [ op - > ch1 ] . op = = XPATH_OP_SORT ) & &
( comp - > steps [ op - > ch2 ] . op = = XPATH_OP_SORT ) ) {
int f = comp - > steps [ op - > ch2 ] . ch1 ;
if ( ( f ! = - 1 ) & &
( comp - > steps [ f ] . op = = XPATH_OP_FUNCTION ) & &
( comp - > steps [ f ] . value5 = = NULL ) & &
( comp - > steps [ f ] . value = = 0 ) & &
( comp - > steps [ f ] . value4 ! = NULL ) & &
( xmlStrEqual
( comp - > steps [ f ] . value4 , BAD_CAST " last " ) ) ) {
xmlNodePtr last = NULL ;
total + =
xmlXPathCompOpEvalLast ( ctxt ,
& comp - > steps [ op - > ch1 ] ,
& last ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
/*
* The nodeset should be in document order ,
* Keep only the last value
*/
if ( ( ctxt - > value ! = NULL ) & &
( ctxt - > value - > type = = XPATH_NODESET ) & &
( ctxt - > value - > nodesetval ! = NULL ) & &
( ctxt - > value - > nodesetval - > nodeTab ! = NULL ) & &
( ctxt - > value - > nodesetval - > nodeNr > 1 ) ) {
ctxt - > value - > nodesetval - > nodeTab [ 0 ] =
ctxt - > value - > nodesetval - > nodeTab [ ctxt - >
value - >
nodesetval - >
nodeNr -
1 ] ;
ctxt - > value - > nodesetval - > nodeNr = 1 ;
}
return ( total ) ;
}
}
if ( op - > ch1 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( op - > ch2 = = - 1 )
return ( total ) ;
if ( ctxt - > value = = NULL )
return ( total ) ;
oldnode = ctxt - > context - > node ;
2001-03-18 23:17:47 +00:00
2001-07-03 10:35:50 +00:00
# ifdef LIBXML_XPTR_ENABLED
/*
* Hum are we filtering the result of an XPointer expression
*/
if ( ctxt - > value - > type = = XPATH_LOCATIONSET ) {
xmlLocationSetPtr newlocset = NULL ;
xmlLocationSetPtr oldlocset ;
/*
* Extract the old locset , and then evaluate the result of the
* expression for all the element in the locset . use it to grow
* up a new locset .
*/
CHECK_TYPE0 ( XPATH_LOCATIONSET ) ;
obj = valuePop ( ctxt ) ;
oldlocset = obj - > user ;
ctxt - > context - > node = NULL ;
if ( ( oldlocset = = NULL ) | | ( oldlocset - > locNr = = 0 ) ) {
ctxt - > context - > contextSize = 0 ;
ctxt - > context - > proximityPosition = 0 ;
if ( op - > ch2 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt ,
& comp - > steps [ op - > ch2 ] ) ;
res = valuePop ( ctxt ) ;
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
valuePush ( ctxt , obj ) ;
CHECK_ERROR0 ;
return ( total ) ;
}
newlocset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldlocset - > locNr ; i + + ) {
/*
* Run the evaluation with a node list made of a
* single item in the nodelocset .
*/
ctxt - > context - > node = oldlocset - > locTab [ i ] - > user ;
tmp = xmlXPathNewNodeSet ( ctxt - > context - > node ) ;
valuePush ( ctxt , tmp ) ;
ctxt - > context - > contextSize = oldlocset - > locNr ;
ctxt - > context - > proximityPosition = i + 1 ;
if ( op - > ch2 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt ,
& comp - > steps [ op - > ch2 ] ) ;
CHECK_ERROR0 ;
/*
* The result of the evaluation need to be tested to
* decided whether the filter succeeded or not
*/
res = valuePop ( ctxt ) ;
if ( xmlXPathEvaluatePredicateResult ( ctxt , res ) ) {
xmlXPtrLocationSetAdd ( newlocset ,
xmlXPathObjectCopy
( oldlocset - > locTab [ i ] ) ) ;
}
/*
* Cleanup
*/
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
if ( ctxt - > value = = tmp ) {
res = valuePop ( ctxt ) ;
xmlXPathFreeObject ( res ) ;
}
ctxt - > context - > node = NULL ;
}
/*
* The result is used as the new evaluation locset .
*/
xmlXPathFreeObject ( obj ) ;
ctxt - > context - > node = NULL ;
ctxt - > context - > contextSize = - 1 ;
ctxt - > context - > proximityPosition = - 1 ;
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newlocset ) ) ;
ctxt - > context - > node = oldnode ;
return ( total ) ;
}
2001-03-18 23:17:47 +00:00
# endif /* LIBXML_XPTR_ENABLED */
2001-07-03 10:35:50 +00:00
/*
* Extract the old set , and then evaluate the result of the
* expression for all the element in the set . use it to grow
* up a new set .
*/
CHECK_TYPE0 ( XPATH_NODESET ) ;
obj = valuePop ( ctxt ) ;
oldset = obj - > nodesetval ;
oldnode = ctxt - > context - > node ;
ctxt - > context - > node = NULL ;
if ( ( oldset = = NULL ) | | ( oldset - > nodeNr = = 0 ) ) {
ctxt - > context - > contextSize = 0 ;
ctxt - > context - > proximityPosition = 0 ;
if ( op - > ch2 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt ,
& comp - > steps [ op - > ch2 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
res = valuePop ( ctxt ) ;
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
valuePush ( ctxt , obj ) ;
ctxt - > context - > node = oldnode ;
CHECK_ERROR0 ;
} else {
/*
* Initialize the new set .
*/
newset = xmlXPathNodeSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > nodeNr ; i + + ) {
/*
* Run the evaluation with a node list made of
* a single item in the nodeset .
*/
ctxt - > context - > node = oldset - > nodeTab [ i ] ;
tmp = xmlXPathNewNodeSet ( ctxt - > context - > node ) ;
valuePush ( ctxt , tmp ) ;
ctxt - > context - > contextSize = oldset - > nodeNr ;
ctxt - > context - > proximityPosition = i + 1 ;
if ( op - > ch2 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt ,
& comp - > steps [ op - > ch2 ] ) ;
CHECK_ERROR0 ;
/*
* The result of the evaluation need to be tested to
* decided whether the filter succeeded or not
*/
res = valuePop ( ctxt ) ;
if ( xmlXPathEvaluatePredicateResult ( ctxt , res ) ) {
xmlXPathNodeSetAdd ( newset , oldset - > nodeTab [ i ] ) ;
}
/*
* Cleanup
*/
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
if ( ctxt - > value = = tmp ) {
res = valuePop ( ctxt ) ;
xmlXPathFreeObject ( res ) ;
}
ctxt - > context - > node = NULL ;
}
/*
* The result is used as the new evaluation set .
*/
xmlXPathFreeObject ( obj ) ;
ctxt - > context - > node = NULL ;
ctxt - > context - > contextSize = - 1 ;
ctxt - > context - > proximityPosition = - 1 ;
valuePush ( ctxt , xmlXPathWrapNodeSet ( newset ) ) ;
}
ctxt - > context - > node = oldnode ;
return ( total ) ;
}
case XPATH_OP_SORT :
if ( op - > ch1 ! = - 1 )
total + = xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
2001-10-06 09:59:51 +00:00
CHECK_ERROR0 ;
2001-07-03 10:35:50 +00:00
if ( ( ctxt - > value ! = NULL ) & &
( ctxt - > value - > type = = XPATH_NODESET ) & &
( ctxt - > value - > nodesetval ! = NULL ) )
xmlXPathNodeSetSort ( ctxt - > value - > nodesetval ) ;
return ( total ) ;
2001-03-18 23:17:47 +00:00
# ifdef LIBXML_XPTR_ENABLED
2001-07-03 10:35:50 +00:00
case XPATH_OP_RANGETO : {
xmlXPathObjectPtr range ;
xmlXPathObjectPtr res , obj ;
xmlXPathObjectPtr tmp ;
xmlLocationSetPtr newset = NULL ;
xmlNodeSetPtr oldset ;
int i ;
if ( op - > ch1 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt , & comp - > steps [ op - > ch1 ] ) ;
if ( op - > ch2 = = - 1 )
return ( total ) ;
CHECK_TYPE0 ( XPATH_NODESET ) ;
obj = valuePop ( ctxt ) ;
oldset = obj - > nodesetval ;
ctxt - > context - > node = NULL ;
newset = xmlXPtrLocationSetCreate ( NULL ) ;
if ( oldset ! = NULL ) {
for ( i = 0 ; i < oldset - > nodeNr ; i + + ) {
/*
* Run the evaluation with a node list made of a single item
* in the nodeset .
*/
ctxt - > context - > node = oldset - > nodeTab [ i ] ;
tmp = xmlXPathNewNodeSet ( ctxt - > context - > node ) ;
valuePush ( ctxt , tmp ) ;
if ( op - > ch2 ! = - 1 )
total + =
xmlXPathCompOpEval ( ctxt ,
& comp - > steps [ op - > ch2 ] ) ;
CHECK_ERROR0 ;
/*
* The result of the evaluation need to be tested to
* decided whether the filter succeeded or not
*/
res = valuePop ( ctxt ) ;
range =
xmlXPtrNewRangeNodeObject ( oldset - > nodeTab [ i ] ,
res ) ;
if ( range ! = NULL ) {
xmlXPtrLocationSetAdd ( newset , range ) ;
}
/*
* Cleanup
*/
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
if ( ctxt - > value = = tmp ) {
res = valuePop ( ctxt ) ;
xmlXPathFreeObject ( res ) ;
}
ctxt - > context - > node = NULL ;
}
}
/*
* The result is used as the new evaluation set .
*/
xmlXPathFreeObject ( obj ) ;
ctxt - > context - > node = NULL ;
ctxt - > context - > contextSize = - 1 ;
ctxt - > context - > proximityPosition = - 1 ;
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
return ( total ) ;
}
2001-03-18 23:17:47 +00:00
# endif /* LIBXML_XPTR_ENABLED */
}
xmlGenericError ( xmlGenericErrorContext ,
2001-07-03 10:35:50 +00:00
" XPath: unknown precompiled operation %d \n " , op - > op ) ;
return ( total ) ;
2001-03-18 23:17:47 +00:00
}
/**
* xmlXPathRunEval :
* @ ctxt : the XPath parser context with the compiled expression
*
* Evaluate the Precompiled XPath expression in the given context .
*/
2001-03-19 15:58:54 +00:00
static void
2001-03-18 23:17:47 +00:00
xmlXPathRunEval ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompExprPtr comp ;
if ( ( ctxt = = NULL ) | | ( ctxt - > comp = = NULL ) )
return ;
if ( ctxt - > valueTab = = NULL ) {
/* Allocate the value stack */
ctxt - > valueTab = ( xmlXPathObjectPtr * )
xmlMalloc ( 10 * sizeof ( xmlXPathObjectPtr ) ) ;
if ( ctxt - > valueTab = = NULL ) {
2003-10-07 21:25:12 +00:00
xmlXPathPErrMemory ( ctxt , " creating evaluation context \n " ) ;
2001-03-18 23:17:47 +00:00
xmlFree ( ctxt ) ;
}
ctxt - > valueNr = 0 ;
ctxt - > valueMax = 10 ;
ctxt - > value = NULL ;
}
comp = ctxt - > comp ;
2002-05-05 06:59:57 +00:00
if ( comp - > last < 0 ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathRunEval: last is less than zero \n " ) ;
return ;
}
2001-03-18 23:17:47 +00:00
xmlXPathCompOpEval ( ctxt , & comp - > steps [ comp - > last ] ) ;
}
2001-03-19 10:57:13 +00:00
/************************************************************************
* *
* Public interfaces *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-03-19 15:58:54 +00:00
/**
* xmlXPathEvalPredicate :
* @ ctxt : the XPath context
* @ res : the Predicate Expression evaluation result
*
* Evaluate a predicate result for the current node .
* A PredicateExpr is evaluated by evaluating the Expr and converting
* the result to a boolean . If the result is a number , the result will
* be converted to true if the number is equal to the position of the
* context node in the context node list ( as returned by the position
* function ) and will be converted to false otherwise ; if the result
* is not a number , then the result will be converted as if by a call
* to the boolean function .
*
2001-12-31 16:16:02 +00:00
* Returns 1 if predicate is true , 0 otherwise
2001-03-19 15:58:54 +00:00
*/
int
xmlXPathEvalPredicate ( xmlXPathContextPtr ctxt , xmlXPathObjectPtr res ) {
if ( res = = NULL ) return ( 0 ) ;
switch ( res - > type ) {
case XPATH_BOOLEAN :
return ( res - > boolval ) ;
case XPATH_NUMBER :
return ( res - > floatval = = ctxt - > proximityPosition ) ;
case XPATH_NODESET :
case XPATH_XSLT_TREE :
2001-04-05 16:54:14 +00:00
if ( res - > nodesetval = = NULL )
return ( 0 ) ;
2001-03-19 15:58:54 +00:00
return ( res - > nodesetval - > nodeNr ! = 0 ) ;
case XPATH_STRING :
return ( ( res - > stringval ! = NULL ) & &
( xmlStrlen ( res - > stringval ) ! = 0 ) ) ;
default :
STRANGE
}
return ( 0 ) ;
}
2001-03-19 10:57:13 +00:00
/**
* xmlXPathEvaluatePredicateResult :
* @ ctxt : the XPath Parser context
* @ res : the Predicate Expression evaluation result
*
* Evaluate a predicate result for the current node .
* A PredicateExpr is evaluated by evaluating the Expr and converting
* the result to a boolean . If the result is a number , the result will
* be converted to true if the number is equal to the position of the
* context node in the context node list ( as returned by the position
* function ) and will be converted to false otherwise ; if the result
* is not a number , then the result will be converted as if by a call
* to the boolean function .
*
2001-12-31 16:16:02 +00:00
* Returns 1 if predicate is true , 0 otherwise
2001-03-19 10:57:13 +00:00
*/
int
xmlXPathEvaluatePredicateResult ( xmlXPathParserContextPtr ctxt ,
xmlXPathObjectPtr res ) {
if ( res = = NULL ) return ( 0 ) ;
switch ( res - > type ) {
case XPATH_BOOLEAN :
return ( res - > boolval ) ;
case XPATH_NUMBER :
return ( res - > floatval = = ctxt - > context - > proximityPosition ) ;
case XPATH_NODESET :
case XPATH_XSLT_TREE :
2001-04-10 14:31:39 +00:00
if ( res - > nodesetval = = NULL )
2001-04-07 15:39:35 +00:00
return ( 0 ) ;
2001-03-19 10:57:13 +00:00
return ( res - > nodesetval - > nodeNr ! = 0 ) ;
case XPATH_STRING :
return ( ( res - > stringval ! = NULL ) & &
( xmlStrlen ( res - > stringval ) ! = 0 ) ) ;
default :
STRANGE
}
return ( 0 ) ;
}
/**
* xmlXPathCompile :
* @ str : the XPath expression
*
* Compile an XPath expression
*
2003-02-09 23:33:36 +00:00
* Returns the xmlXPathCompExprPtr resulting from the compilation or NULL .
2001-03-19 10:57:13 +00:00
* the caller has to free the object .
*/
xmlXPathCompExprPtr
xmlXPathCompile ( const xmlChar * str ) {
xmlXPathParserContextPtr ctxt ;
xmlXPathCompExprPtr comp ;
xmlXPathInit ( ) ;
ctxt = xmlXPathNewParserContext ( str , NULL ) ;
xmlXPathCompileExpr ( ctxt ) ;
2003-10-28 19:02:21 +00:00
if ( ctxt - > error ! = XPATH_EXPRESSION_OK )
{
xmlXPathFreeParserContext ( ctxt ) ;
return ( 0 ) ;
}
2001-04-22 08:50:55 +00:00
if ( * ctxt - > cur ! = 0 ) {
2002-05-07 16:21:36 +00:00
/*
* aleksey : in some cases this line prints * second * error message
* ( see bug # 78858 ) and probably this should be fixed .
* However , we are not sure that all error messages are printed
* out in other places . It ' s not critical so we leave it as - is for now
*/
2001-04-22 08:50:55 +00:00
xmlXPatherror ( ctxt , __FILE__ , __LINE__ , XPATH_EXPR_ERROR ) ;
comp = NULL ;
} else {
comp = ctxt - > comp ;
ctxt - > comp = NULL ;
}
2001-03-19 10:57:13 +00:00
xmlXPathFreeParserContext ( ctxt ) ;
2001-07-03 10:35:50 +00:00
if ( comp ! = NULL ) {
2002-10-04 11:46:37 +00:00
comp - > expr = xmlStrdup ( str ) ;
# ifdef DEBUG_EVAL_COUNTS
2001-07-03 10:35:50 +00:00
comp - > string = xmlStrdup ( str ) ;
comp - > nb = 0 ;
# endif
2002-10-04 11:46:37 +00:00
}
2001-03-19 10:57:13 +00:00
return ( comp ) ;
}
2001-03-18 23:17:47 +00:00
/**
* xmlXPathCompiledEval :
* @ comp : the compiled XPath expression
* @ ctx : the XPath context
*
* Evaluate the Precompiled XPath expression in the given context .
*
2001-12-31 16:16:02 +00:00
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL .
2001-03-18 23:17:47 +00:00
* the caller has to free the object .
*/
xmlXPathObjectPtr
xmlXPathCompiledEval ( xmlXPathCompExprPtr comp , xmlXPathContextPtr ctx ) {
xmlXPathParserContextPtr ctxt ;
xmlXPathObjectPtr res , tmp , init = NULL ;
int stack = 0 ;
2001-10-16 12:34:39 +00:00
# ifndef LIBXML_THREAD_ENABLED
static int reentance = 0 ;
# endif
2001-03-18 23:17:47 +00:00
if ( ( comp = = NULL ) | | ( ctx = = NULL ) )
return ( NULL ) ;
xmlXPathInit ( ) ;
CHECK_CONTEXT ( ctx )
2001-10-16 12:34:39 +00:00
# ifndef LIBXML_THREAD_ENABLED
reentance + + ;
if ( reentance > 1 )
xmlXPathDisableOptimizer = 1 ;
# endif
2001-07-03 10:35:50 +00:00
# ifdef DEBUG_EVAL_COUNTS
comp - > nb + + ;
if ( ( comp - > string ! = NULL ) & & ( comp - > nb > 100 ) ) {
fprintf ( stderr , " 100 x %s \n " , comp - > string ) ;
comp - > nb = 0 ;
}
# endif
2001-03-18 23:17:47 +00:00
ctxt = xmlXPathCompParserContext ( comp , ctx ) ;
xmlXPathRunEval ( ctxt ) ;
if ( ctxt - > value = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
2001-12-31 16:16:02 +00:00
" xmlXPathCompiledEval: evaluation failed \n " ) ;
2001-03-18 23:17:47 +00:00
res = NULL ;
} else {
res = valuePop ( ctxt ) ;
}
2001-07-03 10:35:50 +00:00
2001-03-18 23:17:47 +00:00
do {
tmp = valuePop ( ctxt ) ;
if ( tmp ! = NULL ) {
if ( tmp ! = init )
stack + + ;
xmlXPathFreeObject ( tmp ) ;
}
} while ( tmp ! = NULL ) ;
if ( ( stack ! = 0 ) & & ( res ! = NULL ) ) {
xmlGenericError ( xmlGenericErrorContext ,
2001-12-31 16:16:02 +00:00
" xmlXPathCompiledEval: %d object left on the stack \n " ,
2001-03-18 23:17:47 +00:00
stack ) ;
}
if ( ctxt - > error ! = XPATH_EXPRESSION_OK ) {
xmlXPathFreeObject ( res ) ;
res = NULL ;
}
2001-03-19 10:57:13 +00:00
ctxt - > comp = NULL ;
2001-03-18 23:17:47 +00:00
xmlXPathFreeParserContext ( ctxt ) ;
2001-10-16 12:34:39 +00:00
# ifndef LIBXML_THREAD_ENABLED
reentance - - ;
# endif
2001-03-18 23:17:47 +00:00
return ( res ) ;
}
2001-03-19 10:57:13 +00:00
/**
* xmlXPathEvalExpr :
* @ ctxt : the XPath Parser context
*
* Parse and evaluate an XPath expression in the given context ,
* then push the result on the context stack
*/
void
xmlXPathEvalExpr ( xmlXPathParserContextPtr ctxt ) {
xmlXPathCompileExpr ( ctxt ) ;
2002-05-07 16:21:36 +00:00
CHECK_ERROR ;
2001-03-19 10:57:13 +00:00
xmlXPathRunEval ( ctxt ) ;
}
2001-03-18 23:17:47 +00:00
2001-02-23 17:55:21 +00:00
/**
* xmlXPathEval :
* @ str : the XPath expression
* @ ctx : the XPath context
*
* Evaluate the XPath Location Path in the given context .
*
2001-12-31 16:16:02 +00:00
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL .
2001-02-23 17:55:21 +00:00
* the caller has to free the object .
*/
xmlXPathObjectPtr
xmlXPathEval ( const xmlChar * str , xmlXPathContextPtr ctx ) {
xmlXPathParserContextPtr ctxt ;
xmlXPathObjectPtr res , tmp , init = NULL ;
int stack = 0 ;
xmlXPathInit ( ) ;
CHECK_CONTEXT ( ctx )
ctxt = xmlXPathNewParserContext ( str , ctx ) ;
xmlXPathEvalExpr ( ctxt ) ;
if ( ctxt - > value = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathEval: evaluation failed \n " ) ;
res = NULL ;
} else if ( * ctxt - > cur ! = 0 ) {
xmlXPatherror ( ctxt , __FILE__ , __LINE__ , XPATH_EXPR_ERROR ) ;
res = NULL ;
} else {
res = valuePop ( ctxt ) ;
}
do {
tmp = valuePop ( ctxt ) ;
if ( tmp ! = NULL ) {
if ( tmp ! = init )
stack + + ;
xmlXPathFreeObject ( tmp ) ;
}
} while ( tmp ! = NULL ) ;
if ( ( stack ! = 0 ) & & ( res ! = NULL ) ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathEval: %d object left on the stack \n " ,
stack ) ;
}
if ( ctxt - > error ! = XPATH_EXPRESSION_OK ) {
xmlXPathFreeObject ( res ) ;
res = NULL ;
}
2001-03-18 23:17:47 +00:00
2001-02-23 17:55:21 +00:00
xmlXPathFreeParserContext ( ctxt ) ;
return ( res ) ;
}
/**
* xmlXPathEvalExpression :
* @ str : the XPath expression
* @ ctxt : the XPath context
*
* Evaluate the XPath expression in the given context .
*
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL .
* the caller has to free the object .
*/
xmlXPathObjectPtr
xmlXPathEvalExpression ( const xmlChar * str , xmlXPathContextPtr ctxt ) {
xmlXPathParserContextPtr pctxt ;
xmlXPathObjectPtr res , tmp ;
int stack = 0 ;
xmlXPathInit ( ) ;
CHECK_CONTEXT ( ctxt )
pctxt = xmlXPathNewParserContext ( str , ctxt ) ;
xmlXPathEvalExpr ( pctxt ) ;
if ( * pctxt - > cur ! = 0 ) {
xmlXPatherror ( pctxt , __FILE__ , __LINE__ , XPATH_EXPR_ERROR ) ;
res = NULL ;
} else {
res = valuePop ( pctxt ) ;
}
do {
tmp = valuePop ( pctxt ) ;
if ( tmp ! = NULL ) {
xmlXPathFreeObject ( tmp ) ;
stack + + ;
}
} while ( tmp ! = NULL ) ;
if ( ( stack ! = 0 ) & & ( res ! = NULL ) ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlXPathEvalExpression: %d object left on the stack \n " ,
stack ) ;
}
xmlXPathFreeParserContext ( pctxt ) ;
return ( res ) ;
}
2002-08-22 20:52:17 +00:00
/************************************************************************
* *
* Extra functions not pertaining to the XPath spec *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPathEscapeUriFunction :
* @ ctxt : the XPath Parser context
* @ nargs : the number of arguments
*
* Implement the escape - uri ( ) XPath function
* string escape - uri ( string $ str , bool $ escape - reserved )
*
* This function applies the URI escaping rules defined in section 2 of [ RFC
* 2396 ] to the string supplied as $ uri - part , which typically represents all
* or part of a URI . The effect of the function is to replace any special
* character in the string by an escape sequence of the form % xx % yy . . . ,
* where xxyy . . . is the hexadecimal representation of the octets used to
* represent the character in UTF - 8.
*
* The set of characters that are escaped depends on the setting of the
* boolean argument $ escape - reserved .
*
* If $ escape - reserved is true , all characters are escaped other than lower
* case letters a - z , upper case letters A - Z , digits 0 - 9 , and the characters
* referred to in [ RFC 2396 ] as " marks " : specifically , " - " | " _ " | " . " | " ! "
* | " ~ " | " * " | " ' " | " ( " | " ) " . The " % " character itself is escaped only
* if it is not followed by two hexadecimal digits ( that is , 0 - 9 , a - f , and
* A - F ) .
*
* If $ escape - reserved is false , the behavior differs in that characters
* referred to in [ RFC 2396 ] as reserved characters are not escaped . These
* characters are " ; " | " / " | " ? " | " : " | " @ " | " & " | " = " | " + " | " $ " | " , " .
*
* [ RFC 2396 ] does not define whether escaped URIs should use lower case or
* upper case for hexadecimal digits . To ensure that escaped URIs can be
* compared using string comparison functions , this function must always use
* the upper - case letters A - F .
*
* Generally , $ escape - reserved should be set to true when escaping a string
* that is to form a single part of a URI , and to false when escaping an
* entire URI or URI reference .
*
* In the case of non - ascii characters , the string is encoded according to
* utf - 8 and then converted according to RFC 2396.
*
* Examples
* xf : escape - uri ( " gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean " ) , true ( ) )
* returns " gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean "
* xf : escape - uri ( " gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean " ) , false ( ) )
* returns " gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean "
*
*/
2002-09-24 14:13:13 +00:00
static void
2002-08-22 20:52:17 +00:00
xmlXPathEscapeUriFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr str ;
int escape_reserved ;
xmlBufferPtr target ;
xmlChar * cptr ;
xmlChar escape [ 4 ] ;
CHECK_ARITY ( 2 ) ;
escape_reserved = xmlXPathPopBoolean ( ctxt ) ;
CAST_TO_STRING ;
str = valuePop ( ctxt ) ;
target = xmlBufferCreate ( ) ;
escape [ 0 ] = ' % ' ;
escape [ 3 ] = 0 ;
if ( target ) {
for ( cptr = str - > stringval ; * cptr ; cptr + + ) {
if ( ( * cptr > = ' A ' & & * cptr < = ' Z ' ) | |
( * cptr > = ' a ' & & * cptr < = ' z ' ) | |
( * cptr > = ' 0 ' & & * cptr < = ' 9 ' ) | |
* cptr = = ' - ' | | * cptr = = ' _ ' | | * cptr = = ' . ' | |
* cptr = = ' ! ' | | * cptr = = ' ~ ' | | * cptr = = ' * ' | |
* cptr = = ' \' ' | | * cptr = = ' ( ' | | * cptr = = ' ) ' | |
( * cptr = = ' % ' & &
( ( cptr [ 1 ] > = ' A ' & & cptr [ 1 ] < = ' F ' ) | |
( cptr [ 1 ] > = ' a ' & & cptr [ 1 ] < = ' f ' ) | |
( cptr [ 1 ] > = ' 0 ' & & cptr [ 1 ] < = ' 9 ' ) ) & &
( ( cptr [ 2 ] > = ' A ' & & cptr [ 2 ] < = ' F ' ) | |
( cptr [ 2 ] > = ' a ' & & cptr [ 2 ] < = ' f ' ) | |
( cptr [ 2 ] > = ' 0 ' & & cptr [ 2 ] < = ' 9 ' ) ) ) | |
( ! escape_reserved & &
( * cptr = = ' ; ' | | * cptr = = ' / ' | | * cptr = = ' ? ' | |
* cptr = = ' : ' | | * cptr = = ' @ ' | | * cptr = = ' & ' | |
* cptr = = ' = ' | | * cptr = = ' + ' | | * cptr = = ' $ ' | |
* cptr = = ' , ' ) ) ) {
xmlBufferAdd ( target , cptr , 1 ) ;
} else {
if ( ( * cptr > > 4 ) < 10 )
escape [ 1 ] = ' 0 ' + ( * cptr > > 4 ) ;
else
escape [ 1 ] = ' A ' - 10 + ( * cptr > > 4 ) ;
if ( ( * cptr & 0xF ) < 10 )
escape [ 2 ] = ' 0 ' + ( * cptr & 0xF ) ;
else
escape [ 2 ] = ' A ' - 10 + ( * cptr & 0xF ) ;
xmlBufferAdd ( target , & escape [ 0 ] , 3 ) ;
}
}
}
valuePush ( ctxt , xmlXPathNewString ( xmlBufferContent ( target ) ) ) ;
xmlBufferFree ( target ) ;
xmlXPathFreeObject ( str ) ;
}
2001-02-23 17:55:21 +00:00
/**
* xmlXPathRegisterAllFunctions :
* @ ctxt : the XPath context
*
* Registers all default XPath functions in this context
*/
void
xmlXPathRegisterAllFunctions ( xmlXPathContextPtr ctxt )
{
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " boolean " ,
xmlXPathBooleanFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " ceiling " ,
xmlXPathCeilingFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " count " ,
xmlXPathCountFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " concat " ,
xmlXPathConcatFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " contains " ,
xmlXPathContainsFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " id " ,
xmlXPathIdFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " false " ,
xmlXPathFalseFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " floor " ,
xmlXPathFloorFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " last " ,
xmlXPathLastFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " lang " ,
xmlXPathLangFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " local-name " ,
xmlXPathLocalNameFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " not " ,
xmlXPathNotFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " name " ,
xmlXPathNameFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " namespace-uri " ,
xmlXPathNamespaceURIFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " normalize-space " ,
xmlXPathNormalizeFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " number " ,
xmlXPathNumberFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " position " ,
xmlXPathPositionFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " round " ,
xmlXPathRoundFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " string " ,
xmlXPathStringFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " string-length " ,
xmlXPathStringLengthFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " starts-with " ,
xmlXPathStartsWithFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " substring " ,
xmlXPathSubstringFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " substring-before " ,
xmlXPathSubstringBeforeFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " substring-after " ,
xmlXPathSubstringAfterFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " sum " ,
xmlXPathSumFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " true " ,
xmlXPathTrueFunction ) ;
xmlXPathRegisterFunc ( ctxt , ( const xmlChar * ) " translate " ,
xmlXPathTranslateFunction ) ;
2002-08-22 20:52:17 +00:00
xmlXPathRegisterFuncNS ( ctxt , ( const xmlChar * ) " escape-uri " ,
( const xmlChar * ) " http://www.w3.org/2002/08/xquery-functions " ,
xmlXPathEscapeUriFunction ) ;
2001-02-23 17:55:21 +00:00
}
# endif /* LIBXML_XPATH_ENABLED */