📄 xpath.c
字号:
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) fprintf(output, "%s", (const char *) name); 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; case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;#ifdef LIBXML_XPTR_ENABLED case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;#endif 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);}/** * xmlXPathDebugDumpCompExpr: * @output: the FILE * for the output * @comp: the precompiled XPath expression * @depth: the indentation level. * * Dumps the tree of the compiled XPath expression. */voidxmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, int depth) { int i; char shift[100]; if ((output == NULL) || (comp == NULL)) return; 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);}#endif /* LIBXML_DEBUG_ENABLED *//************************************************************************ * * * Parser stacks related functions and macros * * * ************************************************************************//** * valuePop: * @ctxt: an XPath evaluation context * * Pops the top XPath object from the value stack * * Returns the XPath object just removed */extern xmlXPathObjectPtrvaluePop(xmlXPathParserContextPtr ctxt){ xmlXPathObjectPtr ret; if ((ctxt == NULL) || (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);}/** * valuePush: * @ctxt: an XPath evaluation context * @value: the XPath object * * Pushes a new XPath object on top of the value stack * * returns the number of items on the value stack */extern intvaluePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value){ if ((ctxt == NULL) || (value == NULL)) return(-1); if (ctxt->valueNr >= ctxt->valueMax) { xmlXPathObjectPtr *tmp; tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, 2 * ctxt->valueMax * sizeof(ctxt->valueTab[0])); if (tmp == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); return (0); } ctxt->valueMax *= 2; ctxt->valueTab = tmp; } ctxt->valueTab[ctxt->valueNr] = value; ctxt->value = value; return (ctxt->valueNr++);}/** * xmlXPathPopBoolean: * @ctxt: an XPath parser context * * Pops a boolean from the stack, handling conversion if needed. * Check error with #xmlXPathCheckError. * * Returns the boolean */intxmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { xmlXPathObjectPtr obj; int ret; obj = valuePop(ctxt); if (obj == NULL) { xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); return(0); } if (obj->type != XPATH_BOOLEAN) ret = xmlXPathCastToBoolean(obj); else ret = obj->boolval; 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 */doublexmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { xmlXPathObjectPtr obj; double ret; obj = valuePop(ctxt); if (obj == NULL) { xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); return(0); } if (obj->type != XPATH_NUMBER) ret = xmlXPathCastToNumber(obj); else ret = obj->floatval; 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); /* this does required strdup */ /* 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 */xmlNodeSetPtrxmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { xmlXPathObjectPtr obj; xmlNodeSetPtr ret; if (ctxt == NULL) return(NULL); if (ctxt->value == NULL) { xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); return(NULL); } if (!xmlXPathStackIsNodeSet(ctxt)) { xmlXPathSetTypeError(ctxt); return(NULL); } obj = valuePop(ctxt); ret = obj->nodesetval;#if 0 /* to fix memory leak of not clearing obj->user */ if (obj->boolval && obj->user != NULL) xmlFreeNodeList((xmlNodePtr) obj->user);#endif xmlXPathFreeNodeSetList(obj); return(ret);}/** * xmlXPathPopExternal: * @ctxt: an XPath parser context * * Pops an external object from the stack, handling conversion if needed. * Check error with #xmlXPathCheckError. * * Returns the object */void *xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { xmlXPathObjectPtr obj; void * ret; if ((ctxt == NULL) || (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);}/* * Macros for accessing the content. Those should be used only by the parser, * and not exported. * * Dirty macros, i.e. one need to make assumption on the context to use them * * CUR_PTR return the current pointer to the xmlChar to be parsed. * CUR returns the current xmlChar value, i.e. a 8 bit value * in ISO-Latin or UTF-8. * This should be used internally by the parser * only to compare to ASCII values otherwise it would break when * running with UTF-8 encoding. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only * to compare on ASCII based substring. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined * strings within the parser. * CURRENT Returns the current char value, with the full decoding of * UTF-8 if we are using this mode. It returns an int. * NEXT Skip to the next character, this does the proper decoding * in UTF-8 mode. It also pop-up unfinished entities on the fly. * It returns the pointer to the current xmlChar. */#define CUR (*ctxt->cur)#define SKIP(val) ctxt->cur += (val)#define NXT(val) ctxt->cur[(val)]#define CUR_PTR ctxt->cur#define 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#define SKIP_BLANKS \ while (IS_BLANK_CH(*(ctxt->cur))) NEXT#define CURRENT (*ctxt->cur)#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)#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 voidxmlXPathFormatNumber(double number, char buffer[], int buffersize){ switch (xmlXPathIsInf(number)) { case 1: if (buffersize > (int)sizeof("Infinity")) snprintf(buffer, buffersize, "Infinity"); break; case -1: if (buffersize > (int)sizeof("-Infinity")) snprintf(buffer, buffersize, "-Infinity"); break; default: if (xmlXPathIsNaN(number)) { if (buffersize > (int)sizeof("NaN")) snprintf(buffer, buffersize, "NaN"); } else if (number == 0 && xmlXPathGetSign(number) != 0) { snprintf(buffer, buffersize, "0"); } 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; } } else { /* 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'); } else { /* Use regular notation */ if (absolute_value > 0.0) integer_place = 1 + (int)log10(absolute_value); else integer_place = 0; 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; } /* Remove fractional trailing zeroes */ ptr = after_fraction; while (*(--ptr) == '0') ; if (*ptr != '.') ptr++; while ((*ptr++ = *after_fraction++) != 0); /* Finally copy result back to caller */ size = strlen(work) + 1; if (size > buffersize) { work[buffersize - 1] = 0; size = buffersize; } memmove(buffer, work, size); } break; }}/************************************************************************ * * * Routines to handle NodeSets * * * ************************************************************************//** * 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 (starting at -1) * to be able to differentiate from line numbers. * * Returns the number of elements found in the document or -1 in case * of error. */longxmlXPathOrderDocElems(xmlDocPtr doc) { long count = 0; xmlNodePtr cur; if (doc == NULL) return(-1); cur = doc->children; while (cur != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -