1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021 |
- /*
- * functions.c: Implementation of the XSLT extra functions
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- * Bjorn Reese <breese@users.sourceforge.net> for number formatting
- */
- #define IN_LIBXSLT
- #include "libxslt.h"
- #include <string.h>
- #ifdef HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
- #ifdef HAVE_CTYPE_H
- #include <ctype.h>
- #endif
- #include <libxml/xmlmemory.h>
- #include <libxml/parser.h>
- #include <libxml/tree.h>
- #include <libxml/valid.h>
- #include <libxml/hash.h>
- #include <libxml/xmlerror.h>
- #include <libxml/xpath.h>
- #include <libxml/xpathInternals.h>
- #include <libxml/parserInternals.h>
- #include <libxml/uri.h>
- #include <libxml/xpointer.h>
- #include "xslt.h"
- #include "xsltInternals.h"
- #include "xsltutils.h"
- #include "functions.h"
- #include "extensions.h"
- #include "numbersInternals.h"
- #include "keys.h"
- #include "documents.h"
- #ifdef WITH_XSLT_DEBUG
- #define WITH_XSLT_DEBUG_FUNCTION
- #endif
- /*
- * Some versions of DocBook XSL use the vendor string to detect
- * supporting chunking, this is a workaround to be considered
- * in the list of decent XSLT processors <grin/>
- */
- #define DOCBOOK_XSL_HACK
- /**
- * xsltXPathFunctionLookup:
- * @vctxt: a void * but the XSLT transformation context actually
- * @name: the function name
- * @ns_uri: the function namespace URI
- *
- * This is the entry point when a function is needed by the XPath
- * interpretor.
- *
- * Returns the callback function or NULL if not found
- */
- xmlXPathFunction
- xsltXPathFunctionLookup (void *vctxt,
- const xmlChar *name, const xmlChar *ns_uri) {
- xmlXPathContextPtr ctxt = (xmlXPathContextPtr) vctxt;
- xmlXPathFunction ret;
- if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))
- return (NULL);
- #ifdef WITH_XSLT_DEBUG_FUNCTION
- xsltGenericDebug(xsltGenericDebugContext,
- "Lookup function {%s}%s\n", ns_uri, name);
- #endif
- /* give priority to context-level functions */
- /*
- ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
- */
- XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
- if (ret == NULL)
- ret = xsltExtModuleFunctionLookup(name, ns_uri);
- #ifdef WITH_XSLT_DEBUG_FUNCTION
- if (ret != NULL)
- xsltGenericDebug(xsltGenericDebugContext,
- "found function %s\n", name);
- #endif
- return(ret);
- }
- /************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
- static void
- xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
- {
- xsltTransformContextPtr tctxt;
- xmlURIPtr uri;
- xmlChar *fragment;
- xsltDocumentPtr idoc; /* document info */
- xmlDocPtr doc;
- xmlXPathContextPtr xptrctxt = NULL;
- xmlXPathObjectPtr resObj = NULL;
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "document() : internal error tctxt == NULL\n");
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- return;
- }
- uri = xmlParseURI((const char *) URI);
- if (uri == NULL) {
- xsltTransformError(tctxt, NULL, NULL,
- "document() : failed to parse URI\n");
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- return;
- }
- /*
- * check for and remove fragment identifier
- */
- fragment = (xmlChar *)uri->fragment;
- if (fragment != NULL) {
- xmlChar *newURI;
- uri->fragment = NULL;
- newURI = xmlSaveUri(uri);
- idoc = xsltLoadDocument(tctxt, newURI);
- xmlFree(newURI);
- } else
- idoc = xsltLoadDocument(tctxt, URI);
- xmlFreeURI(uri);
- if (idoc == NULL) {
- if ((URI == NULL) ||
- (URI[0] == '#') ||
- ((tctxt->style->doc != NULL) &&
- (xmlStrEqual(tctxt->style->doc->URL, URI))))
- {
- /*
- * This selects the stylesheet's doc itself.
- */
- doc = tctxt->style->doc;
- } else {
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- if (fragment != NULL)
- xmlFree(fragment);
- return;
- }
- } else
- doc = idoc->doc;
- if (fragment == NULL) {
- valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
- return;
- }
- /* use XPointer of HTML location for fragment ID */
- #ifdef LIBXML_XPTR_ENABLED
- xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
- if (xptrctxt == NULL) {
- xsltTransformError(tctxt, NULL, NULL,
- "document() : internal error xptrctxt == NULL\n");
- goto out_fragment;
- }
- #if LIBXML_VERSION >= 20911 || \
- defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
- xptrctxt->opLimit = ctxt->context->opLimit;
- xptrctxt->opCount = ctxt->context->opCount;
- xptrctxt->depth = ctxt->context->depth;
- resObj = xmlXPtrEval(fragment, xptrctxt);
- ctxt->context->opCount = xptrctxt->opCount;
- #else
- resObj = xmlXPtrEval(fragment, xptrctxt);
- #endif
- xmlXPathFreeContext(xptrctxt);
- #endif /* LIBXML_XPTR_ENABLED */
- if (resObj == NULL)
- goto out_fragment;
- switch (resObj->type) {
- case XPATH_NODESET:
- break;
- case XPATH_UNDEFINED:
- case XPATH_BOOLEAN:
- case XPATH_NUMBER:
- case XPATH_STRING:
- case XPATH_POINT:
- case XPATH_USERS:
- case XPATH_XSLT_TREE:
- case XPATH_RANGE:
- case XPATH_LOCATIONSET:
- xsltTransformError(tctxt, NULL, NULL,
- "document() : XPointer does not select a node set: #%s\n",
- fragment);
- goto out_object;
- }
- valuePush(ctxt, resObj);
- xmlFree(fragment);
- return;
- out_object:
- xmlXPathFreeObject(resObj);
- out_fragment:
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- xmlFree(fragment);
- }
- /**
- * 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)
- {
- xmlXPathObjectPtr obj, obj2 = NULL;
- xmlChar *base = NULL, *URI;
- if ((nargs < 1) || (nargs > 2)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : invalid number of args %d\n",
- nargs);
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if (ctxt->value == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : invalid arg value\n");
- ctxt->error = XPATH_INVALID_TYPE;
- return;
- }
- if (nargs == 2) {
- if (ctxt->value->type != XPATH_NODESET) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "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 != NULL) && 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);
- }
- }
- if (obj != NULL)
- 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) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "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 {
- xsltTransformContextPtr tctxt;
- tctxt = xsltXPathGetTransformContext(ctxt);
- 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->type == XML_PI_NODE)) {
- target = ((xmlAttrPtr) target)->parent;
- }
- base = xmlNodeGetBase(target->doc, target);
- } else {
- 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) {
- if ((tctxt != NULL) && (tctxt->style != NULL) &&
- (tctxt->style->doc != NULL) &&
- (xmlStrEqual(URI, tctxt->style->doc->URL))) {
- /* This selects the stylesheet's doc itself. */
- valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) tctxt->style->doc));
- } else {
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- }
- } else {
- xsltDocumentFunctionLoadDocument( ctxt, URI );
- xmlFree(URI);
- }
- }
- xmlXPathFreeObject(obj);
- if (obj2 != NULL)
- xmlXPathFreeObject(obj2);
- }
- /**
- * 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){
- xmlXPathObjectPtr obj1, obj2;
- if (nargs != 2) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "key() : expects two arguments\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- /*
- * Get the key's value.
- */
- obj2 = valuePop(ctxt);
- xmlXPathStringFunction(ctxt, 1);
- if ((obj2 == NULL) ||
- (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "key() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- xmlXPathFreeObject(obj2);
- return;
- }
- /*
- * Get the key's name.
- */
- obj1 = valuePop(ctxt);
- if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {
- 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 {
- xmlNodeSetPtr nodelist = NULL;
- xmlChar *key = NULL, *value;
- const xmlChar *keyURI;
- xsltTransformContextPtr tctxt;
- xmlChar *qname, *prefix;
- xmlXPathContextPtr xpctxt = ctxt->context;
- xmlNodePtr tmpNode = NULL;
- xsltDocumentPtr oldDocInfo;
- tctxt = xsltXPathGetTransformContext(ctxt);
- oldDocInfo = tctxt->document;
- if (xpctxt->node == NULL) {
- xsltTransformError(tctxt, NULL, tctxt->inst,
- "Internal error in xsltKeyFunction(): "
- "The context node is not set on the XPath context.\n");
- tctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- /*
- * 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(xpctxt, prefix);
- if (keyURI == NULL) {
- xsltTransformError(tctxt, NULL, tctxt->inst,
- "key() : prefix %s is not bound\n", prefix);
- /*
- * TODO: Shouldn't we stop here?
- */
- }
- 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)) {
- xsltTransformError(tctxt, NULL, tctxt->inst,
- "key() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- goto error;
- }
- obj2 = valuePop(ctxt);
- value = obj2->stringval;
- /*
- * We need to ensure that ctxt->document is available for
- * xsltGetKey().
- * First find the relevant doc, which is the context node's
- * owner doc; using context->doc is not safe, since
- * the doc could have been acquired via the document() function,
- * or the doc might be a Result Tree Fragment.
- * FUTURE INFO: In XSLT 2.0 the key() function takes an additional
- * argument indicating the doc to use.
- */
- if (xpctxt->node->type == XML_NAMESPACE_DECL) {
- /*
- * REVISIT: This is a libxml hack! Check xpath.c for details.
- * The XPath module sets the owner element of a ns-node on
- * the ns->next field.
- */
- if ((((xmlNsPtr) xpctxt->node)->next != NULL) &&
- (((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE))
- {
- tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next;
- }
- } else
- tmpNode = xpctxt->node;
- if ((tmpNode == NULL) || (tmpNode->doc == NULL)) {
- xsltTransformError(tctxt, NULL, tctxt->inst,
- "Internal error in xsltKeyFunction(): "
- "Couldn't get the doc of the XPath context node.\n");
- goto error;
- }
- if ((tctxt->document == NULL) ||
- (tctxt->document->doc != tmpNode->doc))
- {
- if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) {
- /*
- * This is a Result Tree Fragment.
- */
- if (tmpNode->doc->_private == NULL) {
- tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc);
- if (tmpNode->doc->_private == NULL)
- goto error;
- }
- tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private;
- } else {
- /*
- * May be the initial source doc or a doc acquired via the
- * document() function.
- */
- tctxt->document = xsltFindDocument(tctxt, tmpNode->doc);
- }
- if (tctxt->document == NULL) {
- xsltTransformError(tctxt, NULL, tctxt->inst,
- "Internal error in xsltKeyFunction(): "
- "Could not get the document info of a context doc.\n");
- tctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- }
- /*
- * Get/compute the key value.
- */
- nodelist = xsltGetKey(tctxt, key, keyURI, value);
- error:
- tctxt->document = oldDocInfo;
- valuePush(ctxt, xmlXPathWrapNodeSet(
- xmlXPathNodeSetMerge(NULL, nodelist)));
- if (key != NULL)
- xmlFree(key);
- }
- if (obj1 != NULL)
- xmlXPathFreeObject(obj1);
- if (obj2 != NULL)
- xmlXPathFreeObject(obj2);
- }
- /**
- * xsltUnparsedEntityURIFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the unparsed-entity-uri() XSLT function
- * string unparsed-entity-uri(string)
- */
- void
- xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlXPathObjectPtr obj;
- xmlChar *str;
- if ((nargs != 1) || (ctxt->value == NULL)) {
- xsltGenericError(xsltGenericErrorContext,
- "unparsed-entity-uri() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- obj = valuePop(ctxt);
- if (obj->type != XPATH_STRING) {
- obj = xmlXPathConvertString(obj);
- }
- str = obj->stringval;
- if (str == NULL) {
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- } else {
- xmlEntityPtr entity;
- entity = xmlGetDocEntity(ctxt->context->doc, str);
- if (entity == NULL) {
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- } else {
- if (entity->URI != NULL)
- valuePush(ctxt, xmlXPathNewString(entity->URI));
- else
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- }
- }
- xmlXPathFreeObject(obj);
- }
- /**
- * xsltFormatNumberFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the format-number() XSLT function
- * string format-number(number, string, string?)
- */
- void
- xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
- {
- xmlXPathObjectPtr numberObj = NULL;
- xmlXPathObjectPtr formatObj = NULL;
- xmlXPathObjectPtr decimalObj = NULL;
- xsltStylesheetPtr sheet;
- xsltDecimalFormatPtr formatValues = NULL;
- xmlChar *result;
- const xmlChar *ncname;
- const xmlChar *prefix = NULL;
- const xmlChar *nsUri = NULL;
- xsltTransformContextPtr tctxt;
- tctxt = xsltXPathGetTransformContext(ctxt);
- if ((tctxt == NULL) || (tctxt->inst == NULL))
- return;
- sheet = tctxt->style;
- if (sheet == NULL)
- return;
- formatValues = sheet->decimalFormat;
- switch (nargs) {
- case 3:
- CAST_TO_STRING;
- decimalObj = valuePop(ctxt);
- ncname = xsltSplitQName(sheet->dict, decimalObj->stringval, &prefix);
- if (prefix != NULL) {
- xmlNsPtr ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, prefix);
- if (ns == NULL) {
- xsltTransformError(tctxt, NULL, NULL,
- "format-number : No namespace found for QName '%s:%s'\n",
- prefix, ncname);
- sheet->errors++;
- ncname = NULL;
- }
- else {
- nsUri = ns->href;
- }
- }
- if (ncname != NULL) {
- formatValues = xsltDecimalFormatGetByQName(sheet, nsUri, ncname);
- }
- if (formatValues == NULL) {
- xsltTransformError(tctxt, NULL, NULL,
- "format-number() : undeclared decimal format '%s'\n",
- decimalObj->stringval);
- }
- /* Intentional fall-through */
- case 2:
- CAST_TO_STRING;
- formatObj = valuePop(ctxt);
- CAST_TO_NUMBER;
- numberObj = valuePop(ctxt);
- break;
- default:
- XP_ERROR(XPATH_INVALID_ARITY);
- }
- if (formatValues != NULL) {
- if (xsltFormatNumberConversion(formatValues,
- formatObj->stringval,
- numberObj->floatval,
- &result) == XPATH_EXPRESSION_OK) {
- valuePush(ctxt, xmlXPathNewString(result));
- xmlFree(result);
- }
- }
- xmlXPathFreeObject(numberObj);
- xmlXPathFreeObject(formatObj);
- xmlXPathFreeObject(decimalObj);
- }
- /**
- * 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){
- static char base_address;
- xmlNodePtr cur = NULL;
- xmlXPathObjectPtr obj = NULL;
- long val;
- xmlChar str[30];
- if (nargs == 0) {
- cur = ctxt->context->node;
- } else if (nargs == 1) {
- xmlNodeSetPtr nodelist;
- int i, ret;
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
- ctxt->error = XPATH_INVALID_TYPE;
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "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];
- }
- } else {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "generate-id() : invalid number of args %d\n", nargs);
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if (obj)
- xmlXPathFreeObject(obj);
- val = (long)((char *)cur - (char *)&base_address);
- if (val >= 0) {
- snprintf((char *)str, sizeof(str), "idp%ld", val);
- } else {
- snprintf((char *)str, sizeof(str), "idm%ld", -val);
- }
- valuePush(ctxt, xmlXPathNewString(str));
- }
- /**
- * 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) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "system-property() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "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) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "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 *)""));
- }
- } else {
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- }
- if (name != NULL)
- xmlFree(name);
- if (prefix != NULL)
- xmlFree(prefix);
- }
- xmlXPathFreeObject(obj);
- }
- /**
- * xsltElementAvailableFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the element-available() XSLT function
- * boolean element-available(string)
- */
- void
- xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlXPathObjectPtr obj;
- xmlChar *prefix, *name;
- const xmlChar *nsURI = NULL;
- xsltTransformContextPtr tctxt;
- if (nargs != 1) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- xmlXPathStringFunction(ctxt, 1);
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- return;
- }
- obj = valuePop(ctxt);
- tctxt = xsltXPathGetTransformContext(ctxt);
- if ((tctxt == NULL) || (tctxt->inst == NULL)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : internal error tctxt == NULL\n");
- xmlXPathFreeObject(obj);
- valuePush(ctxt, xmlXPathNewBoolean(0));
- return;
- }
- name = xmlSplitQName2(obj->stringval, &prefix);
- if (name == NULL) {
- xmlNsPtr ns;
- name = xmlStrdup(obj->stringval);
- ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
- if (ns != NULL) nsURI = ns->href;
- } else {
- nsURI = xmlXPathNsLookup(ctxt->context, prefix);
- if (nsURI == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : prefix %s is not bound\n", prefix);
- }
- }
- if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
- valuePush(ctxt, xmlXPathNewBoolean(1));
- } else {
- valuePush(ctxt, xmlXPathNewBoolean(0));
- }
- xmlXPathFreeObject(obj);
- if (name != NULL)
- xmlFree(name);
- if (prefix != NULL)
- xmlFree(prefix);
- }
- /**
- * 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) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "function-available() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- xmlXPathStringFunction(ctxt, 1);
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "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) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "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) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "current() : function uses no argument\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "current() : internal error tctxt == NULL\n");
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- } else {
- valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */
- }
- }
- /************************************************************************
- * *
- * Registration of XSLT and libxslt functions *
- * *
- ************************************************************************/
- /**
- * xsltRegisterAllFunctions:
- * @ctxt: the XPath context
- *
- * Registers all default XSLT functions in this context
- */
- void
- xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
- {
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
- xsltCurrentFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
- xsltDocumentFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
- xsltUnparsedEntityURIFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
- xsltFormatNumberFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
- xsltGenerateIdFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
- xsltSystemPropertyFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
- xsltElementAvailableFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
- xsltFunctionAvailableFunction);
- }
|