1 | /* |
---|
2 | * variables.c: Implementation of the variable storage and lookup |
---|
3 | * |
---|
4 | * Reference: |
---|
5 | * http://www.w3.org/TR/1999/REC-xslt-19991116 |
---|
6 | * |
---|
7 | * See Copyright for the status of this software. |
---|
8 | * |
---|
9 | * daniel@veillard.com |
---|
10 | */ |
---|
11 | |
---|
12 | #define IN_LIBXSLT |
---|
13 | #include "libxslt.h" |
---|
14 | |
---|
15 | #include <string.h> |
---|
16 | |
---|
17 | #include <libxml/xmlmemory.h> |
---|
18 | #include <libxml/tree.h> |
---|
19 | #include <libxml/valid.h> |
---|
20 | #include <libxml/hash.h> |
---|
21 | #include <libxml/xmlerror.h> |
---|
22 | #include <libxml/xpath.h> |
---|
23 | #include <libxml/xpathInternals.h> |
---|
24 | #include <libxml/parserInternals.h> |
---|
25 | #include "xslt.h" |
---|
26 | #include "xsltInternals.h" |
---|
27 | #include "xsltutils.h" |
---|
28 | #include "variables.h" |
---|
29 | #include "transform.h" |
---|
30 | #include "imports.h" |
---|
31 | #include "preproc.h" |
---|
32 | |
---|
33 | #ifdef WITH_XSLT_DEBUG |
---|
34 | #define WITH_XSLT_DEBUG_VARIABLE |
---|
35 | #endif |
---|
36 | |
---|
37 | /************************************************************************ |
---|
38 | * * |
---|
39 | * Module interfaces * |
---|
40 | * * |
---|
41 | ************************************************************************/ |
---|
42 | |
---|
43 | /** |
---|
44 | * xsltNewStackElem: |
---|
45 | * |
---|
46 | * Create a new XSLT ParserContext |
---|
47 | * |
---|
48 | * Returns the newly allocated xsltParserStackElem or NULL in case of error |
---|
49 | */ |
---|
50 | static xsltStackElemPtr |
---|
51 | xsltNewStackElem(void) { |
---|
52 | xsltStackElemPtr cur; |
---|
53 | |
---|
54 | cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); |
---|
55 | if (cur == NULL) { |
---|
56 | xsltTransformError(NULL, NULL, NULL, |
---|
57 | "xsltNewStackElem : malloc failed\n"); |
---|
58 | return(NULL); |
---|
59 | } |
---|
60 | cur->computed = 0; |
---|
61 | cur->name = NULL; |
---|
62 | cur->nameURI = NULL; |
---|
63 | cur->select = NULL; |
---|
64 | cur->tree = NULL; |
---|
65 | cur->value = NULL; |
---|
66 | cur->comp = NULL; |
---|
67 | return(cur); |
---|
68 | } |
---|
69 | |
---|
70 | /** |
---|
71 | * xsltCopyStackElem: |
---|
72 | * @elem: an XSLT stack element |
---|
73 | * |
---|
74 | * Makes a copy of the stack element |
---|
75 | * |
---|
76 | * Returns the copy of NULL |
---|
77 | */ |
---|
78 | static xsltStackElemPtr |
---|
79 | xsltCopyStackElem(xsltStackElemPtr elem) { |
---|
80 | xsltStackElemPtr cur; |
---|
81 | |
---|
82 | cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); |
---|
83 | if (cur == NULL) { |
---|
84 | xsltTransformError(NULL, NULL, NULL, |
---|
85 | "xsltCopyStackElem : malloc failed\n"); |
---|
86 | return(NULL); |
---|
87 | } |
---|
88 | cur->name = xmlStrdup(elem->name); |
---|
89 | cur->nameURI = xmlStrdup(elem->nameURI); |
---|
90 | cur->select = xmlStrdup(elem->select); |
---|
91 | cur->tree = elem->tree; |
---|
92 | cur->comp = elem->comp; |
---|
93 | cur->computed = 0; |
---|
94 | cur->value = NULL; |
---|
95 | return(cur); |
---|
96 | } |
---|
97 | |
---|
98 | /** |
---|
99 | * xsltFreeStackElem: |
---|
100 | * @elem: an XSLT stack element |
---|
101 | * |
---|
102 | * Free up the memory allocated by @elem |
---|
103 | */ |
---|
104 | static void |
---|
105 | xsltFreeStackElem(xsltStackElemPtr elem) { |
---|
106 | if (elem == NULL) |
---|
107 | return; |
---|
108 | if (elem->name != NULL) |
---|
109 | xmlFree(elem->name); |
---|
110 | if (elem->nameURI != NULL) |
---|
111 | xmlFree(elem->nameURI); |
---|
112 | if (elem->select != NULL) |
---|
113 | xmlFree(elem->select); |
---|
114 | if (elem->value != NULL) |
---|
115 | xmlXPathFreeObject(elem->value); |
---|
116 | |
---|
117 | xmlFree(elem); |
---|
118 | } |
---|
119 | |
---|
120 | /** |
---|
121 | * xsltFreeStackElemList: |
---|
122 | * @elem: an XSLT stack element |
---|
123 | * |
---|
124 | * Free up the memory allocated by @elem |
---|
125 | */ |
---|
126 | void |
---|
127 | xsltFreeStackElemList(xsltStackElemPtr elem) { |
---|
128 | xsltStackElemPtr next; |
---|
129 | |
---|
130 | while(elem != NULL) { |
---|
131 | next = elem->next; |
---|
132 | xsltFreeStackElem(elem); |
---|
133 | elem = next; |
---|
134 | } |
---|
135 | } |
---|
136 | |
---|
137 | /** |
---|
138 | * xsltCheckStackElem: |
---|
139 | * @ctxt: xn XSLT transformation context |
---|
140 | * @name: the variable name |
---|
141 | * @nameURI: the variable namespace URI |
---|
142 | * |
---|
143 | * check wether the variable or param is already defined |
---|
144 | * |
---|
145 | * Returns 1 if variable is present, 2 if param is present, 3 if this |
---|
146 | * is an inherited param, 0 if not found, -1 in case of failure. |
---|
147 | */ |
---|
148 | static int |
---|
149 | xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name, |
---|
150 | const xmlChar *nameURI) { |
---|
151 | xsltStackElemPtr cur; |
---|
152 | |
---|
153 | if ((ctxt == NULL) || (name == NULL)) |
---|
154 | return(-1); |
---|
155 | |
---|
156 | cur = ctxt->vars; |
---|
157 | while (cur != NULL) { |
---|
158 | if (xmlStrEqual(name, cur->name)) { |
---|
159 | if (((nameURI == NULL) && (cur->nameURI == NULL)) || |
---|
160 | ((nameURI != NULL) && (cur->nameURI != NULL) && |
---|
161 | (xmlStrEqual(nameURI, cur->nameURI)))) { |
---|
162 | if ((cur->comp != NULL) && |
---|
163 | (cur->comp->type == XSLT_FUNC_WITHPARAM)) |
---|
164 | return(3); |
---|
165 | if ((cur->comp != NULL) && |
---|
166 | (cur->comp->type == XSLT_FUNC_PARAM)) |
---|
167 | return(2); |
---|
168 | return(1); |
---|
169 | } |
---|
170 | } |
---|
171 | cur = cur->next; |
---|
172 | } |
---|
173 | return(0); |
---|
174 | } |
---|
175 | |
---|
176 | /** |
---|
177 | * xsltAddStackElem: |
---|
178 | * @ctxt: xn XSLT transformation context |
---|
179 | * @elem: a stack element |
---|
180 | * |
---|
181 | * add a new element at this level of the stack. |
---|
182 | * |
---|
183 | * Returns 0 in case of success, -1 in case of failure. |
---|
184 | */ |
---|
185 | static int |
---|
186 | xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) { |
---|
187 | if ((ctxt == NULL) || (elem == NULL)) |
---|
188 | return(-1); |
---|
189 | |
---|
190 | elem->next = ctxt->varsTab[ctxt->varsNr - 1]; |
---|
191 | ctxt->varsTab[ctxt->varsNr - 1] = elem; |
---|
192 | ctxt->vars = elem; |
---|
193 | return(0); |
---|
194 | } |
---|
195 | |
---|
196 | /** |
---|
197 | * xsltAddStackElemList: |
---|
198 | * @ctxt: xn XSLT transformation context |
---|
199 | * @elems: a stack element list |
---|
200 | * |
---|
201 | * add the new element list at this level of the stack. |
---|
202 | * |
---|
203 | * Returns 0 in case of success, -1 in case of failure. |
---|
204 | */ |
---|
205 | int |
---|
206 | xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) { |
---|
207 | xsltStackElemPtr cur; |
---|
208 | |
---|
209 | if ((ctxt == NULL) || (elems == NULL)) |
---|
210 | return(-1); |
---|
211 | |
---|
212 | /* TODO: check doublons */ |
---|
213 | if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) { |
---|
214 | cur = ctxt->varsTab[ctxt->varsNr - 1]; |
---|
215 | while (cur->next != NULL) |
---|
216 | cur = cur->next; |
---|
217 | cur->next = elems; |
---|
218 | } else { |
---|
219 | elems->next = ctxt->varsTab[ctxt->varsNr - 1]; |
---|
220 | ctxt->varsTab[ctxt->varsNr - 1] = elems; |
---|
221 | ctxt->vars = elems; |
---|
222 | } |
---|
223 | return(0); |
---|
224 | } |
---|
225 | |
---|
226 | /** |
---|
227 | * xsltStackLookup: |
---|
228 | * @ctxt: an XSLT transformation context |
---|
229 | * @name: the local part of the name |
---|
230 | * @nameURI: the URI part of the name |
---|
231 | * |
---|
232 | * Locate an element in the stack based on its name. |
---|
233 | */ |
---|
234 | static xsltStackElemPtr |
---|
235 | xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, |
---|
236 | const xmlChar *nameURI) { |
---|
237 | xsltStackElemPtr ret = NULL; |
---|
238 | int i; |
---|
239 | xsltStackElemPtr cur; |
---|
240 | |
---|
241 | if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0)) |
---|
242 | return(NULL); |
---|
243 | |
---|
244 | /* |
---|
245 | * Do the lookup from the top of the stack, but |
---|
246 | * don't use params being computed in a call-param |
---|
247 | */ |
---|
248 | ; |
---|
249 | |
---|
250 | for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { |
---|
251 | cur = ctxt->varsTab[i-1]; |
---|
252 | while (cur != NULL) { |
---|
253 | if (xmlStrEqual(cur->name, name)) { |
---|
254 | if (nameURI == NULL) { |
---|
255 | if (cur->nameURI == NULL) { |
---|
256 | return(cur); |
---|
257 | } |
---|
258 | } else { |
---|
259 | if ((cur->nameURI != NULL) && |
---|
260 | (xmlStrEqual(cur->nameURI, nameURI))) { |
---|
261 | return(cur); |
---|
262 | } |
---|
263 | } |
---|
264 | |
---|
265 | } |
---|
266 | cur = cur->next; |
---|
267 | } |
---|
268 | } |
---|
269 | return(ret); |
---|
270 | } |
---|
271 | |
---|
272 | /************************************************************************ |
---|
273 | * * |
---|
274 | * Module interfaces * |
---|
275 | * * |
---|
276 | ************************************************************************/ |
---|
277 | |
---|
278 | /** |
---|
279 | * xsltEvalVariable: |
---|
280 | * @ctxt: the XSLT transformation context |
---|
281 | * @elem: the variable or parameter. |
---|
282 | * @precomp: pointer to precompiled data |
---|
283 | * |
---|
284 | * Evaluate a variable value. |
---|
285 | * |
---|
286 | * Returns the XPath Object value or NULL in case of error |
---|
287 | */ |
---|
288 | static xmlXPathObjectPtr |
---|
289 | xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem, |
---|
290 | xsltStylePreCompPtr precomp) { |
---|
291 | xmlXPathObjectPtr result = NULL; |
---|
292 | int oldProximityPosition, oldContextSize; |
---|
293 | xmlNodePtr oldInst, oldNode; |
---|
294 | xsltDocumentPtr oldDoc; |
---|
295 | int oldNsNr; |
---|
296 | xmlNsPtr *oldNamespaces; |
---|
297 | |
---|
298 | if ((ctxt == NULL) || (elem == NULL)) |
---|
299 | return(NULL); |
---|
300 | |
---|
301 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
302 | xsltGenericDebug(xsltGenericDebugContext, |
---|
303 | "Evaluating variable %s\n", elem->name); |
---|
304 | #endif |
---|
305 | if (elem->select != NULL) { |
---|
306 | xmlXPathCompExprPtr comp = NULL; |
---|
307 | |
---|
308 | if ((precomp != NULL) && (precomp->comp != NULL)) { |
---|
309 | comp = precomp->comp; |
---|
310 | } else { |
---|
311 | comp = xmlXPathCompile(elem->select); |
---|
312 | } |
---|
313 | if (comp == NULL) |
---|
314 | return(NULL); |
---|
315 | oldProximityPosition = ctxt->xpathCtxt->proximityPosition; |
---|
316 | oldContextSize = ctxt->xpathCtxt->contextSize; |
---|
317 | ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node; |
---|
318 | oldDoc = ctxt->document; |
---|
319 | oldNode = ctxt->node; |
---|
320 | oldInst = ctxt->inst; |
---|
321 | oldNsNr = ctxt->xpathCtxt->nsNr; |
---|
322 | oldNamespaces = ctxt->xpathCtxt->namespaces; |
---|
323 | if (precomp != NULL) { |
---|
324 | ctxt->inst = precomp->inst; |
---|
325 | ctxt->xpathCtxt->namespaces = precomp->nsList; |
---|
326 | ctxt->xpathCtxt->nsNr = precomp->nsNr; |
---|
327 | } else { |
---|
328 | ctxt->inst = NULL; |
---|
329 | ctxt->xpathCtxt->namespaces = NULL; |
---|
330 | ctxt->xpathCtxt->nsNr = 0; |
---|
331 | } |
---|
332 | result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); |
---|
333 | ctxt->xpathCtxt->contextSize = oldContextSize; |
---|
334 | ctxt->xpathCtxt->proximityPosition = oldProximityPosition; |
---|
335 | ctxt->xpathCtxt->nsNr = oldNsNr; |
---|
336 | ctxt->xpathCtxt->namespaces = oldNamespaces; |
---|
337 | ctxt->inst = oldInst; |
---|
338 | ctxt->node = oldNode; |
---|
339 | ctxt->document = oldDoc; |
---|
340 | if ((precomp == NULL) || (precomp->comp == NULL)) |
---|
341 | xmlXPathFreeCompExpr(comp); |
---|
342 | if (result == NULL) { |
---|
343 | xsltTransformError(ctxt, NULL, precomp->inst, |
---|
344 | "Evaluating variable %s failed\n", elem->name); |
---|
345 | ctxt->state = XSLT_STATE_STOPPED; |
---|
346 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
347 | #ifdef LIBXML_DEBUG_ENABLED |
---|
348 | } else { |
---|
349 | if ((xsltGenericDebugContext == stdout) || |
---|
350 | (xsltGenericDebugContext == stderr)) |
---|
351 | xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, |
---|
352 | result, 0); |
---|
353 | #endif |
---|
354 | #endif |
---|
355 | } |
---|
356 | } else { |
---|
357 | if (elem->tree == NULL) { |
---|
358 | result = xmlXPathNewCString(""); |
---|
359 | } else { |
---|
360 | /* |
---|
361 | * This is a result tree fragment. |
---|
362 | */ |
---|
363 | xmlNodePtr container; |
---|
364 | xmlNodePtr oldInsert; |
---|
365 | xmlDocPtr oldoutput; |
---|
366 | |
---|
367 | container = xmlNewDocNode(ctxt->document->doc, NULL, |
---|
368 | (const xmlChar *) " fake node libxslt", NULL); |
---|
369 | if (container == NULL) |
---|
370 | return(NULL); |
---|
371 | container->parent = NULL; |
---|
372 | |
---|
373 | oldoutput = ctxt->output; |
---|
374 | ctxt->output = NULL; |
---|
375 | oldInsert = ctxt->insert; |
---|
376 | ctxt->insert = container; |
---|
377 | xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL); |
---|
378 | ctxt->insert = oldInsert; |
---|
379 | ctxt->output = oldoutput; |
---|
380 | |
---|
381 | result = xmlXPathNewValueTree(container); |
---|
382 | if (result == NULL) { |
---|
383 | result = xmlXPathNewCString(""); |
---|
384 | } else { |
---|
385 | /* |
---|
386 | * Tag the subtree for removal once consumed |
---|
387 | */ |
---|
388 | result->boolval = 1; |
---|
389 | } |
---|
390 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
391 | #ifdef LIBXML_DEBUG_ENABLED |
---|
392 | if ((xsltGenericDebugContext == stdout) || |
---|
393 | (xsltGenericDebugContext == stderr)) |
---|
394 | xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, |
---|
395 | result, 0); |
---|
396 | #endif |
---|
397 | #endif |
---|
398 | } |
---|
399 | } |
---|
400 | return(result); |
---|
401 | } |
---|
402 | |
---|
403 | /** |
---|
404 | * xsltEvalGlobalVariable: |
---|
405 | * @elem: the variable or parameter. |
---|
406 | * @ctxt: the XSLT transformation context |
---|
407 | * |
---|
408 | * Evaluate a global variable value. |
---|
409 | * |
---|
410 | * Returns the XPath Object value or NULL in case of error |
---|
411 | */ |
---|
412 | static xmlXPathObjectPtr |
---|
413 | xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) { |
---|
414 | xmlXPathObjectPtr result = NULL; |
---|
415 | xsltStylePreCompPtr precomp; |
---|
416 | int oldProximityPosition, oldContextSize; |
---|
417 | xmlNodePtr oldInst; |
---|
418 | int oldNsNr; |
---|
419 | xmlNsPtr *oldNamespaces; |
---|
420 | |
---|
421 | if ((ctxt == NULL) || (elem == NULL)) |
---|
422 | return(NULL); |
---|
423 | if (elem->computed) |
---|
424 | return(elem->value); |
---|
425 | |
---|
426 | |
---|
427 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
428 | xsltGenericDebug(xsltGenericDebugContext, |
---|
429 | "Evaluating global variable %s\n", elem->name); |
---|
430 | #endif |
---|
431 | |
---|
432 | #ifdef WITH_DEBUGGER |
---|
433 | if ((xslDebugStatus != XSLT_DEBUG_NONE) && |
---|
434 | elem->comp && elem->comp->inst) |
---|
435 | xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt); |
---|
436 | #endif |
---|
437 | |
---|
438 | precomp = elem->comp; |
---|
439 | if (elem->select != NULL) { |
---|
440 | xmlXPathCompExprPtr comp = NULL; |
---|
441 | |
---|
442 | if ((precomp != NULL) && (precomp->comp != NULL)) { |
---|
443 | comp = precomp->comp; |
---|
444 | } else { |
---|
445 | comp = xmlXPathCompile(elem->select); |
---|
446 | } |
---|
447 | if (comp == NULL) |
---|
448 | return(NULL); |
---|
449 | oldProximityPosition = ctxt->xpathCtxt->proximityPosition; |
---|
450 | oldContextSize = ctxt->xpathCtxt->contextSize; |
---|
451 | oldInst = ctxt->inst; |
---|
452 | oldNsNr = ctxt->xpathCtxt->nsNr; |
---|
453 | oldNamespaces = ctxt->xpathCtxt->namespaces; |
---|
454 | if (precomp != NULL) { |
---|
455 | ctxt->inst = precomp->inst; |
---|
456 | ctxt->xpathCtxt->namespaces = precomp->nsList; |
---|
457 | ctxt->xpathCtxt->nsNr = precomp->nsNr; |
---|
458 | } else { |
---|
459 | ctxt->inst = NULL; |
---|
460 | ctxt->xpathCtxt->namespaces = NULL; |
---|
461 | ctxt->xpathCtxt->nsNr = 0; |
---|
462 | } |
---|
463 | ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node; |
---|
464 | result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); |
---|
465 | ctxt->xpathCtxt->contextSize = oldContextSize; |
---|
466 | ctxt->xpathCtxt->proximityPosition = oldProximityPosition; |
---|
467 | ctxt->inst = oldInst; |
---|
468 | ctxt->xpathCtxt->nsNr = oldNsNr; |
---|
469 | ctxt->xpathCtxt->namespaces = oldNamespaces; |
---|
470 | if ((precomp == NULL) || (precomp->comp == NULL)) |
---|
471 | xmlXPathFreeCompExpr(comp); |
---|
472 | if (result == NULL) { |
---|
473 | xsltTransformError(ctxt, NULL, precomp->inst, |
---|
474 | "Evaluating global variable %s failed\n", elem->name); |
---|
475 | ctxt->state = XSLT_STATE_STOPPED; |
---|
476 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
477 | #ifdef LIBXML_DEBUG_ENABLED |
---|
478 | } else { |
---|
479 | if ((xsltGenericDebugContext == stdout) || |
---|
480 | (xsltGenericDebugContext == stderr)) |
---|
481 | xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, |
---|
482 | result, 0); |
---|
483 | #endif |
---|
484 | #endif |
---|
485 | } |
---|
486 | } else { |
---|
487 | if (elem->tree == NULL) { |
---|
488 | result = xmlXPathNewCString(""); |
---|
489 | } else { |
---|
490 | /* |
---|
491 | * This is a result tree fragment. |
---|
492 | */ |
---|
493 | xmlNodePtr container; |
---|
494 | xmlNodePtr oldInsert; |
---|
495 | xmlDocPtr oldoutput; |
---|
496 | |
---|
497 | container = xmlNewDocNode(ctxt->document->doc, NULL, |
---|
498 | (const xmlChar *) " fake node libxslt", NULL); |
---|
499 | if (container == NULL) |
---|
500 | return(NULL); |
---|
501 | container->parent = NULL; |
---|
502 | |
---|
503 | oldoutput = ctxt->output; |
---|
504 | ctxt->output = NULL; |
---|
505 | oldInsert = ctxt->insert; |
---|
506 | ctxt->insert = container; |
---|
507 | xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL); |
---|
508 | ctxt->insert = oldInsert; |
---|
509 | ctxt->output = oldoutput; |
---|
510 | |
---|
511 | result = xmlXPathNewValueTree(container); |
---|
512 | if (result == NULL) { |
---|
513 | result = xmlXPathNewCString(""); |
---|
514 | } else { |
---|
515 | /* |
---|
516 | * Tag the subtree for removal once consumed |
---|
517 | */ |
---|
518 | result->boolval = 1; |
---|
519 | } |
---|
520 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
521 | #ifdef LIBXML_DEBUG_ENABLED |
---|
522 | if ((xsltGenericDebugContext == stdout) || |
---|
523 | (xsltGenericDebugContext == stderr)) |
---|
524 | xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, |
---|
525 | result, 0); |
---|
526 | #endif |
---|
527 | #endif |
---|
528 | } |
---|
529 | } |
---|
530 | if (result != NULL) { |
---|
531 | elem->value = result; |
---|
532 | elem->computed = 1; |
---|
533 | } |
---|
534 | return(result); |
---|
535 | } |
---|
536 | |
---|
537 | /** |
---|
538 | * xsltEvalGlobalVariables: |
---|
539 | * @ctxt: the XSLT transformation context |
---|
540 | * |
---|
541 | * Evaluate the global variables of a stylesheet. This need to be |
---|
542 | * done on parsed stylesheets before starting to apply transformations |
---|
543 | * |
---|
544 | * Returns 0 in case of success, -1 in case of error |
---|
545 | */ |
---|
546 | int |
---|
547 | xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) { |
---|
548 | xsltStackElemPtr elem; |
---|
549 | xsltStylesheetPtr style; |
---|
550 | |
---|
551 | if (ctxt == NULL) |
---|
552 | return(-1); |
---|
553 | |
---|
554 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
555 | xsltGenericDebug(xsltGenericDebugContext, |
---|
556 | "Registering global variables\n"); |
---|
557 | #endif |
---|
558 | ctxt->node = (xmlNodePtr) ctxt->document->doc; |
---|
559 | ctxt->xpathCtxt->contextSize = 1; |
---|
560 | ctxt->xpathCtxt->proximityPosition = 1; |
---|
561 | |
---|
562 | /* |
---|
563 | * Walk the list from the stylesheets and populate the hash table |
---|
564 | */ |
---|
565 | style = ctxt->style; |
---|
566 | while (style != NULL) { |
---|
567 | elem = style->variables; |
---|
568 | |
---|
569 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
570 | if ((style->doc != NULL) && (style->doc->URL != NULL)) { |
---|
571 | xsltGenericDebug(xsltGenericDebugContext, |
---|
572 | "Registering global variables from %s\n", |
---|
573 | style->doc->URL); |
---|
574 | } |
---|
575 | #endif |
---|
576 | |
---|
577 | while (elem != NULL) { |
---|
578 | xsltStackElemPtr def; |
---|
579 | |
---|
580 | /* |
---|
581 | * Global variables are stored in the variables pool. |
---|
582 | */ |
---|
583 | def = (xsltStackElemPtr) |
---|
584 | xmlHashLookup2(ctxt->globalVars, |
---|
585 | elem->name, elem->nameURI); |
---|
586 | if (def == NULL) { |
---|
587 | int res; |
---|
588 | |
---|
589 | def = xsltCopyStackElem(elem); |
---|
590 | res = xmlHashAddEntry2(ctxt->globalVars, |
---|
591 | elem->name, elem->nameURI, def); |
---|
592 | } else if ((elem->comp != NULL) && |
---|
593 | (elem->comp->type == XSLT_FUNC_VARIABLE)) { |
---|
594 | /* |
---|
595 | * Redefinition of variables from a different stylesheet |
---|
596 | * should not generate a message. |
---|
597 | */ |
---|
598 | if ((elem->comp->inst != NULL) && |
---|
599 | (def->comp != NULL) && (def->comp->inst != NULL) && |
---|
600 | (elem->comp->inst->doc == def->comp->inst->doc)) { |
---|
601 | xsltTransformError(ctxt, style, elem->comp->inst, |
---|
602 | "Global variable %s already defined\n", elem->name); |
---|
603 | if (style != NULL) style->errors++; |
---|
604 | } |
---|
605 | } |
---|
606 | elem = elem->next; |
---|
607 | } |
---|
608 | |
---|
609 | style = xsltNextImport(style); |
---|
610 | } |
---|
611 | |
---|
612 | /* |
---|
613 | * This part does the actual evaluation |
---|
614 | */ |
---|
615 | ctxt->node = (xmlNodePtr) ctxt->document->doc; |
---|
616 | ctxt->xpathCtxt->contextSize = 1; |
---|
617 | ctxt->xpathCtxt->proximityPosition = 1; |
---|
618 | xmlHashScan(ctxt->globalVars, |
---|
619 | (xmlHashScanner) xsltEvalGlobalVariable, ctxt); |
---|
620 | |
---|
621 | return(0); |
---|
622 | } |
---|
623 | |
---|
624 | /** |
---|
625 | * xsltRegisterGlobalVariable: |
---|
626 | * @style: the XSLT transformation context |
---|
627 | * @name: the variable name |
---|
628 | * @ns_uri: the variable namespace URI |
---|
629 | * @select: the expression which need to be evaluated to generate a value |
---|
630 | * @tree: the subtree if select is NULL |
---|
631 | * @comp: the precompiled value |
---|
632 | * @value: the string value if available |
---|
633 | * |
---|
634 | * Register a new variable value. If @value is NULL it unregisters |
---|
635 | * the variable |
---|
636 | * |
---|
637 | * Returns 0 in case of success, -1 in case of error |
---|
638 | */ |
---|
639 | static int |
---|
640 | xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name, |
---|
641 | const xmlChar *ns_uri, const xmlChar *select, |
---|
642 | xmlNodePtr tree, xsltStylePreCompPtr comp, |
---|
643 | const xmlChar *value) { |
---|
644 | xsltStackElemPtr elem, tmp; |
---|
645 | if (style == NULL) |
---|
646 | return(-1); |
---|
647 | if (name == NULL) |
---|
648 | return(-1); |
---|
649 | if (comp == NULL) |
---|
650 | return(-1); |
---|
651 | |
---|
652 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
653 | if (comp->type == XSLT_FUNC_PARAM) |
---|
654 | xsltGenericDebug(xsltGenericDebugContext, |
---|
655 | "Defining global param %s\n", name); |
---|
656 | else |
---|
657 | xsltGenericDebug(xsltGenericDebugContext, |
---|
658 | "Defining global variable %s\n", name); |
---|
659 | #endif |
---|
660 | |
---|
661 | elem = xsltNewStackElem(); |
---|
662 | if (elem == NULL) |
---|
663 | return(-1); |
---|
664 | elem->comp = comp; |
---|
665 | elem->name = xmlStrdup(name); |
---|
666 | elem->select = xmlStrdup(select); |
---|
667 | if (ns_uri) |
---|
668 | elem->nameURI = xmlStrdup(ns_uri); |
---|
669 | elem->tree = tree; |
---|
670 | tmp = style->variables; |
---|
671 | if (tmp == NULL) { |
---|
672 | elem->next = NULL; |
---|
673 | style->variables = elem; |
---|
674 | } else { |
---|
675 | while (tmp != NULL) { |
---|
676 | if ((elem->comp->type == XSLT_FUNC_VARIABLE) && |
---|
677 | (tmp->comp->type == XSLT_FUNC_VARIABLE) && |
---|
678 | (xmlStrEqual(elem->name, tmp->name)) && |
---|
679 | ((elem->nameURI == tmp->nameURI) || |
---|
680 | (xmlStrEqual(elem->nameURI, tmp->nameURI)))) { |
---|
681 | xsltTransformError(NULL, style, comp->inst, |
---|
682 | "redefinition of global variable %s\n", elem->name); |
---|
683 | if (style != NULL) style->errors++; |
---|
684 | } |
---|
685 | if (tmp->next == NULL) |
---|
686 | break; |
---|
687 | tmp = tmp->next; |
---|
688 | } |
---|
689 | elem->next = NULL; |
---|
690 | tmp->next = elem; |
---|
691 | } |
---|
692 | if (value != NULL) { |
---|
693 | elem->computed = 1; |
---|
694 | elem->value = xmlXPathNewString(value); |
---|
695 | } |
---|
696 | return(0); |
---|
697 | } |
---|
698 | |
---|
699 | /** |
---|
700 | * xsltProcessUserParamInternal |
---|
701 | * |
---|
702 | * @ctxt: the XSLT transformation context |
---|
703 | * @name: a null terminated parameter name |
---|
704 | * @value: a null terminated value (may be an XPath expression) |
---|
705 | * @eval: 0 to treat the value literally, else evaluate as XPath expression |
---|
706 | * |
---|
707 | * If @eval is 0 then @value is treated literally and is stored in the global |
---|
708 | * parameter/variable table without any change. |
---|
709 | * |
---|
710 | * Uf @eval is 1 then @value is treated as an XPath expression and is |
---|
711 | * evaluated. In this case, if you want to pass a string which will be |
---|
712 | * interpreted literally then it must be enclosed in single or double quotes. |
---|
713 | * If the string contains single quotes (double quotes) then it cannot be |
---|
714 | * enclosed single quotes (double quotes). If the string which you want to |
---|
715 | * be treated literally contains both single and double quotes (e.g. Meet |
---|
716 | * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable |
---|
717 | * quoting character. You cannot use ' or " inside the string |
---|
718 | * because the replacement of character entities with their equivalents is |
---|
719 | * done at a different stage of processing. The solution is to call |
---|
720 | * xsltQuoteUserParams or xsltQuoteOneUserParam. |
---|
721 | * |
---|
722 | * This needs to be done on parsed stylesheets before starting to apply |
---|
723 | * transformations. Normally this will be called (directly or indirectly) |
---|
724 | * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams, |
---|
725 | * or xsltQuoteOneUserParam. |
---|
726 | * |
---|
727 | * Returns 0 in case of success, -1 in case of error |
---|
728 | */ |
---|
729 | |
---|
730 | static |
---|
731 | int |
---|
732 | xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, |
---|
733 | const xmlChar * name, |
---|
734 | const xmlChar * value, |
---|
735 | int eval) { |
---|
736 | |
---|
737 | xsltStylesheetPtr style; |
---|
738 | xmlChar *ncname; |
---|
739 | xmlChar *prefix; |
---|
740 | const xmlChar *href; |
---|
741 | xmlXPathCompExprPtr comp; |
---|
742 | xmlXPathObjectPtr result; |
---|
743 | int oldProximityPosition; |
---|
744 | int oldContextSize; |
---|
745 | int oldNsNr; |
---|
746 | xmlNsPtr *oldNamespaces; |
---|
747 | xsltStackElemPtr elem; |
---|
748 | int res; |
---|
749 | |
---|
750 | if (ctxt == NULL) |
---|
751 | return(-1); |
---|
752 | if (name == NULL) |
---|
753 | return(0); |
---|
754 | if (value == NULL) |
---|
755 | return(0); |
---|
756 | |
---|
757 | style = ctxt->style; |
---|
758 | |
---|
759 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
760 | xsltGenericDebug(xsltGenericDebugContext, |
---|
761 | "Evaluating user parameter %s=%s\n", name, value); |
---|
762 | #endif |
---|
763 | |
---|
764 | /* |
---|
765 | * Name lookup |
---|
766 | */ |
---|
767 | |
---|
768 | ncname = xmlSplitQName2(name, &prefix); |
---|
769 | href = NULL; |
---|
770 | if (ncname != NULL) { |
---|
771 | if (prefix != NULL) { |
---|
772 | xmlNsPtr ns; |
---|
773 | |
---|
774 | ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc), |
---|
775 | prefix); |
---|
776 | if (ns == NULL) { |
---|
777 | xsltTransformError(ctxt, style, NULL, |
---|
778 | "user param : no namespace bound to prefix %s\n", prefix); |
---|
779 | href = NULL; |
---|
780 | } else { |
---|
781 | href = ns->href; |
---|
782 | } |
---|
783 | xmlFree(prefix); |
---|
784 | prefix = NULL; |
---|
785 | } else { |
---|
786 | href = NULL; |
---|
787 | } |
---|
788 | xmlFree(ncname); |
---|
789 | ncname = NULL; |
---|
790 | } else { |
---|
791 | href = NULL; |
---|
792 | ncname = xmlStrdup(name); |
---|
793 | } |
---|
794 | |
---|
795 | if (ncname == NULL) |
---|
796 | return (-1); |
---|
797 | |
---|
798 | /* |
---|
799 | * Do the evaluation if @eval is non-zero. |
---|
800 | */ |
---|
801 | |
---|
802 | result = NULL; |
---|
803 | if (eval != 0) { |
---|
804 | comp = xmlXPathCompile(value); |
---|
805 | if (comp != NULL) { |
---|
806 | oldProximityPosition = ctxt->xpathCtxt->proximityPosition; |
---|
807 | oldContextSize = ctxt->xpathCtxt->contextSize; |
---|
808 | ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node; |
---|
809 | |
---|
810 | /* |
---|
811 | * There is really no in scope namespace for parameters on the |
---|
812 | * command line. |
---|
813 | */ |
---|
814 | |
---|
815 | oldNsNr = ctxt->xpathCtxt->nsNr; |
---|
816 | oldNamespaces = ctxt->xpathCtxt->namespaces; |
---|
817 | ctxt->xpathCtxt->namespaces = NULL; |
---|
818 | ctxt->xpathCtxt->nsNr = 0; |
---|
819 | result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); |
---|
820 | ctxt->xpathCtxt->contextSize = oldContextSize; |
---|
821 | ctxt->xpathCtxt->proximityPosition = oldProximityPosition; |
---|
822 | ctxt->xpathCtxt->nsNr = oldNsNr; |
---|
823 | ctxt->xpathCtxt->namespaces = oldNamespaces; |
---|
824 | xmlXPathFreeCompExpr(comp); |
---|
825 | } |
---|
826 | if (result == NULL) { |
---|
827 | xsltTransformError(ctxt, style, NULL, |
---|
828 | "Evaluating user parameter %s failed\n", name); |
---|
829 | ctxt->state = XSLT_STATE_STOPPED; |
---|
830 | xmlFree(ncname); |
---|
831 | return(-1); |
---|
832 | } |
---|
833 | } |
---|
834 | |
---|
835 | /* |
---|
836 | * If @eval is 0 then @value is to be taken literally and result is NULL |
---|
837 | * |
---|
838 | * If @eval is not 0, then @value is an XPath expression and has been |
---|
839 | * successfully evaluated and result contains the resulting value and |
---|
840 | * is not NULL. |
---|
841 | * |
---|
842 | * Now create an xsltStackElemPtr for insertion into the context's |
---|
843 | * global variable/parameter hash table. |
---|
844 | */ |
---|
845 | |
---|
846 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
847 | #ifdef LIBXML_DEBUG_ENABLED |
---|
848 | if ((xsltGenericDebugContext == stdout) || |
---|
849 | (xsltGenericDebugContext == stderr)) |
---|
850 | xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, |
---|
851 | result, 0); |
---|
852 | #endif |
---|
853 | #endif |
---|
854 | |
---|
855 | elem = xsltNewStackElem(); |
---|
856 | if (elem != NULL) { |
---|
857 | elem->name = xmlStrdup(ncname); |
---|
858 | if (value != NULL) |
---|
859 | elem->select = xmlStrdup(value); |
---|
860 | else |
---|
861 | elem->select = NULL; |
---|
862 | if (href) |
---|
863 | elem->nameURI = xmlStrdup(href); |
---|
864 | elem->tree = NULL; |
---|
865 | elem->computed = 1; |
---|
866 | if (eval == 0) { |
---|
867 | elem->value = xmlXPathNewString(value); |
---|
868 | } |
---|
869 | else { |
---|
870 | elem->value = result; |
---|
871 | } |
---|
872 | } |
---|
873 | |
---|
874 | /* |
---|
875 | * Global parameters are stored in the XPath context variables pool. |
---|
876 | */ |
---|
877 | |
---|
878 | res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem); |
---|
879 | if (res != 0) { |
---|
880 | xsltFreeStackElem(elem); |
---|
881 | xsltTransformError(ctxt, style, NULL, |
---|
882 | "Global parameter %s already defined\n", ncname); |
---|
883 | } |
---|
884 | xmlFree(ncname); |
---|
885 | return(0); |
---|
886 | } |
---|
887 | |
---|
888 | /** |
---|
889 | * xsltEvalUserParams: |
---|
890 | * |
---|
891 | * @ctxt: the XSLT transformation context |
---|
892 | * @params: a NULL terminated array of parameters name/value tuples |
---|
893 | * |
---|
894 | * Evaluate the global variables of a stylesheet. This needs to be |
---|
895 | * done on parsed stylesheets before starting to apply transformations. |
---|
896 | * Each of the parameters is evaluated as an XPath expression and stored |
---|
897 | * in the global variables/parameter hash table. If you want your |
---|
898 | * parameter used literally, use xsltQuoteUserParams. |
---|
899 | * |
---|
900 | * Returns 0 in case of success, -1 in case of error |
---|
901 | */ |
---|
902 | |
---|
903 | int |
---|
904 | xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) { |
---|
905 | int indx = 0; |
---|
906 | const xmlChar *name; |
---|
907 | const xmlChar *value; |
---|
908 | |
---|
909 | if (params == NULL) |
---|
910 | return(0); |
---|
911 | while (params[indx] != NULL) { |
---|
912 | name = (const xmlChar *) params[indx++]; |
---|
913 | value = (const xmlChar *) params[indx++]; |
---|
914 | if (xsltEvalOneUserParam(ctxt, name, value) != 0) |
---|
915 | return(-1); |
---|
916 | } |
---|
917 | return 0; |
---|
918 | } |
---|
919 | |
---|
920 | /** |
---|
921 | * xsltQuoteUserParams: |
---|
922 | * |
---|
923 | * @ctxt: the XSLT transformation context |
---|
924 | * @params: a NULL terminated arry of parameters names/values tuples |
---|
925 | * |
---|
926 | * Similar to xsltEvalUserParams, but the values are treated literally and |
---|
927 | * are * *not* evaluated as XPath expressions. This should be done on parsed |
---|
928 | * stylesheets before starting to apply transformations. |
---|
929 | * |
---|
930 | * Returns 0 in case of success, -1 in case of error. |
---|
931 | */ |
---|
932 | |
---|
933 | int |
---|
934 | xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) { |
---|
935 | int indx = 0; |
---|
936 | const xmlChar *name; |
---|
937 | const xmlChar *value; |
---|
938 | |
---|
939 | if (params == NULL) |
---|
940 | return(0); |
---|
941 | while (params[indx] != NULL) { |
---|
942 | name = (const xmlChar *) params[indx++]; |
---|
943 | value = (const xmlChar *) params[indx++]; |
---|
944 | if (xsltQuoteOneUserParam(ctxt, name, value) != 0) |
---|
945 | return(-1); |
---|
946 | } |
---|
947 | return 0; |
---|
948 | } |
---|
949 | |
---|
950 | /** |
---|
951 | * xsltEvalOneUserParam: |
---|
952 | * @ctxt: the XSLT transformation context |
---|
953 | * @name: a null terminated string giving the name of the parameter |
---|
954 | * @value: a null terminated string giving the XPath expression to be evaluated |
---|
955 | * |
---|
956 | * This is normally called from xsltEvalUserParams to process a single |
---|
957 | * parameter from a list of parameters. The @value is evaluated as an |
---|
958 | * XPath expression and the result is stored in the context's global |
---|
959 | * variable/parameter hash table. |
---|
960 | * |
---|
961 | * To have a parameter treated literally (not as an XPath expression) |
---|
962 | * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more |
---|
963 | * details see description of xsltProcessOneUserParamInternal. |
---|
964 | * |
---|
965 | * Returns 0 in case of success, -1 in case of error. |
---|
966 | */ |
---|
967 | |
---|
968 | int |
---|
969 | xsltEvalOneUserParam(xsltTransformContextPtr ctxt, |
---|
970 | const xmlChar * name, |
---|
971 | const xmlChar * value) { |
---|
972 | return xsltProcessUserParamInternal(ctxt, name, value, |
---|
973 | 1 /* xpath eval ? */); |
---|
974 | } |
---|
975 | |
---|
976 | /** |
---|
977 | * xsltQuoteOneUserParam: |
---|
978 | * @ctxt: the XSLT transformation context |
---|
979 | * @name: a null terminated string giving the name of the parameter |
---|
980 | * @value: a null terminated string giving the parameter value |
---|
981 | * |
---|
982 | * This is normally called from xsltQuoteUserParams to process a single |
---|
983 | * parameter from a list of parameters. The @value is stored in the |
---|
984 | * context's global variable/parameter hash table. |
---|
985 | * |
---|
986 | * Returns 0 in case of success, -1 in case of error. |
---|
987 | */ |
---|
988 | |
---|
989 | int |
---|
990 | xsltQuoteOneUserParam(xsltTransformContextPtr ctxt, |
---|
991 | const xmlChar * name, |
---|
992 | const xmlChar * value) { |
---|
993 | return xsltProcessUserParamInternal(ctxt, name, value, |
---|
994 | 0 /* xpath eval ? */); |
---|
995 | } |
---|
996 | |
---|
997 | /** |
---|
998 | * xsltBuildVariable: |
---|
999 | * @ctxt: the XSLT transformation context |
---|
1000 | * @comp: the precompiled form |
---|
1001 | * @tree: the tree if select is NULL |
---|
1002 | * |
---|
1003 | * Computes a new variable value. |
---|
1004 | * |
---|
1005 | * Returns the xsltStackElemPtr or NULL in case of error |
---|
1006 | */ |
---|
1007 | static xsltStackElemPtr |
---|
1008 | xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp, |
---|
1009 | xmlNodePtr tree) { |
---|
1010 | xsltStackElemPtr elem; |
---|
1011 | |
---|
1012 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1013 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1014 | "Building variable %s", comp->name); |
---|
1015 | if (comp->select != NULL) |
---|
1016 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1017 | " select %s", comp->select); |
---|
1018 | xsltGenericDebug(xsltGenericDebugContext, "\n"); |
---|
1019 | #endif |
---|
1020 | |
---|
1021 | elem = xsltNewStackElem(); |
---|
1022 | if (elem == NULL) |
---|
1023 | return(NULL); |
---|
1024 | elem->comp = comp; |
---|
1025 | elem->name = xmlStrdup(comp->name); |
---|
1026 | if (comp->select != NULL) |
---|
1027 | elem->select = xmlStrdup(comp->select); |
---|
1028 | else |
---|
1029 | elem->select = NULL; |
---|
1030 | if (comp->ns) |
---|
1031 | elem->nameURI = xmlStrdup(comp->ns); |
---|
1032 | elem->tree = tree; |
---|
1033 | if (elem->computed == 0) { |
---|
1034 | elem->value = xsltEvalVariable(ctxt, elem, comp); |
---|
1035 | if (elem->value != NULL) |
---|
1036 | elem->computed = 1; |
---|
1037 | } |
---|
1038 | return(elem); |
---|
1039 | } |
---|
1040 | |
---|
1041 | /** |
---|
1042 | * xsltRegisterVariable: |
---|
1043 | * @ctxt: the XSLT transformation context |
---|
1044 | * @comp: pointer to precompiled data |
---|
1045 | * @tree: the tree if select is NULL |
---|
1046 | * @param: this is a parameter actually |
---|
1047 | * |
---|
1048 | * Computes and register a new variable value. |
---|
1049 | * |
---|
1050 | * Returns 0 in case of success, -1 in case of error |
---|
1051 | */ |
---|
1052 | static int |
---|
1053 | xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp, |
---|
1054 | xmlNodePtr tree, int param) { |
---|
1055 | xsltStackElemPtr elem; |
---|
1056 | int present; |
---|
1057 | |
---|
1058 | present = xsltCheckStackElem(ctxt, comp->name, comp->ns); |
---|
1059 | if (param == 0) { |
---|
1060 | if ((present != 0) && (present != 3)) { |
---|
1061 | xsltTransformError(ctxt, NULL, comp->inst, |
---|
1062 | "xsl:variable : redefining %s\n", comp->name); |
---|
1063 | return(0); |
---|
1064 | } |
---|
1065 | } else if (present != 0) { |
---|
1066 | if ((present == 1) || (present == 2)) { |
---|
1067 | xsltTransformError(ctxt, NULL, comp->inst, |
---|
1068 | "xsl:param : redefining %s\n", comp->name); |
---|
1069 | return(0); |
---|
1070 | } |
---|
1071 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1072 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1073 | "param %s defined by caller\n", comp->name); |
---|
1074 | #endif |
---|
1075 | return(0); |
---|
1076 | } |
---|
1077 | elem = xsltBuildVariable(ctxt, comp, tree); |
---|
1078 | xsltAddStackElem(ctxt, elem); |
---|
1079 | return(0); |
---|
1080 | } |
---|
1081 | |
---|
1082 | /** |
---|
1083 | * xsltGlobalVariableLookup: |
---|
1084 | * @ctxt: the XSLT transformation context |
---|
1085 | * @name: the variable name |
---|
1086 | * @ns_uri: the variable namespace URI |
---|
1087 | * |
---|
1088 | * Search in the Variable array of the context for the given |
---|
1089 | * variable value. |
---|
1090 | * |
---|
1091 | * Returns the value or NULL if not found |
---|
1092 | */ |
---|
1093 | static xmlXPathObjectPtr |
---|
1094 | xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, |
---|
1095 | const xmlChar *ns_uri) { |
---|
1096 | xsltStackElemPtr elem; |
---|
1097 | xmlXPathObjectPtr ret = NULL; |
---|
1098 | |
---|
1099 | /* |
---|
1100 | * Lookup the global variables in XPath global variable hash table |
---|
1101 | */ |
---|
1102 | if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL)) |
---|
1103 | return(NULL); |
---|
1104 | elem = (xsltStackElemPtr) |
---|
1105 | xmlHashLookup2(ctxt->globalVars, name, ns_uri); |
---|
1106 | if (elem == NULL) { |
---|
1107 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1108 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1109 | "global variable not found %s\n", name); |
---|
1110 | #endif |
---|
1111 | return(NULL); |
---|
1112 | } |
---|
1113 | if (elem->computed == 0) |
---|
1114 | ret = xsltEvalGlobalVariable(elem, ctxt); |
---|
1115 | else |
---|
1116 | ret = elem->value; |
---|
1117 | return(xmlXPathObjectCopy(ret)); |
---|
1118 | } |
---|
1119 | |
---|
1120 | /** |
---|
1121 | * xsltVariableLookup: |
---|
1122 | * @ctxt: the XSLT transformation context |
---|
1123 | * @name: the variable name |
---|
1124 | * @ns_uri: the variable namespace URI |
---|
1125 | * |
---|
1126 | * Search in the Variable array of the context for the given |
---|
1127 | * variable value. |
---|
1128 | * |
---|
1129 | * Returns the value or NULL if not found |
---|
1130 | */ |
---|
1131 | xmlXPathObjectPtr |
---|
1132 | xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, |
---|
1133 | const xmlChar *ns_uri) { |
---|
1134 | xsltStackElemPtr elem; |
---|
1135 | |
---|
1136 | if (ctxt == NULL) |
---|
1137 | return(NULL); |
---|
1138 | |
---|
1139 | elem = xsltStackLookup(ctxt, name, ns_uri); |
---|
1140 | if (elem == NULL) { |
---|
1141 | return(xsltGlobalVariableLookup(ctxt, name, ns_uri)); |
---|
1142 | } |
---|
1143 | if (elem->computed == 0) { |
---|
1144 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1145 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1146 | "uncomputed variable %s\n", name); |
---|
1147 | #endif |
---|
1148 | elem->value = xsltEvalVariable(ctxt, elem, NULL); |
---|
1149 | elem->computed = 1; |
---|
1150 | } |
---|
1151 | if (elem->value != NULL) |
---|
1152 | return(xmlXPathObjectCopy(elem->value)); |
---|
1153 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1154 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1155 | "variable not found %s\n", name); |
---|
1156 | #endif |
---|
1157 | return(NULL); |
---|
1158 | } |
---|
1159 | |
---|
1160 | /** |
---|
1161 | * xsltParseStylesheetCallerParam: |
---|
1162 | * @ctxt: the XSLT transformation context |
---|
1163 | * @cur: the "param" element |
---|
1164 | * |
---|
1165 | * parse an XSLT transformation param declaration, compute |
---|
1166 | * its value but doesn't record it. |
---|
1167 | * |
---|
1168 | * Returns the new xsltStackElemPtr or NULL |
---|
1169 | */ |
---|
1170 | |
---|
1171 | xsltStackElemPtr |
---|
1172 | xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) { |
---|
1173 | xmlNodePtr tree = NULL; |
---|
1174 | xsltStackElemPtr elem = NULL; |
---|
1175 | xsltStylePreCompPtr comp; |
---|
1176 | |
---|
1177 | if ((cur == NULL) || (ctxt == NULL)) |
---|
1178 | return(NULL); |
---|
1179 | comp = (xsltStylePreCompPtr) cur->_private; |
---|
1180 | if (comp == NULL) { |
---|
1181 | xsltTransformError(ctxt, NULL, cur, |
---|
1182 | "xsl:param : compilation error\n"); |
---|
1183 | return(NULL); |
---|
1184 | } |
---|
1185 | |
---|
1186 | if (comp->name == NULL) { |
---|
1187 | xsltTransformError(ctxt, NULL, cur, |
---|
1188 | "xsl:param : missing name attribute\n"); |
---|
1189 | return(NULL); |
---|
1190 | } |
---|
1191 | |
---|
1192 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1193 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1194 | "Handling param %s\n", comp->name); |
---|
1195 | #endif |
---|
1196 | |
---|
1197 | if (comp->select == NULL) { |
---|
1198 | tree = cur->children; |
---|
1199 | } else { |
---|
1200 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1201 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1202 | " select %s\n", comp->select); |
---|
1203 | #endif |
---|
1204 | tree = cur; |
---|
1205 | } |
---|
1206 | |
---|
1207 | elem = xsltBuildVariable(ctxt, comp, tree); |
---|
1208 | |
---|
1209 | return(elem); |
---|
1210 | } |
---|
1211 | |
---|
1212 | /** |
---|
1213 | * xsltParseGlobalVariable: |
---|
1214 | * @style: the XSLT stylesheet |
---|
1215 | * @cur: the "variable" element |
---|
1216 | * |
---|
1217 | * parse an XSLT transformation variable declaration and record |
---|
1218 | * its value. |
---|
1219 | */ |
---|
1220 | |
---|
1221 | void |
---|
1222 | xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) { |
---|
1223 | xsltStylePreCompPtr comp; |
---|
1224 | |
---|
1225 | if ((cur == NULL) || (style == NULL)) |
---|
1226 | return; |
---|
1227 | |
---|
1228 | xsltStylePreCompute(style, cur); |
---|
1229 | comp = (xsltStylePreCompPtr) cur->_private; |
---|
1230 | if (comp == NULL) { |
---|
1231 | xsltTransformError(NULL, style, cur, |
---|
1232 | "xsl:variable : compilation failed\n"); |
---|
1233 | return; |
---|
1234 | } |
---|
1235 | |
---|
1236 | if (comp->name == NULL) { |
---|
1237 | xsltTransformError(NULL, style, cur, |
---|
1238 | "xsl:variable : missing name attribute\n"); |
---|
1239 | return; |
---|
1240 | } |
---|
1241 | |
---|
1242 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1243 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1244 | "Registering global variable %s\n", comp->name); |
---|
1245 | #endif |
---|
1246 | |
---|
1247 | xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select, |
---|
1248 | cur->children, comp, NULL); |
---|
1249 | } |
---|
1250 | |
---|
1251 | /** |
---|
1252 | * xsltParseGlobalParam: |
---|
1253 | * @style: the XSLT stylesheet |
---|
1254 | * @cur: the "param" element |
---|
1255 | * |
---|
1256 | * parse an XSLT transformation param declaration and record |
---|
1257 | * its value. |
---|
1258 | */ |
---|
1259 | |
---|
1260 | void |
---|
1261 | xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) { |
---|
1262 | xsltStylePreCompPtr comp; |
---|
1263 | |
---|
1264 | if ((cur == NULL) || (style == NULL)) |
---|
1265 | return; |
---|
1266 | |
---|
1267 | xsltStylePreCompute(style, cur); |
---|
1268 | comp = (xsltStylePreCompPtr) cur->_private; |
---|
1269 | if (comp == NULL) { |
---|
1270 | xsltTransformError(NULL, style, cur, |
---|
1271 | "xsl:param : compilation failed\n"); |
---|
1272 | return; |
---|
1273 | } |
---|
1274 | |
---|
1275 | if (comp->name == NULL) { |
---|
1276 | xsltTransformError(NULL, style, cur, |
---|
1277 | "xsl:param : missing name attribute\n"); |
---|
1278 | return; |
---|
1279 | } |
---|
1280 | |
---|
1281 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1282 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1283 | "Registering global param %s\n", comp->name); |
---|
1284 | #endif |
---|
1285 | |
---|
1286 | xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select, |
---|
1287 | cur->children, comp, NULL); |
---|
1288 | } |
---|
1289 | |
---|
1290 | /** |
---|
1291 | * xsltParseStylesheetVariable: |
---|
1292 | * @ctxt: the XSLT transformation context |
---|
1293 | * @cur: the "variable" element |
---|
1294 | * |
---|
1295 | * parse an XSLT transformation variable declaration and record |
---|
1296 | * its value. |
---|
1297 | */ |
---|
1298 | |
---|
1299 | void |
---|
1300 | xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) { |
---|
1301 | xsltStylePreCompPtr comp; |
---|
1302 | |
---|
1303 | if ((cur == NULL) || (ctxt == NULL)) |
---|
1304 | return; |
---|
1305 | |
---|
1306 | comp = (xsltStylePreCompPtr) cur->_private; |
---|
1307 | if (comp == NULL) { |
---|
1308 | xsltTransformError(ctxt, NULL, cur, |
---|
1309 | "xsl:variable : compilation failed\n"); |
---|
1310 | return; |
---|
1311 | } |
---|
1312 | |
---|
1313 | if (comp->name == NULL) { |
---|
1314 | xsltTransformError(ctxt, NULL, cur, |
---|
1315 | "xsl:variable : missing name attribute\n"); |
---|
1316 | return; |
---|
1317 | } |
---|
1318 | |
---|
1319 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1320 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1321 | "Registering variable %s\n", comp->name); |
---|
1322 | #endif |
---|
1323 | |
---|
1324 | xsltRegisterVariable(ctxt, comp, cur->children, 0); |
---|
1325 | } |
---|
1326 | |
---|
1327 | /** |
---|
1328 | * xsltParseStylesheetParam: |
---|
1329 | * @ctxt: the XSLT transformation context |
---|
1330 | * @cur: the "param" element |
---|
1331 | * |
---|
1332 | * parse an XSLT transformation param declaration and record |
---|
1333 | * its value. |
---|
1334 | */ |
---|
1335 | |
---|
1336 | void |
---|
1337 | xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) { |
---|
1338 | xsltStylePreCompPtr comp; |
---|
1339 | |
---|
1340 | if ((cur == NULL) || (ctxt == NULL)) |
---|
1341 | return; |
---|
1342 | |
---|
1343 | comp = (xsltStylePreCompPtr) cur->_private; |
---|
1344 | if (comp == NULL) { |
---|
1345 | xsltTransformError(ctxt, NULL, cur, |
---|
1346 | "xsl:param : compilation failed\n"); |
---|
1347 | return; |
---|
1348 | } |
---|
1349 | |
---|
1350 | if (comp->name == NULL) { |
---|
1351 | xsltTransformError(ctxt, NULL, cur, |
---|
1352 | "xsl:param : missing name attribute\n"); |
---|
1353 | return; |
---|
1354 | } |
---|
1355 | |
---|
1356 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1357 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1358 | "Registering param %s\n", comp->name); |
---|
1359 | #endif |
---|
1360 | |
---|
1361 | xsltRegisterVariable(ctxt, comp, cur->children, 1); |
---|
1362 | } |
---|
1363 | |
---|
1364 | /** |
---|
1365 | * xsltFreeGlobalVariables: |
---|
1366 | * @ctxt: the XSLT transformation context |
---|
1367 | * |
---|
1368 | * Free up the data associated to the global variables |
---|
1369 | * its value. |
---|
1370 | */ |
---|
1371 | |
---|
1372 | void |
---|
1373 | xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) { |
---|
1374 | xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem); |
---|
1375 | } |
---|
1376 | |
---|
1377 | /** |
---|
1378 | * xsltXPathVariableLookup: |
---|
1379 | * @ctxt: a void * but the the XSLT transformation context actually |
---|
1380 | * @name: the variable name |
---|
1381 | * @ns_uri: the variable namespace URI |
---|
1382 | * |
---|
1383 | * This is the entry point when a varibale is needed by the XPath |
---|
1384 | * interpretor. |
---|
1385 | * |
---|
1386 | * Returns the value or NULL if not found |
---|
1387 | */ |
---|
1388 | xmlXPathObjectPtr |
---|
1389 | xsltXPathVariableLookup(void *ctxt, const xmlChar *name, |
---|
1390 | const xmlChar *ns_uri) { |
---|
1391 | xsltTransformContextPtr context; |
---|
1392 | xmlXPathObjectPtr ret; |
---|
1393 | |
---|
1394 | if ((ctxt == NULL) || (name == NULL)) |
---|
1395 | return(NULL); |
---|
1396 | |
---|
1397 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1398 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1399 | "Lookup variable %s\n", name); |
---|
1400 | #endif |
---|
1401 | context = (xsltTransformContextPtr) ctxt; |
---|
1402 | ret = xsltVariableLookup(context, name, ns_uri); |
---|
1403 | if (ret == NULL) { |
---|
1404 | xsltTransformError(ctxt, NULL, NULL, |
---|
1405 | "unregistered variable %s\n", name); |
---|
1406 | } |
---|
1407 | #ifdef WITH_XSLT_DEBUG_VARIABLE |
---|
1408 | if (ret != NULL) |
---|
1409 | xsltGenericDebug(xsltGenericDebugContext, |
---|
1410 | "found variable %s\n", name); |
---|
1411 | #endif |
---|
1412 | return(ret); |
---|
1413 | } |
---|
1414 | |
---|
1415 | |
---|