Home | History | Annotate | Download | only in libexslt
      1 #define IN_LIBEXSLT
      2 #include "libexslt/libexslt.h"
      3 
      4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
      5 #include <win32config.h>
      6 #else
      7 #include "config.h"
      8 #endif
      9 
     10 #include <string.h>
     11 
     12 #include <libxml/tree.h>
     13 #include <libxml/xpath.h>
     14 #include <libxml/xpathInternals.h>
     15 #include <libxml/hash.h>
     16 #include <libxml/debugXML.h>
     17 
     18 #include <libxslt/xsltutils.h>
     19 #include <libxslt/variables.h>
     20 #include <libxslt/xsltInternals.h>
     21 #include <libxslt/extensions.h>
     22 #include <libxslt/transform.h>
     23 #include <libxslt/imports.h>
     24 
     25 #include "exslt.h"
     26 
     27 typedef struct _exsltFuncFunctionData exsltFuncFunctionData;
     28 struct _exsltFuncFunctionData {
     29     int nargs;			/* number of arguments to the function */
     30     xmlNodePtr content;		/* the func:fuction template content */
     31 };
     32 
     33 typedef struct _exsltFuncData exsltFuncData;
     34 struct _exsltFuncData {
     35     xmlHashTablePtr funcs;	/* pointer to the stylesheet module data */
     36     xmlXPathObjectPtr result;	/* returned by func:result */
     37     int error;			/* did an error occur? */
     38     xmlDocPtr RVT;   /* result tree fragment */
     39 };
     40 
     41 typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
     42 struct _exsltFuncResultPreComp {
     43     xsltElemPreComp comp;
     44     xmlXPathCompExprPtr select;
     45     xmlNsPtr *nsList;
     46     int nsNr;
     47 };
     48 
     49 /* Used for callback function in exsltInitFunc */
     50 typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
     51 struct _exsltFuncImportRegData {
     52     xsltTransformContextPtr ctxt;
     53     xmlHashTablePtr hash;
     54 };
     55 
     56 static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
     57 				       int nargs);
     58 static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
     59 
     60 #define MAX_FUNC_RECURSION 1000
     61 
     62 /*static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";*/
     63 
     64 /**
     65  * exsltFuncRegisterFunc:
     66  * @func:  the #exsltFuncFunctionData for the function
     67  * @ctxt:  an XSLT transformation context
     68  * @URI:  the function namespace URI
     69  * @name: the function name
     70  *
     71  * Registers a function declared by a func:function element
     72  */
     73 static void
     74 exsltFuncRegisterFunc (exsltFuncFunctionData *data,
     75 		       xsltTransformContextPtr ctxt,
     76 		       const xmlChar *URI, const xmlChar *name,
     77 		       ATTRIBUTE_UNUSED const xmlChar *ignored) {
     78     if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
     79 	return;
     80 
     81     xsltGenericDebug(xsltGenericDebugContext,
     82 		     "exsltFuncRegisterFunc: register {%s}%s\n",
     83 		     URI, name);
     84     xsltRegisterExtFunction(ctxt, name, URI,
     85 			    exsltFuncFunctionFunction);
     86 }
     87 
     88 /*
     89  * exsltFuncRegisterImportFunc
     90  * @data:    the exsltFuncFunctionData for the function
     91  * @ch:	     structure containing context and hash table
     92  * @URI:     the function namespace URI
     93  * @name:    the function name
     94  *
     95  * Checks if imported function is already registered in top-level
     96  * stylesheet.  If not, copies function data and registers function
     97  */
     98 static void
     99 exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,
    100 			     exsltFuncImportRegData *ch,
    101 			     const xmlChar *URI, const xmlChar *name,
    102 			     ATTRIBUTE_UNUSED const xmlChar *ignored) {
    103     exsltFuncFunctionData *func=NULL;
    104 
    105     if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))
    106             return;
    107 
    108     if (ch->ctxt == NULL || ch->hash == NULL)
    109     	return;
    110 
    111     /* Check if already present */
    112     func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name);
    113     if (func == NULL) {		/* Not yet present - copy it in */
    114     	func = exsltFuncNewFunctionData();
    115 	memcpy(func, data, sizeof(exsltFuncFunctionData));
    116 	if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {
    117 	    xsltGenericError(xsltGenericErrorContext,
    118 	    	    "Failed to register function {%s}%s\n",
    119 		    URI, name);
    120 	} else {		/* Do the registration */
    121 	    xsltGenericDebug(xsltGenericDebugContext,
    122 	            "exsltFuncRegisterImportFunc: register {%s}%s\n",
    123 		    URI, name);
    124 	    xsltRegisterExtFunction(ch->ctxt, name, URI,
    125 		    exsltFuncFunctionFunction);
    126 	}
    127     }
    128 }
    129 
    130 /**
    131  * exsltFuncInit:
    132  * @ctxt: an XSLT transformation context
    133  * @URI: the namespace URI for the extension
    134  *
    135  * Initializes the EXSLT - Functions module.
    136  * Called at transformation-time; merges all
    137  * functions declared in the import tree taking
    138  * import precedence into account, i.e. overriding
    139  * functions with lower import precedence.
    140  *
    141  * Returns the data for this transformation
    142  */
    143 static exsltFuncData *
    144 exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
    145     exsltFuncData *ret;
    146     xsltStylesheetPtr tmp;
    147     exsltFuncImportRegData ch;
    148     xmlHashTablePtr hash;
    149 
    150     ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
    151     if (ret == NULL) {
    152 	xsltGenericError(xsltGenericErrorContext,
    153 			 "exsltFuncInit: not enough memory\n");
    154 	return(NULL);
    155     }
    156     memset(ret, 0, sizeof(exsltFuncData));
    157 
    158     ret->result = NULL;
    159     ret->error = 0;
    160 
    161     ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
    162     ret->funcs = ch.hash;
    163     xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
    164     tmp = ctxt->style;
    165     ch.ctxt = ctxt;
    166     while ((tmp=xsltNextImport(tmp))!=NULL) {
    167 	hash = xsltGetExtInfo(tmp, URI);
    168 	if (hash != NULL) {
    169 	    xmlHashScanFull(hash,
    170 		    (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);
    171 	}
    172     }
    173 
    174     return(ret);
    175 }
    176 
    177 /**
    178  * exsltFuncShutdown:
    179  * @ctxt: an XSLT transformation context
    180  * @URI: the namespace URI for the extension
    181  * @data: the module data to free up
    182  *
    183  * Shutdown the EXSLT - Functions module
    184  * Called at transformation-time.
    185  */
    186 static void
    187 exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
    188 		   const xmlChar *URI ATTRIBUTE_UNUSED,
    189 		   exsltFuncData *data) {
    190     if (data->result != NULL)
    191 	xmlXPathFreeObject(data->result);
    192     xmlFree(data);
    193 }
    194 
    195 /**
    196  * exsltFuncStyleInit:
    197  * @style: an XSLT stylesheet
    198  * @URI: the namespace URI for the extension
    199  *
    200  * Allocates the stylesheet data for EXSLT - Function
    201  * Called at compile-time.
    202  *
    203  * Returns the allocated data
    204  */
    205 static xmlHashTablePtr
    206 exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
    207 		    const xmlChar *URI ATTRIBUTE_UNUSED) {
    208     return xmlHashCreate(1);
    209 }
    210 
    211 /**
    212  * exsltFuncStyleShutdown:
    213  * @style: an XSLT stylesheet
    214  * @URI: the namespace URI for the extension
    215  * @data: the stylesheet data to free up
    216  *
    217  * Shutdown the EXSLT - Function module
    218  * Called at compile-time.
    219  */
    220 static void
    221 exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
    222 			const xmlChar *URI ATTRIBUTE_UNUSED,
    223 			xmlHashTablePtr data) {
    224     xmlHashFree(data, (xmlHashDeallocator) xmlFree);
    225 }
    226 
    227 /**
    228  * exsltFuncNewFunctionData:
    229  *
    230  * Allocates an #exslFuncFunctionData object
    231  *
    232  * Returns the new structure
    233  */
    234 static exsltFuncFunctionData *
    235 exsltFuncNewFunctionData (void) {
    236     exsltFuncFunctionData *ret;
    237 
    238     ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
    239     if (ret == NULL) {
    240 	xsltGenericError(xsltGenericErrorContext,
    241 			 "exsltFuncNewFunctionData: not enough memory\n");
    242 	return (NULL);
    243     }
    244     memset(ret, 0, sizeof(exsltFuncFunctionData));
    245 
    246     ret->nargs = 0;
    247     ret->content = NULL;
    248 
    249     return(ret);
    250 }
    251 
    252 /**
    253  * exsltFreeFuncResultPreComp:
    254  * @comp:  the #exsltFuncResultPreComp to free up
    255  *
    256  * Deallocates an #exsltFuncResultPreComp
    257  */
    258 static void
    259 exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
    260     if (comp == NULL)
    261 	return;
    262 
    263     if (comp->select != NULL)
    264 	xmlXPathFreeCompExpr (comp->select);
    265     if (comp->nsList != NULL)
    266         xmlFree(comp->nsList);
    267     xmlFree(comp);
    268 }
    269 
    270 /**
    271  * exsltFuncFunctionFunction:
    272  * @ctxt:  an XPath parser context
    273  * @nargs:  the number of arguments
    274  *
    275  * Evaluates the func:function element that defines the called function.
    276  */
    277 static void
    278 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    279     xmlXPathObjectPtr oldResult, ret;
    280     exsltFuncData *data;
    281     exsltFuncFunctionData *func;
    282     xmlNodePtr paramNode, oldInsert, fake;
    283     int oldBase;
    284     xsltStackElemPtr params = NULL, param;
    285     xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
    286     int i, notSet;
    287     struct objChain {
    288 	struct objChain *next;
    289 	xmlXPathObjectPtr obj;
    290     };
    291     struct objChain	*savedObjChain = NULL, *savedObj;
    292 
    293     /*
    294      * retrieve func:function template
    295      */
    296     data = (exsltFuncData *) xsltGetExtData (tctxt,
    297 					     EXSLT_FUNCTIONS_NAMESPACE);
    298     oldResult = data->result;
    299     data->result = NULL;
    300 
    301     func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
    302 						    ctxt->context->functionURI,
    303 						    ctxt->context->function);
    304 
    305     /*
    306      * params handling
    307      */
    308     if (nargs > func->nargs) {
    309 	xsltGenericError(xsltGenericErrorContext,
    310 			 "{%s}%s: called with too many arguments\n",
    311 			 ctxt->context->functionURI, ctxt->context->function);
    312 	ctxt->error = XPATH_INVALID_ARITY;
    313 	return;
    314     }
    315     if (func->content != NULL) {
    316 	paramNode = func->content->prev;
    317     }
    318     else
    319 	paramNode = NULL;
    320     if ((paramNode == NULL) && (func->nargs != 0)) {
    321 	xsltGenericError(xsltGenericErrorContext,
    322 			 "exsltFuncFunctionFunction: nargs != 0 and "
    323 			 "param == NULL\n");
    324 	return;
    325     }
    326     if (tctxt->funcLevel > MAX_FUNC_RECURSION) {
    327 	xsltGenericError(xsltGenericErrorContext,
    328 			 "{%s}%s: detected a recursion\n",
    329 			 ctxt->context->functionURI, ctxt->context->function);
    330 	ctxt->error = XPATH_MEMORY_ERROR;
    331 	return;
    332     }
    333     tctxt->funcLevel++;
    334 
    335     /*
    336      * We have a problem with the evaluation of function parameters.
    337      * The original library code did not evaluate XPath expressions until
    338      * the last moment.  After version 1.1.17 of the libxslt, the logic
    339      * of other parts of the library was changed, and the evaluation of
    340      * XPath expressions within parameters now takes place as soon as the
    341      * parameter is parsed/evaluated (xsltParseStylesheetCallerParam).
    342      * This means that the parameters need to be evaluated in lexical
    343      * order (since a variable is "in scope" as soon as it is declared).
    344      * However, on entry to this routine, the values (from the caller) are
    345      * in reverse order (held on the XPath context variable stack).  To
    346      * accomplish what is required, I have added code to pop the XPath
    347      * objects off of the stack at the beginning and save them, then use
    348      * them (in the reverse order) as the params are evaluated.  This
    349      * requires an xmlMalloc/xmlFree for each param set by the caller,
    350      * which is not very nice.  There is probably a much better solution
    351      * (like change other code to delay the evaluation).
    352      */
    353     /*
    354      * In order to give the function params and variables a new 'scope'
    355      * we change varsBase in the context.
    356      */
    357     oldBase = tctxt->varsBase;
    358     tctxt->varsBase = tctxt->varsNr;
    359     /* If there are any parameters */
    360     if (paramNode != NULL) {
    361         /* Fetch the stored argument values from the caller */
    362 	for (i = 0; i < nargs; i++) {
    363 	    savedObj = xmlMalloc(sizeof(struct objChain));
    364 	    savedObj->next = savedObjChain;
    365 	    savedObj->obj = valuePop(ctxt);
    366 	    savedObjChain = savedObj;
    367 	}
    368 
    369 	/*
    370 	 * Prepare to process params in reverse order.  First, go to
    371 	 * the beginning of the param chain.
    372 	 */
    373 	for (i = 1; i <= func->nargs; i++) {
    374 	    if (paramNode->prev == NULL)
    375 	        break;
    376 	    paramNode = paramNode->prev;
    377 	}
    378 	/*
    379 	 * i has total # params found, nargs is number which are present
    380 	 * as arguments from the caller
    381 	 * Calculate the number of un-set parameters
    382 	 */
    383 	notSet = func->nargs - nargs;
    384 	for (; i > 0; i--) {
    385 	    param = xsltParseStylesheetCallerParam (tctxt, paramNode);
    386 	    if (i > notSet) {	/* if parameter value set */
    387 		param->computed = 1;
    388 		if (param->value != NULL)
    389 		    xmlXPathFreeObject(param->value);
    390 		savedObj = savedObjChain;	/* get next val from chain */
    391 		param->value = savedObj->obj;
    392 		savedObjChain = savedObjChain->next;
    393 		xmlFree(savedObj);
    394 	    }
    395 	    xsltLocalVariablePush(tctxt, param, -1);
    396 	    param->next = params;
    397 	    params = param;
    398 	    paramNode = paramNode->next;
    399 	}
    400     }
    401     /*
    402      * actual processing
    403      */
    404     fake = xmlNewDocNode(tctxt->output, NULL,
    405 			 (const xmlChar *)"fake", NULL);
    406     oldInsert = tctxt->insert;
    407     tctxt->insert = fake;
    408     xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
    409 			  func->content, NULL, NULL);
    410     xsltLocalVariablePop(tctxt, tctxt->varsBase, -2);
    411     tctxt->insert = oldInsert;
    412     tctxt->varsBase = oldBase;	/* restore original scope */
    413     if (params != NULL)
    414 	xsltFreeStackElemList(params);
    415 
    416     if (data->error != 0)
    417 	goto error;
    418 
    419     if (data->result != NULL) {
    420 	ret = data->result;
    421     } else
    422 	ret = xmlXPathNewCString("");
    423 
    424     data->result = oldResult;
    425 
    426     /*
    427      * It is an error if the instantiation of the template results in
    428      * the generation of result nodes.
    429      */
    430     if (fake->children != NULL) {
    431 #ifdef LIBXML_DEBUG_ENABLED
    432 	xmlDebugDumpNode (stderr, fake, 1);
    433 #endif
    434 	xsltGenericError(xsltGenericErrorContext,
    435 			 "{%s}%s: cannot write to result tree while "
    436 			 "executing a function\n",
    437 			 ctxt->context->functionURI, ctxt->context->function);
    438 	xmlFreeNode(fake);
    439 	goto error;
    440     }
    441     xmlFreeNode(fake);
    442     valuePush(ctxt, ret);
    443 
    444 error:
    445     /*
    446     * IMPORTANT: This enables previously tree fragments marked as
    447     * being results of a function, to be garbage-collected after
    448     * the calling process exits.
    449     */
    450     xsltExtensionInstructionResultFinalize(tctxt);
    451     tctxt->funcLevel--;
    452 }
    453 
    454 
    455 static void
    456 exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
    457     xmlChar *name, *prefix;
    458     xmlNsPtr ns;
    459     xmlHashTablePtr data;
    460     exsltFuncFunctionData *func;
    461 
    462     if ((style == NULL) || (inst == NULL))
    463 	return;
    464 
    465 
    466     {
    467 	xmlChar *qname;
    468 
    469 	qname = xmlGetProp(inst, (const xmlChar *) "name");
    470 	name = xmlSplitQName2 (qname, &prefix);
    471 	xmlFree(qname);
    472     }
    473     if ((name == NULL) || (prefix == NULL)) {
    474 	xsltGenericError(xsltGenericErrorContext,
    475 			 "func:function: not a QName\n");
    476 	if (name != NULL)
    477 	    xmlFree(name);
    478 	return;
    479     }
    480     /* namespace lookup */
    481     ns = xmlSearchNs (inst->doc, inst, prefix);
    482     if (ns == NULL) {
    483 	xsltGenericError(xsltGenericErrorContext,
    484 			 "func:function: undeclared prefix %s\n",
    485 			 prefix);
    486 	xmlFree(name);
    487 	xmlFree(prefix);
    488 	return;
    489     }
    490     xmlFree(prefix);
    491 
    492     /*
    493      * Create function data
    494      */
    495     func = exsltFuncNewFunctionData();
    496     func->content = inst->children;
    497     while (IS_XSLT_ELEM(func->content) &&
    498 	   IS_XSLT_NAME(func->content, "param")) {
    499 	func->content = func->content->next;
    500 	func->nargs++;
    501     }
    502 
    503     xsltParseTemplateContent(style, inst);
    504 
    505     /*
    506      * Register the function data such that it can be retrieved
    507      * by exslFuncFunctionFunction
    508      */
    509 #ifdef XSLT_REFACTORED
    510     /*
    511     * Ensure that the hash table will be stored in the *current*
    512     * stylesheet level in order to correctly evaluate the
    513     * import precedence.
    514     */
    515     data = (xmlHashTablePtr)
    516 	xsltStyleStylesheetLevelGetExtData(style,
    517 	    EXSLT_FUNCTIONS_NAMESPACE);
    518 #else
    519     data = (xmlHashTablePtr)
    520 	xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE);
    521 #endif
    522     if (data == NULL) {
    523 	xsltGenericError(xsltGenericErrorContext,
    524 			 "exsltFuncFunctionComp: no stylesheet data\n");
    525 	xmlFree(name);
    526 	return;
    527     }
    528 
    529     if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
    530 	xsltTransformError(NULL, style, inst,
    531 	    "Failed to register function {%s}%s\n",
    532 			 ns->href, name);
    533 	style->errors++;
    534     } else {
    535 	xsltGenericDebug(xsltGenericDebugContext,
    536 			 "exsltFuncFunctionComp: register {%s}%s\n",
    537 			 ns->href, name);
    538     }
    539     xmlFree(name);
    540 }
    541 
    542 static xsltElemPreCompPtr
    543 exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
    544 		     xsltTransformFunction function) {
    545     xmlNodePtr test;
    546     xmlChar *sel;
    547     exsltFuncResultPreComp *ret;
    548 
    549     /*
    550      * "Validity" checking
    551      */
    552     /* it is an error to have any following sibling elements aside
    553      * from the xsl:fallback element.
    554      */
    555     for (test = inst->next; test != NULL; test = test->next) {
    556 	if (test->type != XML_ELEMENT_NODE)
    557 	    continue;
    558 	if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
    559 	    continue;
    560 	xsltGenericError(xsltGenericErrorContext,
    561 			 "exsltFuncResultElem: only xsl:fallback is "
    562 			 "allowed to follow func:result\n");
    563 	return (NULL);
    564     }
    565     /* it is an error for a func:result element to not be a descendant
    566      * of func:function.
    567      * it is an error if a func:result occurs within a func:result
    568      * element.
    569      * it is an error if instanciating the content of a variable
    570      * binding element (i.e. xsl:variable, xsl:param) results in the
    571      * instanciation of a func:result element.
    572      */
    573     for (test = inst->parent; test != NULL; test = test->parent) {
    574 	if (IS_XSLT_ELEM(test) &&
    575 	    IS_XSLT_NAME(test, "stylesheet")) {
    576 	    xsltGenericError(xsltGenericErrorContext,
    577 			     "func:result element not a descendant "
    578 			     "of a func:function\n");
    579 	    return (NULL);
    580 	}
    581 	if ((test->ns != NULL) &&
    582 	    (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
    583 	    if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
    584 		break;
    585 	    }
    586 	    if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
    587 		xsltGenericError(xsltGenericErrorContext,
    588 				 "func:result element not allowed within"
    589 				 " another func:result element\n");
    590 		return (NULL);
    591 	    }
    592 	}
    593 	if (IS_XSLT_ELEM(test) &&
    594 	    (IS_XSLT_NAME(test, "variable") ||
    595 	     IS_XSLT_NAME(test, "param"))) {
    596 	    xsltGenericError(xsltGenericErrorContext,
    597 			     "func:result element not allowed within"
    598 			     " a variable binding element\n");
    599 	    return (NULL);
    600 	}
    601     }
    602 
    603     /*
    604      * Precomputation
    605      */
    606     ret = (exsltFuncResultPreComp *)
    607 	xmlMalloc (sizeof(exsltFuncResultPreComp));
    608     if (ret == NULL) {
    609 	xsltPrintErrorContext(NULL, NULL, NULL);
    610         xsltGenericError(xsltGenericErrorContext,
    611                          "exsltFuncResultComp : malloc failed\n");
    612         return (NULL);
    613     }
    614     memset(ret, 0, sizeof(exsltFuncResultPreComp));
    615 
    616     xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
    617 		 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
    618     ret->select = NULL;
    619 
    620     /*
    621      * Precompute the select attribute
    622      */
    623     sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
    624     if (sel != NULL) {
    625 	ret->select = xmlXPathCompile (sel);
    626 	xmlFree(sel);
    627     }
    628     /*
    629      * Precompute the namespace list
    630      */
    631     ret->nsList = xmlGetNsList(inst->doc, inst);
    632     if (ret->nsList != NULL) {
    633         int i = 0;
    634         while (ret->nsList[i] != NULL)
    635 	    i++;
    636 	ret->nsNr = i;
    637     }
    638     return ((xsltElemPreCompPtr) ret);
    639 }
    640 
    641 static void
    642 exsltFuncResultElem (xsltTransformContextPtr ctxt,
    643 	             xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
    644 		     exsltFuncResultPreComp *comp) {
    645     exsltFuncData *data;
    646     xmlXPathObjectPtr ret;
    647 
    648 
    649     /* It is an error if instantiating the content of the
    650      * func:function element results in the instantiation of more than
    651      * one func:result elements.
    652      */
    653     data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
    654     if (data == NULL) {
    655 	xsltGenericError(xsltGenericErrorContext,
    656 			 "exsltFuncReturnElem: data == NULL\n");
    657 	return;
    658     }
    659     if (data->result != NULL) {
    660 	xsltGenericError(xsltGenericErrorContext,
    661 			 "func:result already instanciated\n");
    662 	data->error = 1;
    663 	return;
    664     }
    665     /*
    666      * Processing
    667      */
    668     if (comp->select != NULL) {
    669 	xmlNsPtr *oldXPNsList;
    670 	int oldXPNsNr;
    671 	xmlNodePtr oldXPContextNode;
    672 	/* If the func:result element has a select attribute, then the
    673 	 * value of the attribute must be an expression and the
    674 	 * returned value is the object that results from evaluating
    675 	 * the expression. In this case, the content must be empty.
    676 	 */
    677 	if (inst->children != NULL) {
    678 	    xsltGenericError(xsltGenericErrorContext,
    679 			     "func:result content must be empty if"
    680 			     " the function has a select attribute\n");
    681 	    data->error = 1;
    682 	    return;
    683 	}
    684 	oldXPNsList = ctxt->xpathCtxt->namespaces;
    685 	oldXPNsNr = ctxt->xpathCtxt->nsNr;
    686 	oldXPContextNode = ctxt->xpathCtxt->node;
    687 
    688 	ctxt->xpathCtxt->namespaces = comp->nsList;
    689 	ctxt->xpathCtxt->nsNr = comp->nsNr;
    690 
    691 	ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
    692 
    693 	ctxt->xpathCtxt->node = oldXPContextNode;
    694 	ctxt->xpathCtxt->nsNr = oldXPNsNr;
    695 	ctxt->xpathCtxt->namespaces = oldXPNsList;
    696 
    697 	if (ret == NULL) {
    698 	    xsltGenericError(xsltGenericErrorContext,
    699 			     "exsltFuncResultElem: ret == NULL\n");
    700 	    return;
    701 	}
    702 	/*
    703 	* Mark it as a function result in order to avoid garbage
    704 	* collecting of tree fragments before the function exits.
    705 	*/
    706 	xsltExtensionInstructionResultRegister(ctxt, ret);
    707     } else if (inst->children != NULL) {
    708 	/* If the func:result element does not have a select attribute
    709 	 * and has non-empty content (i.e. the func:result element has
    710 	 * one or more child nodes), then the content of the
    711 	 * func:result element specifies the value.
    712 	 */
    713 	xmlNodePtr oldInsert;
    714 	xmlDocPtr container;
    715 
    716 	container = xsltCreateRVT(ctxt);
    717 	if (container == NULL) {
    718 	    xsltGenericError(xsltGenericErrorContext,
    719 			     "exsltFuncResultElem: out of memory\n");
    720 	    data->error = 1;
    721 	    return;
    722 	}
    723 	xsltRegisterLocalRVT(ctxt, container);
    724 
    725 	oldInsert = ctxt->insert;
    726 	ctxt->insert = (xmlNodePtr) container;
    727 	xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
    728 			      inst->children, NULL, NULL);
    729 	ctxt->insert = oldInsert;
    730 
    731 	ret = xmlXPathNewValueTree((xmlNodePtr) container);
    732 	if (ret == NULL) {
    733 	    xsltGenericError(xsltGenericErrorContext,
    734 			     "exsltFuncResultElem: ret == NULL\n");
    735 	    data->error = 1;
    736 	} else {
    737 	    ret->boolval = 0; /* Freeing is not handled there anymore */
    738 	    /*
    739 	    * Mark it as a function result in order to avoid garbage
    740 	    * collecting of tree fragments before the function exits.
    741 	    */
    742 	    xsltExtensionInstructionResultRegister(ctxt, ret);
    743 	}
    744     } else {
    745 	/* If the func:result element has empty content and does not
    746 	 * have a select attribute, then the returned value is an
    747 	 * empty string.
    748 	 */
    749 	ret = xmlXPathNewCString("");
    750     }
    751     data->result = ret;
    752 }
    753 
    754 /**
    755  * exsltFuncRegister:
    756  *
    757  * Registers the EXSLT - Functions module
    758  */
    759 void
    760 exsltFuncRegister (void) {
    761     xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
    762 		       (xsltExtInitFunction) exsltFuncInit,
    763 		       (xsltExtShutdownFunction) exsltFuncShutdown,
    764 		       (xsltStyleExtInitFunction) exsltFuncStyleInit,
    765 		       (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
    766 
    767     xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
    768 				   EXSLT_FUNCTIONS_NAMESPACE,
    769 				   exsltFuncFunctionComp);
    770     xsltRegisterExtModuleElement ((const xmlChar *) "result",
    771 			  EXSLT_FUNCTIONS_NAMESPACE,
    772 			  (xsltPreComputeFunction)exsltFuncResultComp,
    773 			  (xsltTransformFunction) exsltFuncResultElem);
    774 }
    775