1 | #define IN_LIBEXSLT
|
---|
2 | #include "libexslt/libexslt.h"
|
---|
3 |
|
---|
4 | #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
|
---|
5 | #include <win32config.h>
|
---|
6 | #elif defined(VBOX)
|
---|
7 | #include "vboxconfig.h"
|
---|
8 | #else
|
---|
9 | #include "config.h"
|
---|
10 | #endif
|
---|
11 |
|
---|
12 | #include <string.h>
|
---|
13 |
|
---|
14 | #include <libxml/tree.h>
|
---|
15 | #include <libxml/xpath.h>
|
---|
16 | #include <libxml/xpathInternals.h>
|
---|
17 | #include <libxml/hash.h>
|
---|
18 | #include <libxml/debugXML.h>
|
---|
19 |
|
---|
20 | #include <libxslt/xsltutils.h>
|
---|
21 | #include <libxslt/variables.h>
|
---|
22 | #include <libxslt/xsltInternals.h>
|
---|
23 | #include <libxslt/extensions.h>
|
---|
24 | #include <libxslt/transform.h>
|
---|
25 | #include <libxslt/imports.h>
|
---|
26 |
|
---|
27 | #include "exslt.h"
|
---|
28 |
|
---|
29 | typedef struct _exsltFuncFunctionData exsltFuncFunctionData;
|
---|
30 | struct _exsltFuncFunctionData {
|
---|
31 | int nargs; /* number of arguments to the function */
|
---|
32 | xmlNodePtr content; /* the func:fuction template content */
|
---|
33 | };
|
---|
34 |
|
---|
35 | typedef struct _exsltFuncData exsltFuncData;
|
---|
36 | struct _exsltFuncData {
|
---|
37 | xmlHashTablePtr funcs; /* pointer to the stylesheet module data */
|
---|
38 | xmlXPathObjectPtr result; /* returned by func:result */
|
---|
39 | int error; /* did an error occur? */
|
---|
40 | xmlDocPtr RVT; /* result tree fragment */
|
---|
41 | };
|
---|
42 |
|
---|
43 | typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
|
---|
44 | struct _exsltFuncResultPreComp {
|
---|
45 | xsltElemPreComp comp;
|
---|
46 | xmlXPathCompExprPtr select;
|
---|
47 | xmlNsPtr *nsList;
|
---|
48 | int nsNr;
|
---|
49 | };
|
---|
50 |
|
---|
51 | /* Used for callback function in exsltInitFunc */
|
---|
52 | typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
|
---|
53 | struct _exsltFuncImportRegData {
|
---|
54 | xsltTransformContextPtr ctxt;
|
---|
55 | xmlHashTablePtr hash;
|
---|
56 | };
|
---|
57 |
|
---|
58 | static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
|
---|
59 | int nargs);
|
---|
60 | static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
|
---|
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 | /*
|
---|
327 | * We have a problem with the evaluation of function parameters.
|
---|
328 | * The original library code did not evaluate XPath expressions until
|
---|
329 | * the last moment. After version 1.1.17 of the libxslt, the logic
|
---|
330 | * of other parts of the library was changed, and the evaluation of
|
---|
331 | * XPath expressions within parameters now takes place as soon as the
|
---|
332 | * parameter is parsed/evaluated (xsltParseStylesheetCallerParam).
|
---|
333 | * This means that the parameters need to be evaluated in lexical
|
---|
334 | * order (since a variable is "in scope" as soon as it is declared).
|
---|
335 | * However, on entry to this routine, the values (from the caller) are
|
---|
336 | * in reverse order (held on the XPath context variable stack). To
|
---|
337 | * accomplish what is required, I have added code to pop the XPath
|
---|
338 | * objects off of the stack at the beginning and save them, then use
|
---|
339 | * them (in the reverse order) as the params are evaluated. This
|
---|
340 | * requires an xmlMalloc/xmlFree for each param set by the caller,
|
---|
341 | * which is not very nice. There is probably a much better solution
|
---|
342 | * (like change other code to delay the evaluation).
|
---|
343 | */
|
---|
344 | /*
|
---|
345 | * In order to give the function params and variables a new 'scope'
|
---|
346 | * we change varsBase in the context.
|
---|
347 | */
|
---|
348 | oldBase = tctxt->varsBase;
|
---|
349 | tctxt->varsBase = tctxt->varsNr;
|
---|
350 | /* If there are any parameters */
|
---|
351 | if (paramNode != NULL) {
|
---|
352 | /* Fetch the stored argument values from the caller */
|
---|
353 | for (i = 0; i < nargs; i++) {
|
---|
354 | savedObj = xmlMalloc(sizeof(struct objChain));
|
---|
355 | savedObj->next = savedObjChain;
|
---|
356 | savedObj->obj = valuePop(ctxt);
|
---|
357 | savedObjChain = savedObj;
|
---|
358 | }
|
---|
359 |
|
---|
360 | /*
|
---|
361 | * Prepare to process params in reverse order. First, go to
|
---|
362 | * the beginning of the param chain.
|
---|
363 | */
|
---|
364 | for (i = 1; i <= func->nargs; i++) {
|
---|
365 | if (paramNode->prev == NULL)
|
---|
366 | break;
|
---|
367 | paramNode = paramNode->prev;
|
---|
368 | }
|
---|
369 | /*
|
---|
370 | * i has total # params found, nargs is number which are present
|
---|
371 | * as arguments from the caller
|
---|
372 | * Calculate the number of un-set parameters
|
---|
373 | */
|
---|
374 | notSet = func->nargs - nargs;
|
---|
375 | for (; i > 0; i--) {
|
---|
376 | param = xsltParseStylesheetCallerParam (tctxt, paramNode);
|
---|
377 | if (i > notSet) { /* if parameter value set */
|
---|
378 | param->computed = 1;
|
---|
379 | if (param->value != NULL)
|
---|
380 | xmlXPathFreeObject(param->value);
|
---|
381 | savedObj = savedObjChain; /* get next val from chain */
|
---|
382 | param->value = savedObj->obj;
|
---|
383 | savedObjChain = savedObjChain->next;
|
---|
384 | xmlFree(savedObj);
|
---|
385 | }
|
---|
386 | xsltLocalVariablePush(tctxt, param, -1);
|
---|
387 | param->next = params;
|
---|
388 | params = param;
|
---|
389 | paramNode = paramNode->next;
|
---|
390 | }
|
---|
391 | }
|
---|
392 | /*
|
---|
393 | * actual processing
|
---|
394 | */
|
---|
395 | fake = xmlNewDocNode(tctxt->output, NULL,
|
---|
396 | (const xmlChar *)"fake", NULL);
|
---|
397 | oldInsert = tctxt->insert;
|
---|
398 | tctxt->insert = fake;
|
---|
399 | xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
|
---|
400 | func->content, NULL, NULL);
|
---|
401 | xsltLocalVariablePop(tctxt, tctxt->varsBase, -2);
|
---|
402 | tctxt->insert = oldInsert;
|
---|
403 | tctxt->varsBase = oldBase; /* restore original scope */
|
---|
404 | if (params != NULL)
|
---|
405 | xsltFreeStackElemList(params);
|
---|
406 |
|
---|
407 | if (data->error != 0)
|
---|
408 | goto error;
|
---|
409 |
|
---|
410 | if (data->result != NULL) {
|
---|
411 | ret = data->result;
|
---|
412 | } else
|
---|
413 | ret = xmlXPathNewCString("");
|
---|
414 |
|
---|
415 | data->result = oldResult;
|
---|
416 |
|
---|
417 | /*
|
---|
418 | * It is an error if the instantiation of the template results in
|
---|
419 | * the generation of result nodes.
|
---|
420 | */
|
---|
421 | if (fake->children != NULL) {
|
---|
422 | #ifdef LIBXML_DEBUG_ENABLED
|
---|
423 | xmlDebugDumpNode (stderr, fake, 1);
|
---|
424 | #endif
|
---|
425 | xsltGenericError(xsltGenericErrorContext,
|
---|
426 | "{%s}%s: cannot write to result tree while "
|
---|
427 | "executing a function\n",
|
---|
428 | ctxt->context->functionURI, ctxt->context->function);
|
---|
429 | xmlFreeNode(fake);
|
---|
430 | goto error;
|
---|
431 | }
|
---|
432 | xmlFreeNode(fake);
|
---|
433 | valuePush(ctxt, ret);
|
---|
434 |
|
---|
435 | error:
|
---|
436 | /*
|
---|
437 | * IMPORTANT: This enables previously tree fragments marked as
|
---|
438 | * being results of a function, to be garbage-collected after
|
---|
439 | * the calling process exits.
|
---|
440 | */
|
---|
441 | xsltExtensionInstructionResultFinalize(tctxt);
|
---|
442 | }
|
---|
443 |
|
---|
444 |
|
---|
445 | static void
|
---|
446 | exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
|
---|
447 | xmlChar *name, *prefix;
|
---|
448 | xmlNsPtr ns;
|
---|
449 | xmlHashTablePtr data;
|
---|
450 | exsltFuncFunctionData *func;
|
---|
451 |
|
---|
452 | if ((style == NULL) || (inst == NULL))
|
---|
453 | return;
|
---|
454 |
|
---|
455 |
|
---|
456 | {
|
---|
457 | xmlChar *qname;
|
---|
458 |
|
---|
459 | qname = xmlGetProp(inst, (const xmlChar *) "name");
|
---|
460 | name = xmlSplitQName2 (qname, &prefix);
|
---|
461 | xmlFree(qname);
|
---|
462 | }
|
---|
463 | if ((name == NULL) || (prefix == NULL)) {
|
---|
464 | xsltGenericError(xsltGenericErrorContext,
|
---|
465 | "func:function: not a QName\n");
|
---|
466 | if (name != NULL)
|
---|
467 | xmlFree(name);
|
---|
468 | return;
|
---|
469 | }
|
---|
470 | /* namespace lookup */
|
---|
471 | ns = xmlSearchNs (inst->doc, inst, prefix);
|
---|
472 | if (ns == NULL) {
|
---|
473 | xsltGenericError(xsltGenericErrorContext,
|
---|
474 | "func:function: undeclared prefix %s\n",
|
---|
475 | prefix);
|
---|
476 | xmlFree(name);
|
---|
477 | xmlFree(prefix);
|
---|
478 | return;
|
---|
479 | }
|
---|
480 | xmlFree(prefix);
|
---|
481 |
|
---|
482 | /*
|
---|
483 | * Create function data
|
---|
484 | */
|
---|
485 | func = exsltFuncNewFunctionData();
|
---|
486 | func->content = inst->children;
|
---|
487 | while (IS_XSLT_ELEM(func->content) &&
|
---|
488 | IS_XSLT_NAME(func->content, "param")) {
|
---|
489 | func->content = func->content->next;
|
---|
490 | func->nargs++;
|
---|
491 | }
|
---|
492 |
|
---|
493 | xsltParseTemplateContent(style, inst);
|
---|
494 |
|
---|
495 | /*
|
---|
496 | * Register the function data such that it can be retrieved
|
---|
497 | * by exslFuncFunctionFunction
|
---|
498 | */
|
---|
499 | #ifdef XSLT_REFACTORED
|
---|
500 | /*
|
---|
501 | * Ensure that the hash table will be stored in the *current*
|
---|
502 | * stylesheet level in order to correctly evaluate the
|
---|
503 | * import precedence.
|
---|
504 | */
|
---|
505 | data = (xmlHashTablePtr)
|
---|
506 | xsltStyleStylesheetLevelGetExtData(style,
|
---|
507 | EXSLT_FUNCTIONS_NAMESPACE);
|
---|
508 | #else
|
---|
509 | data = (xmlHashTablePtr)
|
---|
510 | xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE);
|
---|
511 | #endif
|
---|
512 | if (data == NULL) {
|
---|
513 | xsltGenericError(xsltGenericErrorContext,
|
---|
514 | "exsltFuncFunctionComp: no stylesheet data\n");
|
---|
515 | xmlFree(name);
|
---|
516 | return;
|
---|
517 | }
|
---|
518 |
|
---|
519 | if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
|
---|
520 | xsltTransformError(NULL, style, inst,
|
---|
521 | "Failed to register function {%s}%s\n",
|
---|
522 | ns->href, name);
|
---|
523 | style->errors++;
|
---|
524 | } else {
|
---|
525 | xsltGenericDebug(xsltGenericDebugContext,
|
---|
526 | "exsltFuncFunctionComp: register {%s}%s\n",
|
---|
527 | ns->href, name);
|
---|
528 | }
|
---|
529 | xmlFree(name);
|
---|
530 | }
|
---|
531 |
|
---|
532 | static xsltElemPreCompPtr
|
---|
533 | exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
|
---|
534 | xsltTransformFunction function) {
|
---|
535 | xmlNodePtr test;
|
---|
536 | xmlChar *sel;
|
---|
537 | exsltFuncResultPreComp *ret;
|
---|
538 |
|
---|
539 | /*
|
---|
540 | * "Validity" checking
|
---|
541 | */
|
---|
542 | /* it is an error to have any following sibling elements aside
|
---|
543 | * from the xsl:fallback element.
|
---|
544 | */
|
---|
545 | for (test = inst->next; test != NULL; test = test->next) {
|
---|
546 | if (test->type != XML_ELEMENT_NODE)
|
---|
547 | continue;
|
---|
548 | if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
|
---|
549 | continue;
|
---|
550 | xsltGenericError(xsltGenericErrorContext,
|
---|
551 | "exsltFuncResultElem: only xsl:fallback is "
|
---|
552 | "allowed to follow func:result\n");
|
---|
553 | return (NULL);
|
---|
554 | }
|
---|
555 | /* it is an error for a func:result element to not be a descendant
|
---|
556 | * of func:function.
|
---|
557 | * it is an error if a func:result occurs within a func:result
|
---|
558 | * element.
|
---|
559 | * it is an error if instanciating the content of a variable
|
---|
560 | * binding element (i.e. xsl:variable, xsl:param) results in the
|
---|
561 | * instanciation of a func:result element.
|
---|
562 | */
|
---|
563 | for (test = inst->parent; test != NULL; test = test->parent) {
|
---|
564 | if ((test->ns != NULL) &&
|
---|
565 | (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
|
---|
566 | if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
|
---|
567 | break;
|
---|
568 | }
|
---|
569 | if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
|
---|
570 | xsltGenericError(xsltGenericErrorContext,
|
---|
571 | "func:result element not allowed within"
|
---|
572 | " another func:result element\n");
|
---|
573 | return (NULL);
|
---|
574 | }
|
---|
575 | }
|
---|
576 | if (IS_XSLT_ELEM(test) &&
|
---|
577 | (IS_XSLT_NAME(test, "variable") ||
|
---|
578 | IS_XSLT_NAME(test, "param"))) {
|
---|
579 | xsltGenericError(xsltGenericErrorContext,
|
---|
580 | "func:result element not allowed within"
|
---|
581 | " a variable binding element\n");
|
---|
582 | return (NULL);
|
---|
583 | }
|
---|
584 | }
|
---|
585 |
|
---|
586 | /*
|
---|
587 | * Precomputation
|
---|
588 | */
|
---|
589 | ret = (exsltFuncResultPreComp *)
|
---|
590 | xmlMalloc (sizeof(exsltFuncResultPreComp));
|
---|
591 | if (ret == NULL) {
|
---|
592 | xsltPrintErrorContext(NULL, NULL, NULL);
|
---|
593 | xsltGenericError(xsltGenericErrorContext,
|
---|
594 | "exsltFuncResultComp : malloc failed\n");
|
---|
595 | return (NULL);
|
---|
596 | }
|
---|
597 | memset(ret, 0, sizeof(exsltFuncResultPreComp));
|
---|
598 |
|
---|
599 | xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
|
---|
600 | (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
|
---|
601 | ret->select = NULL;
|
---|
602 |
|
---|
603 | /*
|
---|
604 | * Precompute the select attribute
|
---|
605 | */
|
---|
606 | sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
|
---|
607 | if (sel != NULL) {
|
---|
608 | ret->select = xmlXPathCompile (sel);
|
---|
609 | xmlFree(sel);
|
---|
610 | }
|
---|
611 | /*
|
---|
612 | * Precompute the namespace list
|
---|
613 | */
|
---|
614 | ret->nsList = xmlGetNsList(inst->doc, inst);
|
---|
615 | if (ret->nsList != NULL) {
|
---|
616 | int i = 0;
|
---|
617 | while (ret->nsList[i] != NULL)
|
---|
618 | i++;
|
---|
619 | ret->nsNr = i;
|
---|
620 | }
|
---|
621 | return ((xsltElemPreCompPtr) ret);
|
---|
622 | }
|
---|
623 |
|
---|
624 | static void
|
---|
625 | exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
---|
626 | xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
|
---|
627 | exsltFuncResultPreComp *comp) {
|
---|
628 | exsltFuncData *data;
|
---|
629 | xmlXPathObjectPtr ret;
|
---|
630 |
|
---|
631 |
|
---|
632 | /* It is an error if instantiating the content of the
|
---|
633 | * func:function element results in the instantiation of more than
|
---|
634 | * one func:result elements.
|
---|
635 | */
|
---|
636 | data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
|
---|
637 | if (data == NULL) {
|
---|
638 | xsltGenericError(xsltGenericErrorContext,
|
---|
639 | "exsltFuncReturnElem: data == NULL\n");
|
---|
640 | return;
|
---|
641 | }
|
---|
642 | if (data->result != NULL) {
|
---|
643 | xsltGenericError(xsltGenericErrorContext,
|
---|
644 | "func:result already instanciated\n");
|
---|
645 | data->error = 1;
|
---|
646 | return;
|
---|
647 | }
|
---|
648 | /*
|
---|
649 | * Processing
|
---|
650 | */
|
---|
651 | if (comp->select != NULL) {
|
---|
652 | xmlNsPtr *oldXPNsList;
|
---|
653 | int oldXPNsNr;
|
---|
654 | xmlNodePtr oldXPContextNode;
|
---|
655 | /* If the func:result element has a select attribute, then the
|
---|
656 | * value of the attribute must be an expression and the
|
---|
657 | * returned value is the object that results from evaluating
|
---|
658 | * the expression. In this case, the content must be empty.
|
---|
659 | */
|
---|
660 | if (inst->children != NULL) {
|
---|
661 | xsltGenericError(xsltGenericErrorContext,
|
---|
662 | "func:result content must be empty if it"
|
---|
663 | " has a select attribute\n");
|
---|
664 | data->error = 1;
|
---|
665 | return;
|
---|
666 | }
|
---|
667 | oldXPNsList = ctxt->xpathCtxt->namespaces;
|
---|
668 | oldXPNsNr = ctxt->xpathCtxt->nsNr;
|
---|
669 | oldXPContextNode = ctxt->xpathCtxt->node;
|
---|
670 |
|
---|
671 | ctxt->xpathCtxt->namespaces = comp->nsList;
|
---|
672 | ctxt->xpathCtxt->nsNr = comp->nsNr;
|
---|
673 |
|
---|
674 | ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
|
---|
675 |
|
---|
676 | ctxt->xpathCtxt->node = oldXPContextNode;
|
---|
677 | ctxt->xpathCtxt->nsNr = oldXPNsNr;
|
---|
678 | ctxt->xpathCtxt->namespaces = oldXPNsList;
|
---|
679 |
|
---|
680 | if (ret == NULL) {
|
---|
681 | xsltGenericError(xsltGenericErrorContext,
|
---|
682 | "exsltFuncResultElem: ret == NULL\n");
|
---|
683 | return;
|
---|
684 | }
|
---|
685 | /*
|
---|
686 | * Mark it as a function result in order to avoid garbage
|
---|
687 | * collecting of tree fragments before the function exits.
|
---|
688 | */
|
---|
689 | xsltExtensionInstructionResultRegister(ctxt, ret);
|
---|
690 | } else if (inst->children != NULL) {
|
---|
691 | /* If the func:result element does not have a select attribute
|
---|
692 | * and has non-empty content (i.e. the func:result element has
|
---|
693 | * one or more child nodes), then the content of the
|
---|
694 | * func:result element specifies the value.
|
---|
695 | */
|
---|
696 | xmlNodePtr oldInsert;
|
---|
697 | xmlDocPtr container;
|
---|
698 |
|
---|
699 | container = xsltCreateRVT(ctxt);
|
---|
700 | if (container == NULL) {
|
---|
701 | xsltGenericError(xsltGenericErrorContext,
|
---|
702 | "exsltFuncResultElem: out of memory\n");
|
---|
703 | data->error = 1;
|
---|
704 | return;
|
---|
705 | }
|
---|
706 | xsltRegisterLocalRVT(ctxt, container);
|
---|
707 |
|
---|
708 | oldInsert = ctxt->insert;
|
---|
709 | ctxt->insert = (xmlNodePtr) container;
|
---|
710 | xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
|
---|
711 | inst->children, NULL, NULL);
|
---|
712 | ctxt->insert = oldInsert;
|
---|
713 |
|
---|
714 | ret = xmlXPathNewValueTree((xmlNodePtr) container);
|
---|
715 | if (ret == NULL) {
|
---|
716 | xsltGenericError(xsltGenericErrorContext,
|
---|
717 | "exsltFuncResultElem: ret == NULL\n");
|
---|
718 | data->error = 1;
|
---|
719 | } else {
|
---|
720 | ret->boolval = 0; /* Freeing is not handled there anymore */
|
---|
721 | /*
|
---|
722 | * Mark it as a function result in order to avoid garbage
|
---|
723 | * collecting of tree fragments before the function exits.
|
---|
724 | */
|
---|
725 | xsltExtensionInstructionResultRegister(ctxt, ret);
|
---|
726 | }
|
---|
727 | } else {
|
---|
728 | /* If the func:result element has empty content and does not
|
---|
729 | * have a select attribute, then the returned value is an
|
---|
730 | * empty string.
|
---|
731 | */
|
---|
732 | ret = xmlXPathNewCString("");
|
---|
733 | }
|
---|
734 | data->result = ret;
|
---|
735 | }
|
---|
736 |
|
---|
737 | /**
|
---|
738 | * exsltFuncRegister:
|
---|
739 | *
|
---|
740 | * Registers the EXSLT - Functions module
|
---|
741 | */
|
---|
742 | void
|
---|
743 | exsltFuncRegister (void) {
|
---|
744 | xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
|
---|
745 | (xsltExtInitFunction) exsltFuncInit,
|
---|
746 | (xsltExtShutdownFunction) exsltFuncShutdown,
|
---|
747 | (xsltStyleExtInitFunction) exsltFuncStyleInit,
|
---|
748 | (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
|
---|
749 |
|
---|
750 | xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
|
---|
751 | EXSLT_FUNCTIONS_NAMESPACE,
|
---|
752 | exsltFuncFunctionComp);
|
---|
753 | xsltRegisterExtModuleElement ((const xmlChar *) "result",
|
---|
754 | EXSLT_FUNCTIONS_NAMESPACE,
|
---|
755 | (xsltPreComputeFunction)exsltFuncResultComp,
|
---|
756 | (xsltTransformFunction) exsltFuncResultElem);
|
---|
757 | }
|
---|