/** * xsltGenerateIdFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the generate-id() XSLT function * string generate-id(node-set?) */ void xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlNodePtr cur = NULL; unsigned long val; xmlChar str[20]; if (nargs == 0) { cur = ctxt->context->node; } else if (nargs == 1) { xmlXPathObjectPtr obj; xmlNodeSetPtr nodelist; int i, ret; if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { ctxt->error = XPATH_INVALID_TYPE; xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "generate-id() : invalid arg expecting a node-set\n"); return; } obj = valuePop(ctxt); nodelist = obj->nodesetval; if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { xmlXPathFreeObject(obj); valuePush(ctxt, xmlXPathNewCString("")); return; } cur = nodelist->nodeTab[0]; for (i = 1;i < nodelist->nodeNr;i++) { ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); if (ret == -1) cur = nodelist->nodeTab[i]; } xmlXPathFreeObject(obj); } else { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "generate-id() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } /* * Okay this is ugly but should work, use the NodePtr address * to forge the ID */ val = (unsigned long)((char *)cur - (char *)0); val /= sizeof(xmlNode); sprintf((char *)str, "id%ld", val); valuePush(ctxt, xmlXPathNewString(str)); }
static void exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str = NULL; xmlXPathObjectPtr ret = NULL; if (ctxt == NULL) return; if (nargs != 1) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "dyn:evalute() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } str = xmlXPathPopString(ctxt); if (!str||!xmlStrlen(str)) { if (str) xmlFree(str); valuePush(ctxt,xmlXPathNewNodeSet(NULL)); return; } ret = xmlXPathEval(str,ctxt->context); if (ret) valuePush(ctxt,ret); else { xsltGenericError(xsltGenericErrorContext, "dyn:evaluate() : unable to evaluate expression '%s'\n",str); valuePush(ctxt,xmlXPathNewNodeSet(NULL)); } xmlFree(str); return; }
/** * xsltFunctionAvailableFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the function-available() XSLT function * boolean function-available(string) */ void xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj; xmlChar *prefix, *name; const xmlChar *nsURI = NULL; if (nargs != 1) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "function-available() : expects one string arg\n"); ctxt->error = XPATH_INVALID_ARITY; return; } if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "function-available() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj = valuePop(ctxt); name = xmlSplitQName2(obj->stringval, &prefix); if (name == NULL) { name = xmlStrdup(obj->stringval); } else { nsURI = xmlXPathNsLookup(ctxt->context, prefix); if (nsURI == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "function-available() : prefix %s is not bound\n", prefix); } } if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) { valuePush(ctxt, xmlXPathNewBoolean(1)); } else { valuePush(ctxt, xmlXPathNewBoolean(0)); } xmlXPathFreeObject(obj); if (name != NULL) xmlFree(name); if (prefix != NULL) xmlFree(prefix); }
/** * xsltCurrentFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the current() XSLT function * node-set current() */ static void xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){ xsltTransformContextPtr tctxt; if (nargs != 0) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "current() : function uses no argument\n"); ctxt->error = XPATH_INVALID_ARITY; return; } tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "current() : internal error tctxt == NULL\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */ } }
/** * xsltNewStyleDocument: * @style: an XSLT style sheet * @doc: a parsed XML document * * Register a new document, apply key computations */ xsltDocumentPtr xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { xsltDocumentPtr cur; cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); if (cur == NULL) { xsltPrintErrorContext(NULL, style, (xmlNodePtr) doc); xsltGenericError(xsltGenericErrorContext, "xsltNewStyleDocument : malloc failed\n"); return(NULL); } memset(cur, 0, sizeof(xsltDocument)); cur->doc = doc; if (style != NULL) { cur->next = style->docList; style->docList = cur; } return(cur); }
/** * xsltLoadDocument: * @ctxt: an XSLT transformation context * @URI: the computed URI of the document * * Try to load a document within the XSLT transformation context * * Returns the new xsltDocumentPtr or NULL in case of error */ xsltDocumentPtr xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { xsltDocumentPtr ret; xmlDocPtr doc; if ((ctxt == NULL) || (URI == NULL)) return(NULL); /* * Walk the context list to find the document if preparsed */ ret = ctxt->docList; while (ret != NULL) { if ((ret->doc != NULL) && (ret->doc->URL != NULL) && (xmlStrEqual(ret->doc->URL, URI))) return(ret); ret = ret->next; } doc = xmlParseFile((const char *) URI); if (doc == NULL) return(NULL); if (ctxt->xinclude != 0) { #ifdef LIBXML_XINCLUDE_ENABLED xmlXIncludeProcess(doc); #else xsltPrintErrorContext(ctxt, NULL, NULL); xsltGenericError(xsltGenericErrorContext, "xsltLoadDocument(%s) : XInclude processing not compiled in\n", URI); #endif } /* * Apply white-space stripping if asked for */ if (xsltNeedElemSpaceHandling(ctxt)) xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); ret = xsltNewDocument(ctxt, doc); return(ret); }
/** * xsltNewDocument: * @ctxt: an XSLT transformation context (or NULL) * @doc: a parsed XML document * * Register a new document, apply key computations */ xsltDocumentPtr xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) { xsltDocumentPtr cur; cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); if (cur == NULL) { xsltPrintErrorContext(ctxt, NULL, (xmlNodePtr) doc); xsltGenericError(xsltGenericErrorContext, "xsltNewDocument : malloc failed\n"); return(NULL); } memset(cur, 0, sizeof(xsltDocument)); cur->doc = doc; if (ctxt != NULL) { cur->next = ctxt->docList; ctxt->docList = cur; xsltInitCtxtKeys(ctxt, cur); } return(cur); }
/** * xsltFormatNumberConversion: * @self: the decimal format * @format: the format requested * @number: the value to format * @result: the place to ouput the result * * format-number() uses the JDK 1.1 DecimalFormat class: * * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html * * Structure: * * pattern := subpattern{;subpattern} * subpattern := {prefix}integer{.fraction}{suffix} * prefix := '\\u0000'..'\\uFFFD' - specialCharacters * suffix := '\\u0000'..'\\uFFFD' - specialCharacters * integer := '#'* '0'* '0' * fraction := '0'* '#'* * * Notation: * X* 0 or more instances of X * (X | Y) either X or Y. * X..Y any character from X up to Y, inclusive. * S - T characters in S, except those in T * * Special Characters: * * Symbol Meaning * 0 a digit * # a digit, zero shows as absent * . placeholder for decimal separator * , placeholder for grouping separator. * ; separates formats. * - default negative prefix. * % multiply by 100 and show as percentage * ? multiply by 1000 and show as per mille * X any other characters can be used in the prefix or suffix * ' used to quote special characters in a prefix or suffix. */ xmlXPathError xsltFormatNumberConversion(xsltDecimalFormatPtr self, xmlChar *format, double number, xmlChar **result) { xmlXPathError status = XPATH_EXPRESSION_OK; xmlBufferPtr buffer; xmlChar *the_format, *prefix = NULL, *suffix = NULL; xmlChar *nprefix, *nsuffix = NULL; xmlChar pchar; int prefix_length, suffix_length = 0, nprefix_length, nsuffix_length; double scale; int j; xsltFormatNumberInfo format_info; /* delayed_multiplier allows a 'trailing' percent or permille to be treated as suffix */ int delayed_multiplier = 0; /* flag to show no -ve format present for -ve number */ char default_sign = 0; /* flag to show error found, should use default format */ char found_error = 0; *result = NULL; switch (xmlXPathIsInf(number)) { case -1: if (self->minusSign == NULL) *result = xmlStrdup(BAD_CAST "-"); else *result = xmlStrdup(self->minusSign); /* no-break on purpose */ case 1: if ((self == NULL) || (self->infinity == NULL)) *result = xmlStrcat(*result, BAD_CAST "Infinity"); else *result = xmlStrcat(*result, self->infinity); return(status); default: if (xmlXPathIsNaN(number)) { if ((self == NULL) || (self->noNumber == NULL)) *result = xmlStrdup(BAD_CAST "NaN"); else *result = xmlStrdup(self->noNumber); return(status); } } buffer = xmlBufferCreate(); if (buffer == NULL) { return XPATH_MEMORY_ERROR; } format_info.integer_digits = 0; format_info.frac_digits = 0; format_info.frac_hash = 0; format_info.group = -1; format_info.multiplier = 1; format_info.is_multiplier_set = FALSE; format_info.is_negative_pattern = FALSE; the_format = format; /* First we process the +ve pattern to get percent / permille, as well as main format */ prefix = the_format; prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (prefix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } /* Here we process the "number" part of the format. It gets a little messy because of */ /* the percent/per-mille - if that appears at the end, it may be part of the suffix */ /* instead of part of the number, so the variable delayed_multiplier is used to handle it */ while ((*the_format != 0) && (*the_format != self->decimalPoint[0]) && (*the_format != self->patternSeparator[0])) { if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; format_info.is_multiplier_set = TRUE; delayed_multiplier = 0; } if (*the_format == self->digit[0]) { if (format_info.integer_digits > 0) { found_error = 1; goto OUTPUT_NUMBER; } if (format_info.group >= 0) format_info.group++; } else if (*the_format == self->zeroDigit[0]) { format_info.integer_digits++; if (format_info.group >= 0) format_info.group++; } else if (*the_format == self->grouping[0]) { /* Reset group count */ format_info.group = 0; } else if (*the_format == self->percent[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; } else if (*the_format == self->permille[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; } else break; /* while */ the_format++; } /* We have finished the integer part, now work on fraction */ if (*the_format == self->decimalPoint[0]) the_format++; /* Skip over the decimal */ while (*the_format != 0) { if (*the_format == self->zeroDigit[0]) { if (format_info.frac_hash != 0) { found_error = 1; goto OUTPUT_NUMBER; } format_info.frac_digits++; } else if (*the_format == self->digit[0]) { format_info.frac_hash++; } else if (*the_format == self->percent[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 100; the_format++; continue; /* while */ } else if (*the_format == self->permille[0]) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } delayed_multiplier = 1000; the_format++; continue; /* while */ } else if (*the_format != self->grouping[0]) { break; /* while */ } the_format++; if (delayed_multiplier != 0) { format_info.multiplier = delayed_multiplier; delayed_multiplier = 0; format_info.is_multiplier_set = TRUE; } } /* If delayed_multiplier is set after processing the "number" part, should be in suffix */ if (delayed_multiplier != 0) { the_format--; delayed_multiplier = 0; } suffix = the_format; suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if ( (suffix_length < 0) || ((*the_format != 0) && (*the_format != self->patternSeparator[0])) ) { found_error = 1; goto OUTPUT_NUMBER; } /* We have processed the +ve prefix, number part and +ve suffix. */ /* If the number is -ve, we must substitute the -ve prefix / suffix */ if (number < 0) { the_format = (xmlChar *)xmlStrchr(format, self->patternSeparator[0]); if (the_format == NULL) { /* No -ve pattern present, so use default signing */ default_sign = 1; } else { /* Flag changes interpretation of percent/permille in -ve pattern */ the_format++; /* Skip over pattern separator */ format_info.is_negative_pattern = TRUE; format_info.is_multiplier_set = FALSE; /* First do the -ve prefix */ nprefix = the_format; nprefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nprefix_length<0) { found_error = 1; goto OUTPUT_NUMBER; } /* Next skip over the -ve number info */ the_format += prefix_length; while (*the_format != 0) { if ( (*the_format == (self)->percent[0]) || (*the_format == (self)->permille[0]) ) { if (format_info.is_multiplier_set) { found_error = 1; goto OUTPUT_NUMBER; } format_info.is_multiplier_set = TRUE; delayed_multiplier = 1; } else if (IS_SPECIAL(self, *the_format)) delayed_multiplier = 0; else break; /* while */ the_format++; } if (delayed_multiplier != 0) { format_info.is_multiplier_set = FALSE; the_format--; } /* Finally do the -ve suffix */ if (*the_format != 0) { nsuffix = the_format; nsuffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); if (nsuffix_length < 0) { found_error = 1; goto OUTPUT_NUMBER; } } else nsuffix_length = 0; if (*the_format != 0) { found_error = 1; goto OUTPUT_NUMBER; } /* Here's another Java peculiarity: * if -ve prefix/suffix == +ve ones, discard & use default */ if ((nprefix_length != prefix_length) || (nsuffix_length != suffix_length) || ((nprefix_length > 0) && (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) || ((nsuffix_length > 0) && (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) { prefix = nprefix; prefix_length = nprefix_length; suffix = nsuffix; suffix_length = nsuffix_length; } else { default_sign = 1; } } } OUTPUT_NUMBER: if (found_error != 0) { xsltPrintErrorContext(NULL, NULL, NULL); xsltGenericError(xsltGenericErrorContext, "xsltFormatNumberConversion : error in format string, using default\n"); default_sign = (number < 0.0) ? 1 : 0; prefix_length = suffix_length = 0; format_info.integer_digits = 1; format_info.frac_digits = 1; format_info.frac_hash = 4; format_info.group = -1; format_info.multiplier = 1; } /* Ready to output our number. First see if "default sign" is required */ if (default_sign != 0) xmlBufferAdd(buffer, self->minusSign, 1); /* Put the prefix into the buffer */ for (j = 0; j < prefix_length; j++) { if ((pchar = *prefix++) == SYMBOL_QUOTE) { pchar = *prefix++; prefix++; } xmlBufferAdd(buffer, &pchar, 1); } /* Next do the integer part of the number */ number = fabs(number) * (double)format_info.multiplier; scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash)); number = floor((scale * number + 0.5)) / scale; if ((self->grouping != NULL) && (self->grouping[0] != 0)) xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, (xmlChar) self->grouping[0]); else xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.integer_digits, format_info.group, (xmlChar) ','); /* Next the fractional part, if required */ if (format_info.frac_digits + format_info.frac_hash > 0) { number -= floor(number); if ((number != 0) || (format_info.frac_digits != 0)) { xmlBufferAdd(buffer, self->decimalPoint, 1); number = floor(scale * number + 0.5); for (j = format_info.frac_hash; j > 0; j--) { if (fmod(number, 10.0) >= 1.0) break; /* for */ number /= 10.0; } xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], format_info.frac_digits + j, 0, (xmlChar)0); } } /* Put the suffix into the buffer */ for (j = 0; j < suffix_length; j++) { if ((pchar = *suffix++) == SYMBOL_QUOTE) { pchar = *suffix++; suffix++; } xmlBufferAdd(buffer, &pchar, 1); } *result = xmlStrdup(xmlBufferContent(buffer)); xmlBufferFree(buffer); return status; }
/** * xsltNamespaceAlias: * @style: the XSLT stylesheet * @node: the xsl:namespace-alias node * * Read the stylesheet-prefix and result-prefix attributes, register * them as well as the corresponding namespace. */ void xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) { xmlChar *sprefix; xmlNsPtr sNs; xmlChar *rprefix; xmlNsPtr rNs; sprefix = xsltGetNsProp(node, (const xmlChar *)"stylesheet-prefix", XSLT_NAMESPACE); if (sprefix == NULL) { xsltPrintErrorContext(NULL, style, node); xsltGenericError(xsltGenericErrorContext, "namespace-alias: stylesheet-prefix attribute missing\n"); return; } rprefix = xsltGetNsProp(node, (const xmlChar *)"result-prefix", XSLT_NAMESPACE); if (rprefix == NULL) { xsltPrintErrorContext(NULL, style, node); xsltGenericError(xsltGenericErrorContext, "namespace-alias: result-prefix attribute missing\n"); goto error; } if (xmlStrEqual(sprefix, (const xmlChar *)"#default")) { sNs = xmlSearchNs(node->doc, node, NULL); } else { sNs = xmlSearchNs(node->doc, node, sprefix); } if ((sNs == NULL) || (sNs->href == NULL)) { xsltPrintErrorContext(NULL, style, node); xsltGenericError(xsltGenericErrorContext, "namespace-alias: prefix %s not bound to any namespace\n", sprefix); goto error; } if (xmlStrEqual(rprefix, (const xmlChar *)"#default")) { rNs = xmlSearchNs(node->doc, node, NULL); } else { rNs = xmlSearchNs(node->doc, node, rprefix); } if ((rNs == NULL) || (rNs->href == NULL)) { xsltPrintErrorContext(NULL, style, node); xsltGenericError(xsltGenericErrorContext, "namespace-alias: prefix %s not bound to any namespace\n", rprefix); goto error; } if (style->nsAliases == NULL) style->nsAliases = xmlHashCreate(10); if (style->nsAliases == NULL) { xsltPrintErrorContext(NULL, style, node); xsltGenericError(xsltGenericErrorContext, "namespace-alias: cannot create hash table\n"); goto error; } xmlHashAddEntry((xmlHashTablePtr) style->nsAliases, sNs->href, (void *) rNs->href); error: if (sprefix != NULL) xmlFree(sprefix); if (rprefix != NULL) xmlFree(rprefix); }
/** * xsltSystemPropertyFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the system-property() XSLT function * object system-property(string) */ void xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlXPathObjectPtr obj; xmlChar *prefix, *name; const xmlChar *nsURI = NULL; if (nargs != 1) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "system-property() : expects one string arg\n"); ctxt->error = XPATH_INVALID_ARITY; return; } if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "system-property() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj = valuePop(ctxt); if (obj->stringval == NULL) { valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } else { name = xmlSplitQName2(obj->stringval, &prefix); if (name == NULL) { name = xmlStrdup(obj->stringval); } else { nsURI = xmlXPathNsLookup(ctxt->context, prefix); if (nsURI == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "system-property() : prefix %s is not bound\n", prefix); } } if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) { #ifdef DOCBOOK_XSL_HACK if (xmlStrEqual(name, (const xmlChar *)"vendor")) { xsltStylesheetPtr sheet; xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if ((tctxt != NULL) && (tctxt->inst != NULL) && (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) && (tctxt->inst->parent != NULL) && (xmlStrEqual(tctxt->inst->parent->name, BAD_CAST "template"))) sheet = tctxt->style; else sheet = NULL; if ((sheet != NULL) && (sheet->doc != NULL) && (sheet->doc->URL != NULL) && (xmlStrstr(sheet->doc->URL, (const xmlChar *)"chunk") != NULL)) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)"libxslt (SAXON 6.2 compatible)")); } else { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_VENDOR)); } } else #else if (xmlStrEqual(name, (const xmlChar *)"vendor")) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_VENDOR)); } else #endif if (xmlStrEqual(name, (const xmlChar *)"version")) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_VERSION)); } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) { valuePush(ctxt, xmlXPathNewString( (const xmlChar *)XSLT_DEFAULT_URL)); } else { valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); } } if (name != NULL) xmlFree(name); if (prefix != NULL) xmlFree(prefix); } xmlXPathFreeObject(obj); }
/** * xsltKeyFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the key() XSLT function * node-set key(string, object) */ void xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){ xmlNodeSetPtr nodelist; xmlXPathObjectPtr obj1, obj2; xmlChar *key = NULL, *value; const xmlChar *keyURI; xsltTransformContextPtr tctxt; if (nargs != 2) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : expects two arguments\n"); ctxt->error = XPATH_INVALID_ARITY; return; } obj2 = valuePop(ctxt); if ((obj2 == NULL) || (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; xmlXPathFreeObject(obj2); return; } obj1 = valuePop(ctxt); if (obj2->type == XPATH_NODESET) { int i; xmlXPathObjectPtr newobj, ret; ret = xmlXPathNewNodeSet(NULL); if (obj2->nodesetval != NULL) { for (i = 0; i < obj2->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathObjectCopy(obj1)); valuePush(ctxt, xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); xsltKeyFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } valuePush(ctxt, ret); } else { xmlChar *qname, *prefix; /* * Get the associated namespace URI if qualified name */ qname = obj1->stringval; key = xmlSplitQName2(qname, &prefix); if (key == NULL) { key = xmlStrdup(obj1->stringval); keyURI = NULL; if (prefix != NULL) xmlFree(prefix); } else { if (prefix != NULL) { keyURI = xmlXPathNsLookup(ctxt->context, prefix); if (keyURI == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : prefix %s is not bound\n", prefix); } xmlFree(prefix); } else { keyURI = NULL; } } /* * Force conversion of first arg to string */ valuePush(ctxt, obj2); xmlXPathStringFunction(ctxt, 1); if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "key() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; xmlXPathFreeObject(obj1); return; } obj2 = valuePop(ctxt); value = obj2->stringval; tctxt = xsltXPathGetTransformContext(ctxt); nodelist = xsltGetKey(tctxt, key, keyURI, value); valuePush(ctxt, xmlXPathWrapNodeSet( xmlXPathNodeSetMerge(NULL, nodelist))); } if (obj1 != NULL) xmlXPathFreeObject(obj1); if (obj2 != NULL) xmlXPathFreeObject(obj2); if (key != NULL) xmlFree(key); }
/** * xsltDocumentFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the document() XSLT function * node-set document(object, node-set?) */ void xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){ xsltDocumentPtr doc; xmlXPathObjectPtr obj, obj2 = NULL; xmlChar *base = NULL, *URI; if ((nargs < 1) || (nargs > 2)) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid number of args %d\n", nargs); ctxt->error = XPATH_INVALID_ARITY; return; } if (ctxt->value == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid arg value\n"); ctxt->error = XPATH_INVALID_TYPE; return; } if (nargs == 2) { if (ctxt->value->type != XPATH_NODESET) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid arg expecting a nodeset\n"); ctxt->error = XPATH_INVALID_TYPE; return; } obj2 = valuePop(ctxt); } if (ctxt->value->type == XPATH_NODESET) { int i; xmlXPathObjectPtr newobj, ret; obj = valuePop(ctxt); ret = xmlXPathNewNodeSet(NULL); if (obj->nodesetval) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); xmlXPathStringFunction(ctxt, 1); if (nargs == 2) { valuePush(ctxt, xmlXPathObjectCopy(obj2)); } else { valuePush(ctxt, xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); } xsltDocumentFunction(ctxt, 2); newobj = valuePop(ctxt); ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, newobj->nodesetval); xmlXPathFreeObject(newobj); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); valuePush(ctxt, ret); return; } /* * Make sure it's converted to a string */ xmlXPathStringFunction(ctxt, 1); if (ctxt->value->type != XPATH_STRING) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : invalid arg expecting a string\n"); ctxt->error = XPATH_INVALID_TYPE; if (obj2 != NULL) xmlXPathFreeObject(obj2); return; } obj = valuePop(ctxt); if (obj->stringval == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { if ((obj2 != NULL) && (obj2->nodesetval != NULL) && (obj2->nodesetval->nodeNr > 0) && IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) { xmlNodePtr target; target = obj2->nodesetval->nodeTab[0]; if (target->type == XML_ATTRIBUTE_NODE) { target = ((xmlAttrPtr) target)->parent; } base = xmlNodeGetBase(target->doc, target); } else { xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if ((tctxt != NULL) && (tctxt->inst != NULL)) { base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst); } else if ((tctxt != NULL) && (tctxt->style != NULL) && (tctxt->style->doc != NULL)) { base = xmlNodeGetBase(tctxt->style->doc, (xmlNodePtr) tctxt->style->doc); } } URI = xmlBuildURI(obj->stringval, base); if (base != NULL) xmlFree(base); if (URI == NULL) { valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { xsltTransformContextPtr tctxt; tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); xsltGenericError(xsltGenericErrorContext, "document() : internal error tctxt == NULL\n"); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); } else { if (xmlStrEqual(tctxt->style->doc->URL, URI)) { valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr)tctxt->style->doc)); } else { doc = xsltLoadDocument(tctxt, URI); if (doc == NULL) valuePush(ctxt, xmlXPathNewNodeSet(NULL)); else { /* TODO: use XPointer of HTML location for fragment ID */ /* pbm #xxx can lead to location sets, not nodesets :-) */ valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc->doc)); } } } xmlFree(URI); } } xmlXPathFreeObject(obj); if (obj2 != NULL) xmlXPathFreeObject(obj2); }