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;
48 /* Used for callback function in exsltInitFunc */
49 typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
50 struct _exsltFuncImportRegData {
51 xsltTransformContextPtr ctxt;
55 static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
57 static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
60 * exsltFuncRegisterFunc:
61 * @func: the #exsltFuncFunctionData for the function
62 * @ctxt: an XSLT transformation context
63 * @URI: the function namespace URI
64 * @name: the function name
66 * Registers a function declared by a func:function element
69 exsltFuncRegisterFunc (exsltFuncFunctionData *data,
70 xsltTransformContextPtr ctxt,
71 const xmlChar *URI, const xmlChar *name,
72 ATTRIBUTE_UNUSED const xmlChar *ignored) {
73 if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
76 xsltGenericDebug(xsltGenericDebugContext,
77 "exsltFuncRegisterFunc: register {%s}%s\n",
79 xsltRegisterExtFunction(ctxt, name, URI,
80 exsltFuncFunctionFunction);
84 * exsltFuncRegisterImportFunc
85 * @data: the exsltFuncFunctionData for the function
86 * @ch: structure containing context and hash table
87 * @URI: the function namespace URI
88 * @name: the function name
90 * Checks if imported function is already registered in top-level
91 * stylesheet. If not, copies function data and registers function
94 exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,
95 exsltFuncImportRegData *ch,
96 const xmlChar *URI, const xmlChar *name,
97 ATTRIBUTE_UNUSED const xmlChar *ignored) {
98 exsltFuncFunctionData *func=NULL;
100 if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))
103 if (ch->ctxt == NULL || ch->hash == NULL)
106 /* Check if already present */
107 func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name);
108 if (func == NULL) { /* Not yet present - copy it in */
109 func = exsltFuncNewFunctionData();
110 memcpy(func, data, sizeof(exsltFuncFunctionData));
111 if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {
112 xsltGenericError(xsltGenericErrorContext,
113 "Failed to register function {%s}%s\n",
115 } else { /* Do the registration */
116 xsltGenericDebug(xsltGenericDebugContext,
117 "exsltFuncRegisterImportFunc: register {%s}%s\n",
119 xsltRegisterExtFunction(ch->ctxt, name, URI,
120 exsltFuncFunctionFunction);
127 * @ctxt: an XSLT transformation context
128 * @URI: the namespace URI for the extension
130 * Initializes the EXSLT - Functions module.
132 * Returns the data for this transformation
134 static exsltFuncData *
135 exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
137 xsltStylesheetPtr tmp;
138 exsltFuncImportRegData ch;
139 xmlHashTablePtr hash;
141 ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
143 xsltGenericError(xsltGenericErrorContext,
144 "exsltFuncInit: not enough memory\n");
147 memset(ret, 0, sizeof(exsltFuncData));
152 ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
153 ret->funcs = ch.hash;
154 xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
157 while ((tmp=xsltNextImport(tmp))!=NULL) {
158 hash = xsltGetExtInfo(tmp, URI);
160 xmlHashScanFull(hash,
161 (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);
170 * @ctxt: an XSLT transformation context
171 * @URI: the namespace URI for the extension
172 * @data: the module data to free up
174 * Shutdown the EXSLT - Functions module
177 exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
178 const xmlChar *URI ATTRIBUTE_UNUSED,
179 exsltFuncData *data) {
180 if (data->result != NULL)
181 xmlXPathFreeObject(data->result);
186 * exsltFuncStyleInit:
187 * @style: an XSLT stylesheet
188 * @URI: the namespace URI for the extension
190 * Allocates the stylesheet data for EXSLT - Function
192 * Returns the allocated data
194 static xmlHashTablePtr
195 exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
196 const xmlChar *URI ATTRIBUTE_UNUSED) {
197 return xmlHashCreate(1);
201 * exsltFuncStyleShutdown:
202 * @style: an XSLT stylesheet
203 * @URI: the namespace URI for the extension
204 * @data: the stylesheet data to free up
206 * Shutdown the EXSLT - Function module
209 exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
210 const xmlChar *URI ATTRIBUTE_UNUSED,
211 xmlHashTablePtr data) {
212 xmlHashFree(data, (xmlHashDeallocator) xmlFree);
216 * exsltFuncNewFunctionData:
218 * Allocates an #exslFuncFunctionData object
220 * Returns the new structure
222 static exsltFuncFunctionData *
223 exsltFuncNewFunctionData (void) {
224 exsltFuncFunctionData *ret;
226 ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
228 xsltGenericError(xsltGenericErrorContext,
229 "exsltFuncNewFunctionData: not enough memory\n");
232 memset(ret, 0, sizeof(exsltFuncFunctionData));
241 * exsltFreeFuncResultPreComp:
242 * @comp: the #exsltFuncResultPreComp to free up
244 * Deallocates an #exsltFuncResultPreComp
247 exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
251 if (comp->select != NULL)
252 xmlXPathFreeCompExpr (comp->select);
253 if (comp->nsList != NULL)
254 xmlFree(comp->nsList);
259 * exsltFuncFunctionFunction:
260 * @ctxt: an XPath parser context
261 * @nargs: the number of arguments
263 * Evaluates the func:function element that defines the called function.
266 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
267 xmlXPathObjectPtr obj, oldResult, ret;
269 exsltFuncFunctionData *func;
270 xmlNodePtr paramNode, oldInsert, fake, content = NULL;
272 xsltStackElemPtr params = NULL, param;
273 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
277 * retrieve func:function template
279 data = (exsltFuncData *) xsltGetExtData (tctxt,
280 EXSLT_FUNCTIONS_NAMESPACE);
281 oldResult = data->result;
284 func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
285 ctxt->context->functionURI,
286 ctxt->context->function);
291 if (nargs > func->nargs) {
292 xsltGenericError(xsltGenericErrorContext,
293 "{%s}%s: called with too many arguments\n",
294 ctxt->context->functionURI, ctxt->context->function);
295 ctxt->error = XPATH_INVALID_ARITY;
298 if (func->content != NULL) {
299 paramNode = func->content->prev;
300 content = func->content;
304 if ((paramNode == NULL) && (func->nargs != 0)) {
305 xsltGenericError(xsltGenericErrorContext,
306 "exsltFuncFunctionFunction: nargs != 0 and "
312 for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {
313 paramNode = paramNode->prev;
315 content = content->prev;
317 while ((i-- > 0) && (paramNode != NULL)) {
318 obj = valuePop(ctxt);
319 /* FIXME: this is a bit hackish */
320 param = xsltParseStylesheetCallerParam (tctxt, paramNode);
322 if (param->value != NULL)
323 xmlXPathFreeObject(param->value);
325 param->next = params;
327 paramNode = paramNode->prev;
333 fake = xmlNewDocNode(tctxt->output, NULL,
334 (const xmlChar *)"fake", NULL);
335 oldInsert = tctxt->insert;
336 tctxt->insert = fake;
338 * In order to give the function variables a new 'scope' we
339 * change varsBase in the context.
341 oldBase = tctxt->varsBase;
342 tctxt->varsBase = tctxt->varsNr;
343 xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
344 content, NULL, params);
345 tctxt->insert = oldInsert;
346 tctxt->varsBase = oldBase; /* restore original scope */
348 xsltFreeStackElemList(params);
350 if (data->error != 0)
353 if (data->result != NULL)
356 ret = xmlXPathNewCString("");
358 data->result = oldResult;
361 * It is an error if the instantiation of the template results in
362 * the generation of result nodes.
364 if (fake->children != NULL) {
365 #ifdef LIBXML_DEBUG_ENABLED
366 xmlDebugDumpNode (stderr, fake, 1);
368 xsltGenericError(xsltGenericErrorContext,
369 "{%s}%s: cannot write to result tree while "
370 "executing a function\n",
371 ctxt->context->functionURI, ctxt->context->function);
376 valuePush(ctxt, ret);
381 exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
382 xmlChar *name, *prefix;
384 xmlHashTablePtr data;
385 exsltFuncFunctionData *func;
387 if ((style == NULL) || (inst == NULL))
394 qname = xmlGetProp(inst, (const xmlChar *) "name");
395 name = xmlSplitQName2 (qname, &prefix);
398 if ((name == NULL) || (prefix == NULL)) {
399 xsltGenericError(xsltGenericErrorContext,
400 "func:function: not a QName\n");
405 /* namespace lookup */
406 ns = xmlSearchNs (inst->doc, inst, prefix);
408 xsltGenericError(xsltGenericErrorContext,
409 "func:function: undeclared prefix %s\n",
418 * Create function data
420 func = exsltFuncNewFunctionData();
421 func->content = inst->children;
422 while (IS_XSLT_ELEM(func->content) &&
423 IS_XSLT_NAME(func->content, "param")) {
424 func->content = func->content->next;
428 xsltParseTemplateContent(style, inst);
431 * Register the function data such that it can be retrieved
432 * by exslFuncFunctionFunction
434 data = (xmlHashTablePtr) xsltStyleGetExtData (style,
435 EXSLT_FUNCTIONS_NAMESPACE);
437 xsltGenericError(xsltGenericErrorContext,
438 "exsltFuncFunctionComp: no stylesheet data\n");
443 if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
444 xsltGenericError(xsltGenericErrorContext,
445 "Failed to register function {%s}%s\n",
448 xsltGenericDebug(xsltGenericDebugContext,
449 "exsltFuncFunctionComp: register {%s}%s\n",
455 static xsltElemPreCompPtr
456 exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
457 xsltTransformFunction function) {
460 exsltFuncResultPreComp *ret;
463 * "Validity" checking
465 /* it is an error to have any following sibling elements aside
466 * from the xsl:fallback element.
468 for (test = inst->next; test != NULL; test = test->next) {
469 if (test->type != XML_ELEMENT_NODE)
471 if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
473 xsltGenericError(xsltGenericErrorContext,
474 "exsltFuncResultElem: only xsl:fallback is "
475 "allowed to follow func:result\n");
478 /* it is an error for a func:result element to not be a descendant
480 * it is an error if a func:result occurs within a func:result
482 * it is an error if instanciating the content of a variable
483 * binding element (i.e. xsl:variable, xsl:param) results in the
484 * instanciation of a func:result element.
486 for (test = inst->parent; test != NULL; test = test->parent) {
487 if ((test->ns != NULL) &&
488 (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
489 if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
492 if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
493 xsltGenericError(xsltGenericErrorContext,
494 "func:result element not allowed within"
495 " another func:result element\n");
499 if (IS_XSLT_ELEM(test) &&
500 (IS_XSLT_NAME(test, "variable") ||
501 IS_XSLT_NAME(test, "param"))) {
502 xsltGenericError(xsltGenericErrorContext,
503 "func:result element not allowed within"
504 " a variable binding element\n");
512 ret = (exsltFuncResultPreComp *)
513 xmlMalloc (sizeof(exsltFuncResultPreComp));
515 xsltPrintErrorContext(NULL, NULL, NULL);
516 xsltGenericError(xsltGenericErrorContext,
517 "exsltFuncResultComp : malloc failed\n");
520 memset(ret, 0, sizeof(exsltFuncResultPreComp));
522 xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
523 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
527 * Precompute the select attribute
529 sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
531 ret->select = xmlXPathCompile (sel);
535 * Precompute the namespace list
537 ret->nsList = xmlGetNsList(inst->doc, inst);
538 if (ret->nsList != NULL) {
540 while (ret->nsList[i] != NULL)
544 return ((xsltElemPreCompPtr) ret);
548 exsltFuncResultElem (xsltTransformContextPtr ctxt,
549 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
550 exsltFuncResultPreComp *comp) {
552 xmlXPathObjectPtr ret;
556 /* It is an error if instantiating the content of the
557 * func:function element results in the instantiation of more than
558 * one func:result elements.
560 data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
562 xsltGenericError(xsltGenericErrorContext,
563 "exsltFuncReturnElem: data == NULL\n");
566 if (data->result != NULL) {
567 xsltGenericError(xsltGenericErrorContext,
568 "func:result already instanciated\n");
575 if (comp->select != NULL) {
576 /* If the func:result element has a select attribute, then the
577 * value of the attribute must be an expression and the
578 * returned value is the object that results from evaluating
579 * the expression. In this case, the content must be empty.
581 if (inst->children != NULL) {
582 xsltGenericError(xsltGenericErrorContext,
583 "func:result content must be empty if it"
584 " has a select attribute\n");
588 oldNsList = ctxt->xpathCtxt->namespaces;
589 oldNsNr = ctxt->xpathCtxt->nsNr;
590 ctxt->xpathCtxt->namespaces = comp->nsList;
591 ctxt->xpathCtxt->nsNr = comp->nsNr;
592 ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
593 ctxt->xpathCtxt->nsNr = oldNsNr;
594 ctxt->xpathCtxt->namespaces = oldNsList;
596 xsltGenericError(xsltGenericErrorContext,
597 "exsltFuncResultElem: ret == NULL\n");
600 } else if (inst->children != NULL) {
601 /* If the func:result element does not have a select attribute
602 * and has non-empty content (i.e. the func:result element has
603 * one or more child nodes), then the content of the
604 * func:result element specifies the value.
606 xmlNodePtr oldInsert;
609 container = xsltCreateRVT(ctxt);
610 if (container == NULL) {
611 xsltGenericError(xsltGenericErrorContext,
612 "exsltFuncResultElem: out of memory\n");
616 xsltRegisterTmpRVT(ctxt, container);
617 oldInsert = ctxt->insert;
618 ctxt->insert = (xmlNodePtr) container;
619 xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
620 inst->children, NULL, NULL);
621 ctxt->insert = oldInsert;
623 ret = xmlXPathNewValueTree((xmlNodePtr) container);
625 xsltGenericError(xsltGenericErrorContext,
626 "exsltFuncResultElem: ret == NULL\n");
629 ret->boolval = 0; /* Freeing is not handled there anymore */
632 /* If the func:result element has empty content and does not
633 * have a select attribute, then the returned value is an
636 ret = xmlXPathNewCString("");
644 * Registers the EXSLT - Functions module
647 exsltFuncRegister (void) {
648 xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
649 (xsltExtInitFunction) exsltFuncInit,
650 (xsltExtShutdownFunction) exsltFuncShutdown,
651 (xsltStyleExtInitFunction) exsltFuncStyleInit,
652 (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
654 xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
655 EXSLT_FUNCTIONS_NAMESPACE,
656 exsltFuncFunctionComp);
657 xsltRegisterExtModuleElement ((const xmlChar *) "result",
658 EXSLT_FUNCTIONS_NAMESPACE,
659 (xsltPreComputeFunction)exsltFuncResultComp,
660 (xsltTransformFunction) exsltFuncResultElem);