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