2 #include "libexslt/libexslt.h"
4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
5 #include <win32config.h>
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>
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>
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 */
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? */
40 typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
41 struct _exsltFuncResultPreComp {
43 xmlXPathCompExprPtr select;
46 /* Used for callback function in exsltInitFunc */
47 typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
48 struct _exsltFuncImportRegData {
49 xsltTransformContextPtr ctxt;
53 static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
55 static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
58 * exsltFuncRegisterFunc:
59 * @func: the #exsltFuncFunctionData for the function
60 * @ctxt: an XSLT transformation context
61 * @URI: the function namespace URI
62 * @name: the function name
64 * Registers a function declared by a func:function element
67 exsltFuncRegisterFunc (exsltFuncFunctionData *data,
68 xsltTransformContextPtr ctxt,
69 const xmlChar *URI, const xmlChar *name) {
70 if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
73 xsltGenericDebug(xsltGenericDebugContext,
74 "exsltFuncRegisterFunc: register {%s}%s\n",
76 xsltRegisterExtFunction(ctxt, name, URI,
77 exsltFuncFunctionFunction);
81 * exsltFuncRegisterImportFunc
82 * @data: the exsltFuncFunctionData for the function
83 * @ch: structure containing context and hash table
84 * @URI: the function namespace URI
85 * @name: the function name
87 * Checks if imported function is already registered in top-level
88 * stylesheet. If not, copies function data and registers function
91 exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,
92 exsltFuncImportRegData *ch,
93 const xmlChar *URI, const xmlChar *name) {
94 exsltFuncFunctionData *func=NULL;
96 if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))
99 if (ch->ctxt == NULL || ch->hash == NULL)
102 /* Check if already present */
103 func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash,
105 if (func == NULL) { /* Not yet present - copy it in */
106 func = exsltFuncNewFunctionData();
107 memcpy(func, data, sizeof(exsltFuncFunctionData));
108 if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {
109 xsltGenericError(xsltGenericErrorContext,
110 "Failed to register function {%s}%s\n",
112 } else { /* Do the registration */
113 xsltGenericDebug(xsltGenericDebugContext,
114 "exsltFuncRegisterImportFunc: register {%s}%s\n",
116 xsltRegisterExtFunction(ch->ctxt, name, URI,
117 exsltFuncFunctionFunction);
124 * @ctxt: an XSLT transformation context
125 * @URI: the namespace URI for the extension
127 * Initializes the EXSLT - Functions module.
129 * Returns the data for this transformation
131 static exsltFuncData *
132 exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
134 xsltStylesheetPtr tmp;
135 exsltFuncImportRegData ch;
136 xmlHashTablePtr hash;
138 ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
140 xsltGenericError(xsltGenericErrorContext,
141 "exsltFuncInit: not enough memory\n");
144 memset(ret, 0, sizeof(exsltFuncData));
149 ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
150 ret->funcs = ch.hash;
151 xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
154 while ((tmp=xsltNextImport(tmp))!=NULL) {
155 hash = xsltGetExtInfo(tmp, URI);
157 xmlHashScanFull(hash,
158 (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);
167 * @ctxt: an XSLT transformation context
168 * @URI: the namespace URI for the extension
169 * @data: the module data to free up
171 * Shutdown the EXSLT - Functions module
174 exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
175 const xmlChar *URI ATTRIBUTE_UNUSED,
176 exsltFuncData *data) {
177 if (data->result != NULL)
178 xmlXPathFreeObject(data->result);
183 * exsltFuncStyleInit:
184 * @style: an XSLT stylesheet
185 * @URI: the namespace URI for the extension
187 * Allocates the stylesheet data for EXSLT - Function
189 * Returns the allocated data
191 static xmlHashTablePtr
192 exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
193 const xmlChar *URI ATTRIBUTE_UNUSED) {
194 return xmlHashCreate(1);
198 * exsltFuncStyleShutdown:
199 * @style: an XSLT stylesheet
200 * @URI: the namespace URI for the extension
201 * @data: the stylesheet data to free up
203 * Shutdown the EXSLT - Function module
206 exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
207 const xmlChar *URI ATTRIBUTE_UNUSED,
208 xmlHashTablePtr data) {
209 xmlHashFree(data, (xmlHashDeallocator) xmlFree);
213 * exsltFuncNewFunctionData:
215 * Allocates an #exslFuncFunctionData object
217 * Returns the new structure
219 static exsltFuncFunctionData *
220 exsltFuncNewFunctionData (void) {
221 exsltFuncFunctionData *ret;
223 ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
225 xsltGenericError(xsltGenericErrorContext,
226 "exsltFuncNewFunctionData: not enough memory\n");
229 memset(ret, 0, sizeof(exsltFuncFunctionData));
238 * exsltFreeFuncResultPreComp:
239 * @comp: the #exsltFuncResultPreComp to free up
241 * Deallocates an #exsltFuncResultPreComp
244 exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
248 if (comp->select != NULL)
249 xmlXPathFreeCompExpr (comp->select);
254 * exsltFuncFunctionFunction:
255 * @ctxt: an XPath parser context
256 * @nargs: the number of arguments
258 * Evaluates the func:function element that defines the called function.
261 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
262 xmlXPathObjectPtr obj, oldResult, ret;
264 exsltFuncFunctionData *func;
265 xmlNodePtr paramNode, oldInsert, fake, content = NULL;
267 xsltStackElemPtr params = NULL, param;
268 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
272 * retrieve func:function template
274 data = (exsltFuncData *) xsltGetExtData (tctxt,
275 EXSLT_FUNCTIONS_NAMESPACE);
276 oldResult = data->result;
279 func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
280 ctxt->context->functionURI,
281 ctxt->context->function);
286 if (nargs > func->nargs) {
287 xsltGenericError(xsltGenericErrorContext,
288 "{%s}%s: called with too many arguments\n",
289 ctxt->context->functionURI, ctxt->context->function);
290 ctxt->error = XPATH_INVALID_ARITY;
293 if (func->content != NULL) {
294 paramNode = func->content->prev;
295 content = func->content;
299 if ((paramNode == NULL) && (func->nargs != 0)) {
300 xsltGenericError(xsltGenericErrorContext,
301 "exsltFuncFunctionFunction: nargs != 0 and "
307 for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {
308 paramNode = paramNode->prev;
310 content = content->prev;
312 while ((i-- > 0) && (paramNode != NULL)) {
313 obj = valuePop(ctxt);
314 /* FIXME: this is a bit hackish */
315 param = xsltParseStylesheetCallerParam (tctxt, paramNode);
317 if (param->value != NULL)
318 xmlXPathFreeObject(param->value);
320 param->next = params;
322 paramNode = paramNode->prev;
328 fake = xmlNewDocNode(tctxt->output, NULL,
329 (const xmlChar *)"fake", NULL);
330 oldInsert = tctxt->insert;
331 tctxt->insert = fake;
333 * In order to give the function variables a new 'scope' we
334 * change varsBase in the context.
336 oldBase = tctxt->varsBase;
337 tctxt->varsBase = tctxt->varsNr;
338 xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
339 content, NULL, params);
340 tctxt->insert = oldInsert;
341 tctxt->varsBase = oldBase; /* restore original scope */
343 xsltFreeStackElemList(params);
345 if (data->error != 0)
348 if (data->result != NULL)
351 ret = xmlXPathNewCString("");
353 data->result = oldResult;
356 * It is an error if the instantiation of the template results in
357 * the generation of result nodes.
359 if (fake->children != NULL) {
360 #ifdef LIBXML_DEBUG_ENABLED
361 xmlDebugDumpNode (stderr, fake, 1);
363 xsltGenericError(xsltGenericErrorContext,
364 "{%s}%s: cannot write to result tree while "
365 "executing a function\n",
366 ctxt->context->functionURI, ctxt->context->function);
371 valuePush(ctxt, ret);
376 exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
377 xmlChar *name, *prefix;
379 xmlHashTablePtr data;
380 exsltFuncFunctionData *func;
382 if ((style == NULL) || (inst == NULL))
389 qname = xmlGetProp(inst, (const xmlChar *) "name");
390 name = xmlSplitQName2 (qname, &prefix);
393 if ((name == NULL) || (prefix == NULL)) {
394 xsltGenericError(xsltGenericErrorContext,
395 "func:function: not a QName\n");
400 /* namespace lookup */
401 ns = xmlSearchNs (inst->doc, inst, prefix);
403 xsltGenericError(xsltGenericErrorContext,
404 "func:function: undeclared prefix %s\n",
413 * Create function data
415 func = exsltFuncNewFunctionData();
416 func->content = inst->children;
417 while (IS_XSLT_ELEM(func->content) &&
418 IS_XSLT_NAME(func->content, "param")) {
419 func->content = func->content->next;
423 xsltParseTemplateContent(style, inst);
426 * Register the function data such that it can be retrieved
427 * by exslFuncFunctionFunction
429 data = (xmlHashTablePtr) xsltStyleGetExtData (style,
430 EXSLT_FUNCTIONS_NAMESPACE);
432 xsltGenericError(xsltGenericErrorContext,
433 "exsltFuncFunctionComp: no stylesheet data\n");
438 if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
439 xsltGenericError(xsltGenericErrorContext,
440 "Failed to register function {%s}%s\n",
443 xsltGenericDebug(xsltGenericDebugContext,
444 "exsltFuncFunctionComp: register {%s}%s\n",
450 static xsltElemPreCompPtr
451 exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
452 xsltTransformFunction function) {
455 exsltFuncResultPreComp *ret;
458 * "Validity" checking
460 /* it is an error to have any following sibling elements aside
461 * from the xsl:fallback element.
463 for (test = inst->next; test != NULL; test = test->next) {
464 if (test->type != XML_ELEMENT_NODE)
466 if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
468 xsltGenericError(xsltGenericErrorContext,
469 "exsltFuncResultElem: only xsl:fallback is "
470 "allowed to follow func:result\n");
473 /* it is an error for a func:result element to not be a descendant
475 * it is an error if a func:result occurs within a func:result
477 * it is an error if instanciating the content of a variable
478 * binding element (i.e. xsl:variable, xsl:param) results in the
479 * instanciation of a func:result element.
481 for (test = inst->parent; test != NULL; test = test->parent) {
482 if ((test->ns != NULL) &&
483 (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
484 if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
487 if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
488 xsltGenericError(xsltGenericErrorContext,
489 "func:result element not allowed within"
490 " another func:result element\n");
494 if (IS_XSLT_ELEM(test) &&
495 (IS_XSLT_NAME(test, "variable") ||
496 IS_XSLT_NAME(test, "param"))) {
497 xsltGenericError(xsltGenericErrorContext,
498 "func:result element not allowed within"
499 " a variable binding element\n");
507 ret = (exsltFuncResultPreComp *)
508 xmlMalloc (sizeof(exsltFuncResultPreComp));
510 xsltPrintErrorContext(NULL, NULL, NULL);
511 xsltGenericError(xsltGenericErrorContext,
512 "exsltFuncResultComp : malloc failed\n");
515 memset(ret, 0, sizeof(exsltFuncResultPreComp));
517 xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
518 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
522 * Precompute the select attribute
524 select = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
525 if (select != NULL) {
526 ret->select = xmlXPathCompile (select);
530 return ((xsltElemPreCompPtr) ret);
534 exsltFuncResultElem (xsltTransformContextPtr ctxt,
535 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
536 exsltFuncResultPreComp *comp) {
538 xmlXPathObjectPtr ret;
540 /* It is an error if instantiating the content of the
541 * func:function element results in the instantiation of more than
542 * one func:result elements.
544 data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
546 xsltGenericError(xsltGenericErrorContext,
547 "exsltFuncReturnElem: data == NULL\n");
550 if (data->result != NULL) {
551 xsltGenericError(xsltGenericErrorContext,
552 "func:result already instanciated\n");
559 if (comp->select != NULL) {
560 /* If the func:result element has a select attribute, then the
561 * value of the attribute must be an expression and the
562 * returned value is the object that results from evaluating
563 * the expression. In this case, the content must be empty.
565 if (inst->children != NULL) {
566 xsltGenericError(xsltGenericErrorContext,
567 "func:result content must be empty if it"
568 " has a select attribute\n");
572 ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
574 xsltGenericError(xsltGenericErrorContext,
575 "exsltFuncResultElem: ret == NULL\n");
578 } else if (inst->children != NULL) {
579 /* If the func:result element does not have a select attribute
580 * and has non-empty content (i.e. the func:result element has
581 * one or more child nodes), then the content of the
582 * func:result element specifies the value.
584 xmlNodePtr oldInsert;
587 container = xsltCreateRVT(ctxt);
588 if (container == NULL) {
589 xsltGenericError(xsltGenericErrorContext,
590 "exsltFuncResultElem: out of memory\n");
594 xsltRegisterTmpRVT(ctxt, container);
595 oldInsert = ctxt->insert;
596 ctxt->insert = (xmlNodePtr) container;
597 xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
598 inst->children, NULL, NULL);
599 ctxt->insert = oldInsert;
601 ret = xmlXPathNewValueTree((xmlNodePtr) container);
603 xsltGenericError(xsltGenericErrorContext,
604 "exsltFuncResultElem: ret == NULL\n");
607 ret->boolval = 0; /* Freeing is not handled there anymore */
610 /* If the func:result element has empty content and does not
611 * have a select attribute, then the returned value is an
614 ret = xmlXPathNewCString("");
622 * Registers the EXSLT - Functions module
625 exsltFuncRegister (void) {
626 xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
627 (xsltExtInitFunction) exsltFuncInit,
628 (xsltExtShutdownFunction) exsltFuncShutdown,
629 (xsltStyleExtInitFunction) exsltFuncStyleInit,
630 (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
632 xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
633 EXSLT_FUNCTIONS_NAMESPACE,
634 exsltFuncFunctionComp);
635 xsltRegisterExtModuleElement ((const xmlChar *) "result",
636 EXSLT_FUNCTIONS_NAMESPACE,
637 (xsltPreComputeFunction)exsltFuncResultComp,
638 (xsltTransformFunction) exsltFuncResultElem);