1 #include "libexslt/libexslt.h"
3 #if defined(WIN32) && !defined (__CYGWIN__)
4 #include <win32config.h>
11 #include <libxml/tree.h>
12 #include <libxml/xpath.h>
13 #include <libxml/xpathInternals.h>
14 #include <libxml/hash.h>
15 #include <libxml/debugXML.h>
17 #include <libxslt/xsltutils.h>
18 #include <libxslt/variables.h>
19 #include <libxslt/xsltInternals.h>
20 #include <libxslt/extensions.h>
21 #include <libxslt/transform.h>
25 typedef struct _exsltFuncFunctionData exsltFuncFunctionData;
26 struct _exsltFuncFunctionData {
27 int nargs; /* number of arguments to the function */
28 xmlNodePtr content; /* the func:fuction template content */
31 typedef struct _exsltFuncData exsltFuncData;
32 struct _exsltFuncData {
33 xmlHashTablePtr funcs; /* pointer to the stylesheet module data */
34 xmlXPathObjectPtr result; /* returned by func:result */
35 int error; /* did an error occur? */
38 typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
39 struct _exsltFuncResultPreComp {
41 xmlXPathCompExprPtr select;
44 static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
48 * exsltFuncRegisterFunc:
49 * @func: the #exsltFuncFunctionData for the function
50 * @ctxt: an XSLT transformation context
51 * @URI: the function namespace URI
52 * @name: the function name
54 * Registers a function declared by a func:function element
57 exsltFuncRegisterFunc (exsltFuncFunctionData *data,
58 xsltTransformContextPtr ctxt,
59 const xmlChar *URI, const xmlChar *name) {
60 if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
63 xsltGenericDebug(xsltGenericDebugContext,
64 "exsltFuncRegisterFunc: register {%s}%s\n",
66 xsltRegisterExtFunction(ctxt, name, URI,
67 exsltFuncFunctionFunction);
72 * @ctxt: an XSLT transformation context
73 * @URI: the namespace URI for the extension
75 * Initializes the EXSLT - Functions module.
77 * Returns the data for this transformation
79 static exsltFuncData *
80 exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
84 ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
86 xsltGenericError(xsltGenericErrorContext,
87 "exsltFuncInit: not enough memory\n");
90 memset(ret, 0, sizeof(exsltFuncData));
95 hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
96 xmlHashScanFull(hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
105 * @ctxt: an XSLT transformation context
106 * @URI: the namespace URI for the extension
107 * @data: the module data to free up
109 * Shutdown the EXSLT - Functions module
112 exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
113 const xmlChar *URI ATTRIBUTE_UNUSED,
114 exsltFuncData *data) {
115 if (data->result != NULL)
116 xmlXPathFreeObject(data->result);
121 * exsltFuncStyleInit:
122 * @style: an XSLT stylesheet
123 * @URI: the namespace URI for the extension
125 * Allocates the styleshet data for EXSLT - Function
127 * Returns the allocated data
129 static xmlHashTablePtr
130 exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
131 const xmlChar *URI ATTRIBUTE_UNUSED) {
132 return xmlHashCreate(1);
136 * exsltFuncStyleShutdown:
137 * @style: an XSLT stylesheet
138 * @URI: the namespace URI for the extension
139 * @data: the stylesheet data to free up
141 * Shutdown the EXSLT - Function module
144 exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
145 const xmlChar *URI ATTRIBUTE_UNUSED,
146 xmlHashTablePtr data) {
147 xmlHashFree(data, (xmlHashDeallocator) xmlFree);
151 * exsltFuncNewFunctionData:
153 * Allocates an #exslFuncFunctionData object
155 * Returns the new structure
157 static exsltFuncFunctionData *
158 exsltFuncNewFunctionData (void) {
159 exsltFuncFunctionData *ret;
161 ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
163 xsltGenericError(xsltGenericErrorContext,
164 "exsltFuncNewFunctionData: not enough memory\n");
167 memset(ret, 0, sizeof(exsltFuncFunctionData));
176 * exsltFreeFuncResultPreComp:
177 * @comp: the #exsltFuncResultPreComp to free up
179 * Deallocates an #exsltFuncResultPreComp
182 exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
186 if (comp->select != NULL)
187 xmlXPathFreeCompExpr (comp->select);
192 * exsltFuncFunctionFunction:
193 * @ctxt: an XPath parser context
194 * @nargs: the number of arguments
196 * Evaluates the func:function element that defines the called function.
199 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
200 xmlXPathObjectPtr obj, oldResult, ret;
202 exsltFuncFunctionData *func;
203 xmlNodePtr paramNode, oldInsert, fake;
204 xsltStackElemPtr params = NULL, param;
205 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
209 * retrieve func:function template
211 data = (exsltFuncData *) xsltGetExtData (tctxt,
212 EXSLT_FUNCTIONS_NAMESPACE);
213 oldResult = data->result;
216 func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
217 ctxt->context->functionURI,
218 ctxt->context->function);
223 if (nargs > func->nargs) {
224 xsltGenericError(xsltGenericErrorContext,
225 "{%s}%s: called with too many arguments\n",
226 ctxt->context->functionURI, ctxt->context->function);
227 ctxt->error = XPATH_INVALID_ARITY;
230 if (func->content != NULL)
231 paramNode = func->content->prev;
234 if ((paramNode == NULL) && (func->nargs != 0)) {
235 xsltGenericError(xsltGenericErrorContext,
236 "exsltFuncFunctionFunction: nargs != 0 and "
240 /* defaulted params */
241 for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {
242 param = xsltParseStylesheetCallerParam (tctxt, paramNode);
243 param->next = params;
245 paramNode = paramNode->prev;
248 while ((i-- > 0) && (paramNode != NULL)) {
249 obj = valuePop(ctxt);
250 /* FIXME: this is a bit hackish */
251 param = xsltParseStylesheetCallerParam (tctxt, paramNode);
253 if (param->value != NULL)
254 xmlXPathFreeObject(param->value);
256 param->next = params;
258 paramNode = paramNode->prev;
264 fake = xmlNewDocNode(tctxt->output, NULL,
265 (const xmlChar *)"fake", NULL);
266 oldInsert = tctxt->insert;
267 tctxt->insert = fake;
268 xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
269 func->content, NULL, params);
270 tctxt->insert = oldInsert;
272 xsltFreeStackElemList(params);
274 if (data->error != 0)
277 if (data->result != NULL)
280 ret = xmlXPathNewCString("");
282 data->result = oldResult;
285 * It is an error if the instantiation of the template results in
286 * the generation of result nodes.
288 if (fake->children != NULL) {
289 #ifdef LIBXML_DEBUG_ENABLED
290 xmlDebugDumpNode (stderr, fake, 1);
292 xsltGenericError(xsltGenericErrorContext,
293 "{%s}%s: cannot write to result tree while "
294 "executing a function\n",
295 ctxt->context->functionURI, ctxt->context->function);
300 valuePush(ctxt, ret);
305 exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
306 xmlChar *name, *prefix;
308 xmlHashTablePtr data;
309 exsltFuncFunctionData *func;
311 if ((style == NULL) || (inst == NULL))
318 qname = xmlGetProp(inst, (const xmlChar *) "name");
319 name = xmlSplitQName2 (qname, &prefix);
322 if ((name == NULL) || (prefix == NULL)) {
323 xsltGenericError(xsltGenericErrorContext,
324 "func:function: not a QName\n");
329 /* namespace lookup */
330 ns = xmlSearchNs (inst->doc, inst, prefix);
332 xsltGenericError(xsltGenericErrorContext,
333 "func:function: undeclared prefix %s\n",
342 * Create function data
344 func = exsltFuncNewFunctionData();
345 func->content = inst->children;
346 while (IS_XSLT_ELEM(func->content) &&
347 IS_XSLT_NAME(func->content, "param")) {
348 func->content = func->content->next;
352 xsltParseTemplateContent(style, inst);
355 * Register the function data such that it can be retrieved
356 * by exslFuncFunctionFunction
358 data = (xmlHashTablePtr) xsltStyleGetExtData (style,
359 EXSLT_FUNCTIONS_NAMESPACE);
361 xsltGenericError(xsltGenericErrorContext,
362 "exsltFuncFunctionComp: no stylesheet data\n");
367 if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
368 xsltGenericError(xsltGenericErrorContext,
369 "Failed to register function {%s}%s\n",
372 xsltGenericDebug(xsltGenericDebugContext,
373 "exsltFuncFunctionComp: register {%s}%s\n",
379 static xsltElemPreCompPtr
380 exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
381 xsltTransformFunction function) {
384 exsltFuncResultPreComp *ret;
387 * "Validity" checking
389 /* it is an error to have any following sibling elements aside
390 * from the xsl:fallback element.
392 for (test = inst->next; test != NULL; test = test->next) {
393 if (test->type != XML_ELEMENT_NODE)
395 if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
397 xsltGenericError(xsltGenericErrorContext,
398 "exsltFuncResultElem: only xsl:fallback is "
399 "allowed to follow func:result\n");
402 /* it is an error for a func:result element to not be a descendant
404 * it is an error if a func:result occurs within a func:result
406 * it is an error if instanciating the content of a variable
407 * binding element (i.e. xsl:variable, xsl:param) results in the
408 * instanciation of a func:result element.
410 for (test = inst->parent; test != NULL; test = test->parent) {
411 if ((test->ns != NULL) &&
412 (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
413 if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
416 if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
417 xsltGenericError(xsltGenericErrorContext,
418 "func:result element not allowed within"
419 " another func:result element\n");
423 if (IS_XSLT_ELEM(test) &&
424 (IS_XSLT_NAME(test, "variable") ||
425 IS_XSLT_NAME(test, "param"))) {
426 xsltGenericError(xsltGenericErrorContext,
427 "func:result element not allowed within"
428 " a variable binding element\n");
436 ret = (exsltFuncResultPreComp *)
437 xmlMalloc (sizeof(exsltFuncResultPreComp));
439 xsltPrintErrorContext(NULL, NULL, NULL);
440 xsltGenericError(xsltGenericErrorContext,
441 "exsltFuncResultComp : malloc failed\n");
444 memset(ret, 0, sizeof(exsltFuncResultPreComp));
446 xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
447 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
451 * Precompute the select attribute
453 select = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
454 if (select != NULL) {
455 ret->select = xmlXPathCompile (select);
459 return ((xsltElemPreCompPtr) ret);
463 exsltFuncResultElem (xsltTransformContextPtr ctxt,
464 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
465 exsltFuncResultPreComp *comp) {
467 xmlXPathObjectPtr ret;
469 /* It is an error if instantiating the content of the
470 * func:function element results in the instantiation of more than
471 * one func:result elements.
473 data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
475 xsltGenericError(xsltGenericErrorContext,
476 "exsltFuncReturnElem: data == NULL\n");
479 if (data->result != NULL) {
480 xsltGenericError(xsltGenericErrorContext,
481 "func:result already instanciated\n");
488 if (comp->select != NULL) {
489 /* If the func:result element has a select attribute, then the
490 * value of the attribute must be an expression and the
491 * returned value is the object that results from evaluating
492 * the expression. In this case, the content must be empty.
494 if (inst->children != NULL) {
495 xsltGenericError(xsltGenericErrorContext,
496 "func:result content must be empty if it"
497 " has a select attribute\n");
501 ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
503 xsltGenericError(xsltGenericErrorContext,
504 "exsltFuncResultElem: ret == NULL\n");
507 } else if (inst->children != NULL) {
508 /* If the func:result element does not have a select attribute
509 * and has non-empty content (i.e. the func:result element has
510 * one or more child nodes), then the content of the
511 * func:result element specifies the value.
513 xmlNodePtr container, oldInsert;
515 container = xmlNewDocNode (ctxt->output, NULL,
516 (const xmlChar *) "fake", NULL);
517 oldInsert = ctxt->insert;
518 ctxt->insert = container;
519 xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
520 inst->children, NULL, NULL);
521 ctxt->insert = oldInsert;
523 ret = xmlXPathNewValueTree(container);
525 xsltGenericError(xsltGenericErrorContext,
526 "exsltFuncResultElem: ret == NULL\n");
530 /* If the func:result element has empty content and does not
531 * have a select attribute, then the returned value is an
534 ret = xmlXPathNewCString("");
542 * Registers the EXSLT - Functions module
545 exsltFuncRegister (void) {
546 xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
547 (xsltExtInitFunction) exsltFuncInit,
548 (xsltExtShutdownFunction) exsltFuncShutdown,
549 (xsltStyleExtInitFunction) exsltFuncStyleInit,
550 (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
552 xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
553 EXSLT_FUNCTIONS_NAMESPACE,
554 exsltFuncFunctionComp);
555 xsltRegisterExtModuleElement ((const xmlChar *) "result",
556 EXSLT_FUNCTIONS_NAMESPACE,
557 (xsltPreComputeFunction)exsltFuncResultComp,
558 (xsltTransformFunction) exsltFuncResultElem);