Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xslt/libxslt/variables.c
8755 views
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
* [email protected]
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 <libxml/dict.h>
26
#include "xslt.h"
27
#include "xsltInternals.h"
28
#include "xsltutils.h"
29
#include "variables.h"
30
#include "transform.h"
31
#include "imports.h"
32
#include "preproc.h"
33
#include "keys.h"
34
35
#ifdef WITH_XSLT_DEBUG
36
#define WITH_XSLT_DEBUG_VARIABLE
37
#endif
38
39
#ifdef XSLT_REFACTORED
40
const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
41
#endif
42
43
static const xmlChar *xsltComputingGlobalVarMarker =
44
(const xmlChar *) " var/param being computed";
45
46
#define XSLT_VAR_GLOBAL (1<<0)
47
#define XSLT_VAR_IN_SELECT (1<<1)
48
#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
49
50
/************************************************************************
51
* *
52
* Result Value Tree (Result Tree Fragment) interfaces *
53
* *
54
************************************************************************/
55
/**
56
* xsltCreateRVT:
57
* @ctxt: an XSLT transformation context
58
*
59
* Creates a Result Value Tree
60
* (the XSLT 1.0 term for this is "Result Tree Fragment")
61
*
62
* Returns the result value tree or NULL in case of API or internal errors.
63
*/
64
xmlDocPtr
65
xsltCreateRVT(xsltTransformContextPtr ctxt)
66
{
67
xmlDocPtr container;
68
69
/*
70
* Question: Why is this function public?
71
* Answer: It is called by the EXSLT module.
72
*/
73
if (ctxt == NULL)
74
return(NULL);
75
76
/*
77
* Reuse a RTF from the cache if available.
78
*/
79
if (ctxt->cache->RVT) {
80
container = ctxt->cache->RVT;
81
ctxt->cache->RVT = (xmlDocPtr) container->next;
82
/* clear the internal pointers */
83
container->next = NULL;
84
container->prev = NULL;
85
if (ctxt->cache->nbRVT > 0)
86
ctxt->cache->nbRVT--;
87
#ifdef XSLT_DEBUG_PROFILE_CACHE
88
ctxt->cache->dbgReusedRVTs++;
89
#endif
90
return(container);
91
}
92
93
container = xmlNewDoc(NULL);
94
if (container == NULL)
95
return(NULL);
96
container->dict = ctxt->dict;
97
xmlDictReference(container->dict);
98
XSLT_MARK_RES_TREE_FRAG(container);
99
container->doc = container;
100
container->parent = NULL;
101
return(container);
102
}
103
104
/**
105
* xsltRegisterTmpRVT:
106
* @ctxt: an XSLT transformation context
107
* @RVT: a result value tree (Result Tree Fragment)
108
*
109
* Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
110
* in the garbage collector.
111
* The fragment will be freed at the exit of the currently
112
* instantiated xsl:template.
113
* Obsolete; this function might produce massive memory overhead,
114
* since the fragment is only freed when the current xsl:template
115
* exits. Use xsltRegisterLocalRVT() instead.
116
*
117
* Returns 0 in case of success and -1 in case of API or internal errors.
118
*/
119
int
120
xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
121
{
122
if ((ctxt == NULL) || (RVT == NULL))
123
return(-1);
124
125
RVT->prev = NULL;
126
RVT->compression = XSLT_RVT_LOCAL;
127
128
/*
129
* We'll restrict the lifetime of user-created fragments
130
* insinde an xsl:variable and xsl:param to the lifetime of the
131
* var/param itself.
132
*/
133
if (ctxt->contextVariable != NULL) {
134
RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
135
XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
136
return(0);
137
}
138
139
RVT->next = (xmlNodePtr) ctxt->tmpRVT;
140
if (ctxt->tmpRVT != NULL)
141
ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
142
ctxt->tmpRVT = RVT;
143
return(0);
144
}
145
146
/**
147
* xsltRegisterLocalRVT:
148
* @ctxt: an XSLT transformation context
149
* @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)
150
*
151
* Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
152
* in the RVT garbage collector.
153
* The fragment will be freed when the instruction which created the
154
* fragment exits.
155
*
156
* Returns 0 in case of success and -1 in case of API or internal errors.
157
*/
158
int
159
xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
160
xmlDocPtr RVT)
161
{
162
if ((ctxt == NULL) || (RVT == NULL))
163
return(-1);
164
165
RVT->prev = NULL;
166
RVT->compression = XSLT_RVT_LOCAL;
167
168
/*
169
* When evaluating "select" expressions of xsl:variable
170
* and xsl:param, we need to bind newly created tree fragments
171
* to the variable itself; otherwise the fragment will be
172
* freed before we leave the scope of a var.
173
*/
174
if ((ctxt->contextVariable != NULL) &&
175
(XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
176
{
177
RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
178
XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
179
return(0);
180
}
181
/*
182
* Store the fragment in the scope of the current instruction.
183
* If not reference by a returning instruction (like EXSLT's function),
184
* then this fragment will be freed, when the instruction exits.
185
*/
186
RVT->next = (xmlNodePtr) ctxt->localRVT;
187
if (ctxt->localRVT != NULL)
188
ctxt->localRVT->prev = (xmlNodePtr) RVT;
189
ctxt->localRVT = RVT;
190
return(0);
191
}
192
193
/**
194
* xsltExtensionInstructionResultFinalize:
195
* @ctxt: an XSLT transformation context
196
*
197
* Finalizes the data (e.g. result tree fragments) created
198
* within a value-returning process (e.g. EXSLT's function).
199
* Tree fragments marked as being returned by a function are
200
* set to normal state, which means that the fragment garbage
201
* collector will free them after the function-calling process exits.
202
*
203
* Returns 0 in case of success and -1 in case of API or internal errors.
204
*
205
* This function is unsupported in newer releases of libxslt.
206
*/
207
int
208
xsltExtensionInstructionResultFinalize(
209
xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED)
210
{
211
xmlGenericError(xmlGenericErrorContext,
212
"xsltExtensionInstructionResultFinalize is unsupported "
213
"in this release of libxslt.\n");
214
return(-1);
215
}
216
217
/**
218
* xsltExtensionInstructionResultRegister:
219
* @ctxt: an XSLT transformation context
220
* @obj: an XPath object to be inspected for result tree fragments
221
*
222
* Marks the result of a value-returning extension instruction
223
* in order to avoid it being garbage collected before the
224
* extension instruction exits.
225
* Note that one still has to additionally register any newly created
226
* tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
227
*
228
* Returns 0 in case of success and -1 in case of error.
229
*
230
* It isn't necessary to call this function in newer releases of
231
* libxslt.
232
*/
233
int
234
xsltExtensionInstructionResultRegister(
235
xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
236
xmlXPathObjectPtr obj ATTRIBUTE_UNUSED)
237
{
238
return(0);
239
}
240
241
/**
242
* xsltFlagRVTs:
243
* @ctxt: an XSLT transformation context
244
* @obj: an XPath object to be inspected for result tree fragments
245
* @val: the flag value
246
*
247
* Updates ownership information of RVTs in @obj according to @val.
248
*
249
* @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its
250
* RVTs won't be destroyed after leaving the returning scope.
251
* @val = XSLT_RVT_LOCAL for the result of an extension function to reset
252
* the state of its RVTs after it was returned to a new scope.
253
* @val = XSLT_RVT_GLOBAL for parts of global variables.
254
*
255
* Returns 0 in case of success and -1 in case of error.
256
*/
257
int
258
xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, int val) {
259
int i;
260
xmlNodePtr cur;
261
xmlDocPtr doc;
262
263
if ((ctxt == NULL) || (obj == NULL))
264
return(-1);
265
266
/*
267
* OPTIMIZE TODO: If no local variables/params and no local tree
268
* fragments were created, then we don't need to analyse the XPath
269
* objects for tree fragments.
270
*/
271
272
if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
273
return(0);
274
if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
275
return(0);
276
277
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
278
cur = obj->nodesetval->nodeTab[i];
279
if (cur->type == XML_NAMESPACE_DECL) {
280
/*
281
* The XPath module sets the owner element of a ns-node on
282
* the ns->next field.
283
*/
284
if ((((xmlNsPtr) cur)->next != NULL) &&
285
(((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
286
{
287
cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
288
doc = cur->doc;
289
} else {
290
xsltTransformError(ctxt, NULL, ctxt->inst,
291
"Internal error in xsltFlagRVTs(): "
292
"Cannot retrieve the doc of a namespace node.\n");
293
return(-1);
294
}
295
} else {
296
doc = cur->doc;
297
}
298
if (doc == NULL) {
299
xsltTransformError(ctxt, NULL, ctxt->inst,
300
"Internal error in xsltFlagRVTs(): "
301
"Cannot retrieve the doc of a node.\n");
302
return(-1);
303
}
304
if (doc->name && (doc->name[0] == ' ') &&
305
doc->compression != XSLT_RVT_GLOBAL) {
306
/*
307
* This is a result tree fragment.
308
* We store ownership information in the @compression field.
309
* TODO: How do we know if this is a doc acquired via the
310
* document() function?
311
*/
312
#ifdef WITH_XSLT_DEBUG_VARIABLE
313
XSLT_TRACE(ctxt, XSLT_TRACE_VARIABLES,
314
xsltGenericDebug(xsltGenericDebugContext,
315
"Flagging RVT %p: %d -> %d\n",
316
(void *) doc, doc->compression, val));
317
#endif
318
319
if (val == XSLT_RVT_LOCAL) {
320
if (doc->compression == XSLT_RVT_FUNC_RESULT)
321
doc->compression = XSLT_RVT_LOCAL;
322
} else if (val == XSLT_RVT_GLOBAL) {
323
if (doc->compression != XSLT_RVT_LOCAL) {
324
xmlGenericError(xmlGenericErrorContext,
325
"xsltFlagRVTs: Invalid transition %d => GLOBAL\n",
326
doc->compression);
327
doc->compression = XSLT_RVT_GLOBAL;
328
return(-1);
329
}
330
331
/* Will be registered as persistant in xsltReleaseLocalRVTs. */
332
doc->compression = XSLT_RVT_GLOBAL;
333
} else if (val == XSLT_RVT_FUNC_RESULT) {
334
doc->compression = val;
335
}
336
}
337
}
338
339
return(0);
340
}
341
342
/**
343
* xsltReleaseRVT:
344
* @ctxt: an XSLT transformation context
345
* @RVT: a result value tree (Result Tree Fragment)
346
*
347
* Either frees the RVT (which is an xmlDoc) or stores
348
* it in the context's cache for later reuse.
349
*/
350
void
351
xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
352
{
353
if (RVT == NULL)
354
return;
355
356
if (ctxt && (ctxt->cache->nbRVT < 40)) {
357
/*
358
* Store the Result Tree Fragment.
359
* Free the document info.
360
*/
361
if (RVT->_private != NULL) {
362
xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
363
xmlFree(RVT->_private);
364
RVT->_private = NULL;
365
}
366
/*
367
* Clear the document tree.
368
*/
369
if (RVT->children != NULL) {
370
xmlFreeNodeList(RVT->children);
371
RVT->children = NULL;
372
RVT->last = NULL;
373
}
374
if (RVT->ids != NULL) {
375
xmlFreeIDTable((xmlIDTablePtr) RVT->ids);
376
RVT->ids = NULL;
377
}
378
379
/*
380
* Reset the ownership information.
381
*/
382
RVT->compression = 0;
383
384
RVT->next = (xmlNodePtr) ctxt->cache->RVT;
385
ctxt->cache->RVT = RVT;
386
387
ctxt->cache->nbRVT++;
388
389
#ifdef XSLT_DEBUG_PROFILE_CACHE
390
ctxt->cache->dbgCachedRVTs++;
391
#endif
392
return;
393
}
394
/*
395
* Free it.
396
*/
397
if (RVT->_private != NULL) {
398
xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
399
xmlFree(RVT->_private);
400
}
401
xmlFreeDoc(RVT);
402
}
403
404
/**
405
* xsltRegisterPersistRVT:
406
* @ctxt: an XSLT transformation context
407
* @RVT: a result value tree (Result Tree Fragment)
408
*
409
* Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
410
* in the fragment garbage collector.
411
* The fragment will be freed when the transformation context is
412
* freed.
413
*
414
* Returns 0 in case of success and -1 in case of error.
415
*/
416
int
417
xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
418
{
419
if ((ctxt == NULL) || (RVT == NULL)) return(-1);
420
421
RVT->compression = XSLT_RVT_GLOBAL;
422
RVT->prev = NULL;
423
RVT->next = (xmlNodePtr) ctxt->persistRVT;
424
if (ctxt->persistRVT != NULL)
425
ctxt->persistRVT->prev = (xmlNodePtr) RVT;
426
ctxt->persistRVT = RVT;
427
return(0);
428
}
429
430
/**
431
* xsltFreeRVTs:
432
* @ctxt: an XSLT transformation context
433
*
434
* Frees all registered result value trees (Result Tree Fragments)
435
* of the transformation. Internal function; should not be called
436
* by user-code.
437
*/
438
void
439
xsltFreeRVTs(xsltTransformContextPtr ctxt)
440
{
441
xmlDocPtr cur, next;
442
443
if (ctxt == NULL)
444
return;
445
/*
446
* Local fragments.
447
*/
448
cur = ctxt->localRVT;
449
while (cur != NULL) {
450
next = (xmlDocPtr) cur->next;
451
if (cur->_private != NULL) {
452
xsltFreeDocumentKeys(cur->_private);
453
xmlFree(cur->_private);
454
}
455
xmlFreeDoc(cur);
456
cur = next;
457
}
458
ctxt->localRVT = NULL;
459
/*
460
* User-created per-template fragments.
461
*/
462
cur = ctxt->tmpRVT;
463
while (cur != NULL) {
464
next = (xmlDocPtr) cur->next;
465
if (cur->_private != NULL) {
466
xsltFreeDocumentKeys(cur->_private);
467
xmlFree(cur->_private);
468
}
469
xmlFreeDoc(cur);
470
cur = next;
471
}
472
ctxt->tmpRVT = NULL;
473
/*
474
* Global fragments.
475
*/
476
cur = ctxt->persistRVT;
477
while (cur != NULL) {
478
next = (xmlDocPtr) cur->next;
479
if (cur->_private != NULL) {
480
xsltFreeDocumentKeys(cur->_private);
481
xmlFree(cur->_private);
482
}
483
xmlFreeDoc(cur);
484
cur = next;
485
}
486
ctxt->persistRVT = NULL;
487
}
488
489
/************************************************************************
490
* *
491
* Module interfaces *
492
* *
493
************************************************************************/
494
495
/**
496
* xsltNewStackElem:
497
*
498
* Create a new XSLT ParserContext
499
*
500
* Returns the newly allocated xsltParserStackElem or NULL in case of error
501
*/
502
static xsltStackElemPtr
503
xsltNewStackElem(xsltTransformContextPtr ctxt)
504
{
505
xsltStackElemPtr ret;
506
/*
507
* Reuse a stack item from the cache if available.
508
*/
509
if (ctxt && ctxt->cache->stackItems) {
510
ret = ctxt->cache->stackItems;
511
ctxt->cache->stackItems = ret->next;
512
ret->next = NULL;
513
ctxt->cache->nbStackItems--;
514
#ifdef XSLT_DEBUG_PROFILE_CACHE
515
ctxt->cache->dbgReusedVars++;
516
#endif
517
return(ret);
518
}
519
ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
520
if (ret == NULL) {
521
xsltTransformError(NULL, NULL, NULL,
522
"xsltNewStackElem : malloc failed\n");
523
return(NULL);
524
}
525
memset(ret, 0, sizeof(xsltStackElem));
526
ret->context = ctxt;
527
return(ret);
528
}
529
530
/**
531
* xsltCopyStackElem:
532
* @elem: an XSLT stack element
533
*
534
* Makes a copy of the stack element
535
*
536
* Returns the copy of NULL
537
*/
538
static xsltStackElemPtr
539
xsltCopyStackElem(xsltStackElemPtr elem) {
540
xsltStackElemPtr cur;
541
542
cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
543
if (cur == NULL) {
544
xsltTransformError(NULL, NULL, NULL,
545
"xsltCopyStackElem : malloc failed\n");
546
return(NULL);
547
}
548
memset(cur, 0, sizeof(xsltStackElem));
549
cur->context = elem->context;
550
cur->name = elem->name;
551
cur->nameURI = elem->nameURI;
552
cur->select = elem->select;
553
cur->tree = elem->tree;
554
cur->comp = elem->comp;
555
return(cur);
556
}
557
558
/**
559
* xsltFreeStackElem:
560
* @elem: an XSLT stack element
561
*
562
* Free up the memory allocated by @elem
563
*/
564
static void
565
xsltFreeStackElem(xsltStackElemPtr elem) {
566
if (elem == NULL)
567
return;
568
if (elem->value != NULL)
569
xmlXPathFreeObject(elem->value);
570
/*
571
* Release the list of temporary Result Tree Fragments.
572
*/
573
if (elem->context) {
574
xmlDocPtr cur;
575
576
while (elem->fragment != NULL) {
577
cur = elem->fragment;
578
elem->fragment = (xmlDocPtr) cur->next;
579
580
if (cur->compression == XSLT_RVT_LOCAL) {
581
xsltReleaseRVT(elem->context, cur);
582
} else if (cur->compression == XSLT_RVT_FUNC_RESULT) {
583
xsltRegisterLocalRVT(elem->context, cur);
584
cur->compression = XSLT_RVT_FUNC_RESULT;
585
} else {
586
xmlGenericError(xmlGenericErrorContext,
587
"xsltFreeStackElem: Unexpected RVT flag %d\n",
588
cur->compression);
589
}
590
}
591
}
592
/*
593
* Cache or free the variable structure.
594
*/
595
if (elem->context && (elem->context->cache->nbStackItems < 50)) {
596
/*
597
* Store the item in the cache.
598
*/
599
xsltTransformContextPtr ctxt = elem->context;
600
memset(elem, 0, sizeof(xsltStackElem));
601
elem->context = ctxt;
602
elem->next = ctxt->cache->stackItems;
603
ctxt->cache->stackItems = elem;
604
ctxt->cache->nbStackItems++;
605
#ifdef XSLT_DEBUG_PROFILE_CACHE
606
ctxt->cache->dbgCachedVars++;
607
#endif
608
return;
609
}
610
xmlFree(elem);
611
}
612
613
static void
614
xsltFreeStackElemEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
615
xsltFreeStackElem((xsltStackElemPtr) payload);
616
}
617
618
619
/**
620
* xsltFreeStackElemList:
621
* @elem: an XSLT stack element
622
*
623
* Free up the memory allocated by @elem
624
*/
625
void
626
xsltFreeStackElemList(xsltStackElemPtr elem) {
627
xsltStackElemPtr next;
628
629
while (elem != NULL) {
630
next = elem->next;
631
xsltFreeStackElem(elem);
632
elem = next;
633
}
634
}
635
636
/**
637
* xsltStackLookup:
638
* @ctxt: an XSLT transformation context
639
* @name: the local part of the name
640
* @nameURI: the URI part of the name
641
*
642
* Locate an element in the stack based on its name.
643
*/
644
static xsltStackElemPtr
645
xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
646
const xmlChar *nameURI) {
647
int i;
648
xsltStackElemPtr cur;
649
650
if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
651
return(NULL);
652
653
/*
654
* Do the lookup from the top of the stack, but
655
* don't use params being computed in a call-param
656
* First lookup expects the variable name and URI to
657
* come from the disctionnary and hence pointer comparison.
658
*/
659
for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
660
cur = ctxt->varsTab[i-1];
661
while (cur != NULL) {
662
if ((cur->name == name) && (cur->nameURI == nameURI)) {
663
return(cur);
664
}
665
cur = cur->next;
666
}
667
}
668
669
/*
670
* Redo the lookup with interned string compares
671
* to avoid string compares.
672
*/
673
name = xmlDictLookup(ctxt->dict, name, -1);
674
if (nameURI != NULL)
675
nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
676
677
for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
678
cur = ctxt->varsTab[i-1];
679
while (cur != NULL) {
680
if ((cur->name == name) && (cur->nameURI == nameURI)) {
681
return(cur);
682
}
683
cur = cur->next;
684
}
685
}
686
687
return(NULL);
688
}
689
690
#ifdef XSLT_REFACTORED
691
#else
692
693
/**
694
* xsltCheckStackElem:
695
* @ctxt: xn XSLT transformation context
696
* @name: the variable name
697
* @nameURI: the variable namespace URI
698
*
699
* Checks whether a variable or param is already defined.
700
*
701
* URGENT TODO: Checks for redefinition of vars/params should be
702
* done only at compilation time.
703
*
704
* Returns 1 if variable is present, 2 if param is present, 3 if this
705
* is an inherited param, 0 if not found, -1 in case of failure.
706
*/
707
static int
708
xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
709
const xmlChar *nameURI) {
710
xsltStackElemPtr cur;
711
712
if ((ctxt == NULL) || (name == NULL))
713
return(-1);
714
715
cur = xsltStackLookup(ctxt, name, nameURI);
716
if (cur == NULL)
717
return(0);
718
if (cur->comp != NULL) {
719
if (cur->comp->type == XSLT_FUNC_WITHPARAM)
720
return(3);
721
else if (cur->comp->type == XSLT_FUNC_PARAM)
722
return(2);
723
}
724
725
return(1);
726
}
727
728
#endif /* XSLT_REFACTORED */
729
730
/**
731
* xsltAddStackElem:
732
* @ctxt: xn XSLT transformation context
733
* @elem: a stack element
734
*
735
* Push an element (or list) onto the stack.
736
* In case of a list, each member will be pushed into
737
* a seperate slot; i.e. there's always 1 stack entry for
738
* 1 stack element.
739
*
740
* Returns 0 in case of success, -1 in case of failure.
741
*/
742
static int
743
xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
744
{
745
if ((ctxt == NULL) || (elem == NULL))
746
return(-1);
747
748
do {
749
if (ctxt->varsNr >= ctxt->varsMax) {
750
xsltStackElemPtr *tmp;
751
int newMax = ctxt->varsMax == 0 ? 10 : 2 * ctxt->varsMax;
752
753
tmp = (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
754
newMax * sizeof(*tmp));
755
if (tmp == NULL) {
756
xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
757
return (-1);
758
}
759
ctxt->varsTab = tmp;
760
ctxt->varsMax = newMax;
761
}
762
ctxt->varsTab[ctxt->varsNr++] = elem;
763
ctxt->vars = elem;
764
765
elem = elem->next;
766
} while (elem != NULL);
767
768
return(0);
769
}
770
771
/**
772
* xsltAddStackElemList:
773
* @ctxt: xn XSLT transformation context
774
* @elems: a stack element list
775
*
776
* Push an element list onto the stack.
777
*
778
* Returns 0 in case of success, -1 in case of failure.
779
*/
780
int
781
xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
782
{
783
return(xsltAddStackElem(ctxt, elems));
784
}
785
786
/************************************************************************
787
* *
788
* Module interfaces *
789
* *
790
************************************************************************/
791
792
/**
793
* xsltEvalVariable:
794
* @ctxt: the XSLT transformation context
795
* @variable: the variable or parameter item
796
* @comp: the compiled XSLT instruction
797
*
798
* Evaluate a variable value.
799
*
800
* Returns the XPath Object value or NULL in case of error
801
*/
802
static xmlXPathObjectPtr
803
xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
804
xsltStylePreCompPtr castedComp)
805
{
806
#ifdef XSLT_REFACTORED
807
xsltStyleItemVariablePtr comp =
808
(xsltStyleItemVariablePtr) castedComp;
809
#else
810
xsltStylePreCompPtr comp = castedComp;
811
#endif
812
xmlXPathObjectPtr result = NULL;
813
xmlNodePtr oldInst;
814
815
if ((ctxt == NULL) || (variable == NULL))
816
return(NULL);
817
818
/*
819
* A variable or parameter are evaluated on demand; thus the
820
* context (of XSLT and XPath) need to be temporarily adjusted and
821
* restored on exit.
822
*/
823
oldInst = ctxt->inst;
824
825
#ifdef WITH_XSLT_DEBUG_VARIABLE
826
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
827
"Evaluating variable '%s'\n", variable->name));
828
#endif
829
if (variable->select != NULL) {
830
xmlXPathCompExprPtr xpExpr = NULL;
831
xmlDocPtr oldXPDoc;
832
xmlNodePtr oldXPContextNode;
833
int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
834
xmlNsPtr *oldXPNamespaces;
835
xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
836
xsltStackElemPtr oldVar = ctxt->contextVariable;
837
838
if ((comp != NULL) && (comp->comp != NULL)) {
839
xpExpr = comp->comp;
840
} else {
841
xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, variable->select);
842
}
843
if (xpExpr == NULL)
844
return(NULL);
845
/*
846
* Save context states.
847
*/
848
oldXPDoc = xpctxt->doc;
849
oldXPContextNode = xpctxt->node;
850
oldXPProximityPosition = xpctxt->proximityPosition;
851
oldXPContextSize = xpctxt->contextSize;
852
oldXPNamespaces = xpctxt->namespaces;
853
oldXPNsNr = xpctxt->nsNr;
854
855
xpctxt->node = ctxt->node;
856
/*
857
* OPTIMIZE TODO: Lame try to set the context doc.
858
* Get rid of this somehow in xpath.c.
859
*/
860
if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
861
ctxt->node->doc)
862
xpctxt->doc = ctxt->node->doc;
863
/*
864
* BUG TODO: The proximity position and the context size will
865
* potentially be wrong.
866
* Example:
867
* <xsl:template select="foo">
868
* <xsl:variable name="pos" select="position()"/>
869
* <xsl:for-each select="bar">
870
* <xsl:value-of select="$pos"/>
871
* </xsl:for-each>
872
* </xsl:template>
873
* Here the proximity position and context size are changed
874
* to the context of <xsl:for-each select="bar">, but
875
* the variable needs to be evaluated in the context of
876
* <xsl:template select="foo">.
877
*/
878
if (comp != NULL) {
879
880
#ifdef XSLT_REFACTORED
881
if (comp->inScopeNs != NULL) {
882
xpctxt->namespaces = comp->inScopeNs->list;
883
xpctxt->nsNr = comp->inScopeNs->xpathNumber;
884
} else {
885
xpctxt->namespaces = NULL;
886
xpctxt->nsNr = 0;
887
}
888
#else
889
xpctxt->namespaces = comp->nsList;
890
xpctxt->nsNr = comp->nsNr;
891
#endif
892
} else {
893
xpctxt->namespaces = NULL;
894
xpctxt->nsNr = 0;
895
}
896
897
/*
898
* We need to mark that we are "selecting" a var's value;
899
* if any tree fragments are created inside the expression,
900
* then those need to be stored inside the variable; otherwise
901
* we'll eventually free still referenced fragments, before
902
* we leave the scope of the variable.
903
*/
904
ctxt->contextVariable = variable;
905
variable->flags |= XSLT_VAR_IN_SELECT;
906
907
result = xmlXPathCompiledEval(xpExpr, xpctxt);
908
909
variable->flags ^= XSLT_VAR_IN_SELECT;
910
/*
911
* Restore Context states.
912
*/
913
ctxt->contextVariable = oldVar;
914
915
xpctxt->doc = oldXPDoc;
916
xpctxt->node = oldXPContextNode;
917
xpctxt->contextSize = oldXPContextSize;
918
xpctxt->proximityPosition = oldXPProximityPosition;
919
xpctxt->namespaces = oldXPNamespaces;
920
xpctxt->nsNr = oldXPNsNr;
921
922
if ((comp == NULL) || (comp->comp == NULL))
923
xmlXPathFreeCompExpr(xpExpr);
924
if (result == NULL) {
925
xsltTransformError(ctxt, NULL,
926
(comp != NULL) ? comp->inst : NULL,
927
"Failed to evaluate the expression of variable '%s'.\n",
928
variable->name);
929
ctxt->state = XSLT_STATE_STOPPED;
930
931
#ifdef WITH_XSLT_DEBUG_VARIABLE
932
#ifdef LIBXML_DEBUG_ENABLED
933
} else {
934
if ((xsltGenericDebugContext == stdout) ||
935
(xsltGenericDebugContext == stderr))
936
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
937
result, 0);
938
#endif
939
#endif
940
}
941
} else {
942
if (variable->tree == NULL) {
943
result = xmlXPathNewCString("");
944
} else {
945
if (variable->tree) {
946
xmlDocPtr container;
947
xmlNodePtr oldInsert;
948
xmlDocPtr oldOutput;
949
const xmlChar *oldLastText;
950
int oldLastTextSize, oldLastTextUse;
951
xsltStackElemPtr oldVar = ctxt->contextVariable;
952
953
/*
954
* Generate a result tree fragment.
955
*/
956
container = xsltCreateRVT(ctxt);
957
if (container == NULL)
958
goto error;
959
/*
960
* NOTE: Local Result Tree Fragments of params/variables
961
* are not registered globally anymore; the life-time
962
* is not directly dependant of the param/variable itself.
963
*
964
* OLD: xsltRegisterTmpRVT(ctxt, container);
965
*/
966
/*
967
* Attach the Result Tree Fragment to the variable;
968
* when the variable is freed, it will also free
969
* the Result Tree Fragment.
970
*/
971
variable->fragment = container;
972
container->compression = XSLT_RVT_LOCAL;
973
974
oldOutput = ctxt->output;
975
oldInsert = ctxt->insert;
976
oldLastText = ctxt->lasttext;
977
oldLastTextSize = ctxt->lasttsize;
978
oldLastTextUse = ctxt->lasttuse;
979
980
ctxt->output = container;
981
ctxt->insert = (xmlNodePtr) container;
982
ctxt->contextVariable = variable;
983
/*
984
* Process the sequence constructor (variable->tree).
985
* The resulting tree will be held by @container.
986
*/
987
xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
988
NULL, NULL);
989
990
ctxt->contextVariable = oldVar;
991
ctxt->insert = oldInsert;
992
ctxt->output = oldOutput;
993
ctxt->lasttext = oldLastText;
994
ctxt->lasttsize = oldLastTextSize;
995
ctxt->lasttuse = oldLastTextUse;
996
997
result = xmlXPathNewValueTree((xmlNodePtr) container);
998
}
999
if (result == NULL) {
1000
result = xmlXPathNewCString("");
1001
} else {
1002
/*
1003
* This stops older libxml2 versions from freeing the nodes
1004
* in the tree.
1005
*/
1006
result->boolval = 0;
1007
}
1008
#ifdef WITH_XSLT_DEBUG_VARIABLE
1009
#ifdef LIBXML_DEBUG_ENABLED
1010
1011
if ((xsltGenericDebugContext == stdout) ||
1012
(xsltGenericDebugContext == stderr))
1013
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1014
result, 0);
1015
#endif
1016
#endif
1017
}
1018
}
1019
1020
error:
1021
ctxt->inst = oldInst;
1022
return(result);
1023
}
1024
1025
/**
1026
* xsltEvalGlobalVariable:
1027
* @elem: the variable or parameter
1028
* @ctxt: the XSLT transformation context
1029
*
1030
* Evaluates a the value of a global xsl:variable or
1031
* xsl:param declaration.
1032
*
1033
* Returns the XPath Object value or NULL in case of error
1034
*/
1035
static xmlXPathObjectPtr
1036
xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
1037
{
1038
xmlXPathObjectPtr result = NULL;
1039
xmlNodePtr oldInst;
1040
const xmlChar* oldVarName;
1041
xsltStackElemPtr oldCtxtVar = ctxt->contextVariable;
1042
1043
#ifdef XSLT_REFACTORED
1044
xsltStyleBasicItemVariablePtr comp;
1045
#else
1046
xsltStylePreCompPtr comp;
1047
#endif
1048
1049
if ((ctxt == NULL) || (elem == NULL))
1050
return(NULL);
1051
if (elem->computed)
1052
return(elem->value);
1053
1054
1055
#ifdef WITH_XSLT_DEBUG_VARIABLE
1056
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1057
"Evaluating global variable %s\n", elem->name));
1058
#endif
1059
1060
#ifdef WITH_DEBUGGER
1061
if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
1062
elem->comp && elem->comp->inst)
1063
xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
1064
#endif
1065
1066
oldInst = ctxt->inst;
1067
#ifdef XSLT_REFACTORED
1068
comp = (xsltStyleBasicItemVariablePtr) elem->comp;
1069
#else
1070
comp = elem->comp;
1071
#endif
1072
oldVarName = elem->name;
1073
elem->name = xsltComputingGlobalVarMarker;
1074
1075
/*
1076
* The "context variable" isn't used for globals, so we must
1077
* make sure to set it to NULL.
1078
*/
1079
oldCtxtVar = ctxt->contextVariable;
1080
ctxt->contextVariable = NULL;
1081
1082
/*
1083
* OPTIMIZE TODO: We should consider instantiating global vars/params
1084
* on-demand. The vars/params don't need to be evaluated if never
1085
* called; and in the case of global params, if values for such params
1086
* are provided by the user.
1087
*/
1088
if (elem->select != NULL) {
1089
xmlXPathCompExprPtr xpExpr = NULL;
1090
xmlDocPtr oldXPDoc;
1091
xmlNodePtr oldXPContextNode;
1092
int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1093
xmlNsPtr *oldXPNamespaces;
1094
xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1095
1096
if ((comp != NULL) && (comp->comp != NULL)) {
1097
xpExpr = comp->comp;
1098
} else {
1099
xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, elem->select);
1100
}
1101
if (xpExpr == NULL)
1102
goto error;
1103
1104
1105
if (comp != NULL)
1106
ctxt->inst = comp->inst;
1107
else
1108
ctxt->inst = NULL;
1109
/*
1110
* SPEC XSLT 1.0:
1111
* "At top-level, the expression or template specifying the
1112
* variable value is evaluated with the same context as that used
1113
* to process the root node of the source document: the current
1114
* node is the root node of the source document and the current
1115
* node list is a list containing just the root node of the source
1116
* document."
1117
*/
1118
/*
1119
* Save context states.
1120
*/
1121
oldXPDoc = xpctxt->doc;
1122
oldXPContextNode = xpctxt->node;
1123
oldXPProximityPosition = xpctxt->proximityPosition;
1124
oldXPContextSize = xpctxt->contextSize;
1125
oldXPNamespaces = xpctxt->namespaces;
1126
oldXPNsNr = xpctxt->nsNr;
1127
1128
xpctxt->node = ctxt->initialContextNode;
1129
xpctxt->doc = ctxt->initialContextDoc;
1130
xpctxt->contextSize = 1;
1131
xpctxt->proximityPosition = 1;
1132
1133
if (comp != NULL) {
1134
1135
#ifdef XSLT_REFACTORED
1136
if (comp->inScopeNs != NULL) {
1137
xpctxt->namespaces = comp->inScopeNs->list;
1138
xpctxt->nsNr = comp->inScopeNs->xpathNumber;
1139
} else {
1140
xpctxt->namespaces = NULL;
1141
xpctxt->nsNr = 0;
1142
}
1143
#else
1144
xpctxt->namespaces = comp->nsList;
1145
xpctxt->nsNr = comp->nsNr;
1146
#endif
1147
} else {
1148
xpctxt->namespaces = NULL;
1149
xpctxt->nsNr = 0;
1150
}
1151
1152
result = xmlXPathCompiledEval(xpExpr, xpctxt);
1153
1154
/*
1155
* Restore Context states.
1156
*/
1157
xpctxt->doc = oldXPDoc;
1158
xpctxt->node = oldXPContextNode;
1159
xpctxt->contextSize = oldXPContextSize;
1160
xpctxt->proximityPosition = oldXPProximityPosition;
1161
xpctxt->namespaces = oldXPNamespaces;
1162
xpctxt->nsNr = oldXPNsNr;
1163
1164
if ((comp == NULL) || (comp->comp == NULL))
1165
xmlXPathFreeCompExpr(xpExpr);
1166
if (result == NULL) {
1167
if (comp == NULL)
1168
xsltTransformError(ctxt, NULL, NULL,
1169
"Evaluating global variable %s failed\n", elem->name);
1170
else
1171
xsltTransformError(ctxt, NULL, comp->inst,
1172
"Evaluating global variable %s failed\n", elem->name);
1173
ctxt->state = XSLT_STATE_STOPPED;
1174
goto error;
1175
}
1176
1177
/*
1178
* Mark all RVTs that are referenced from result as part
1179
* of this variable so they won't be freed too early.
1180
*/
1181
xsltFlagRVTs(ctxt, result, XSLT_RVT_GLOBAL);
1182
1183
#ifdef WITH_XSLT_DEBUG_VARIABLE
1184
#ifdef LIBXML_DEBUG_ENABLED
1185
if ((xsltGenericDebugContext == stdout) ||
1186
(xsltGenericDebugContext == stderr))
1187
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1188
result, 0);
1189
#endif
1190
#endif
1191
} else {
1192
if (elem->tree == NULL) {
1193
result = xmlXPathNewCString("");
1194
} else {
1195
xmlDocPtr container;
1196
xmlNodePtr oldInsert;
1197
xmlDocPtr oldOutput, oldXPDoc;
1198
/*
1199
* Generate a result tree fragment.
1200
*/
1201
container = xsltCreateRVT(ctxt);
1202
if (container == NULL)
1203
goto error;
1204
/*
1205
* Let the lifetime of the tree fragment be handled by
1206
* the Libxslt's garbage collector.
1207
*/
1208
xsltRegisterPersistRVT(ctxt, container);
1209
1210
oldOutput = ctxt->output;
1211
oldInsert = ctxt->insert;
1212
1213
oldXPDoc = ctxt->xpathCtxt->doc;
1214
1215
ctxt->output = container;
1216
ctxt->insert = (xmlNodePtr) container;
1217
1218
ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
1219
/*
1220
* Process the sequence constructor.
1221
*/
1222
xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
1223
1224
ctxt->xpathCtxt->doc = oldXPDoc;
1225
1226
ctxt->insert = oldInsert;
1227
ctxt->output = oldOutput;
1228
1229
result = xmlXPathNewValueTree((xmlNodePtr) container);
1230
if (result == NULL) {
1231
result = xmlXPathNewCString("");
1232
} else {
1233
/*
1234
* This stops older libxml2 versions from freeing the nodes
1235
* in the tree.
1236
*/
1237
result->boolval = 0;
1238
}
1239
#ifdef WITH_XSLT_DEBUG_VARIABLE
1240
#ifdef LIBXML_DEBUG_ENABLED
1241
if ((xsltGenericDebugContext == stdout) ||
1242
(xsltGenericDebugContext == stderr))
1243
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1244
result, 0);
1245
#endif
1246
#endif
1247
}
1248
}
1249
1250
error:
1251
ctxt->contextVariable = oldCtxtVar;
1252
1253
elem->name = oldVarName;
1254
ctxt->inst = oldInst;
1255
if (result != NULL) {
1256
elem->value = result;
1257
elem->computed = 1;
1258
}
1259
return(result);
1260
}
1261
1262
/**
1263
* xsltEvalGlobalVariables:
1264
* @ctxt: the XSLT transformation context
1265
*
1266
* Evaluates all global variables and parameters of a stylesheet.
1267
* For internal use only. This is called at start of a transformation.
1268
*
1269
* Returns 0 in case of success, -1 in case of error
1270
*/
1271
int
1272
xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
1273
xsltStackElemPtr elem;
1274
xsltStackElemPtr head = NULL;
1275
xsltStylesheetPtr style;
1276
1277
if ((ctxt == NULL) || (ctxt->document == NULL))
1278
return(-1);
1279
1280
#ifdef WITH_XSLT_DEBUG_VARIABLE
1281
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1282
"Registering global variables\n"));
1283
#endif
1284
/*
1285
* Walk the list from the stylesheets and populate the hash table
1286
*/
1287
style = ctxt->style;
1288
while (style != NULL) {
1289
elem = style->variables;
1290
1291
#ifdef WITH_XSLT_DEBUG_VARIABLE
1292
if ((style->doc != NULL) && (style->doc->URL != NULL)) {
1293
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1294
"Registering global variables from %s\n",
1295
style->doc->URL));
1296
}
1297
#endif
1298
1299
while (elem != NULL) {
1300
xsltStackElemPtr def;
1301
1302
/*
1303
* Global variables are stored in the variables pool.
1304
*/
1305
def = (xsltStackElemPtr)
1306
xmlHashLookup2(ctxt->globalVars,
1307
elem->name, elem->nameURI);
1308
if (def == NULL) {
1309
1310
def = xsltCopyStackElem(elem);
1311
if (xmlHashAddEntry2(ctxt->globalVars,
1312
elem->name, elem->nameURI, def) < 0) {
1313
xmlGenericError(xmlGenericErrorContext,
1314
"hash update failed\n");
1315
xsltFreeStackElem(def);
1316
return(-1);
1317
}
1318
def->next = head;
1319
head = def;
1320
} else if ((elem->comp != NULL) &&
1321
(elem->comp->type == XSLT_FUNC_VARIABLE)) {
1322
/*
1323
* Redefinition of variables from a different stylesheet
1324
* should not generate a message.
1325
*/
1326
if ((elem->comp->inst != NULL) &&
1327
(def->comp != NULL) && (def->comp->inst != NULL) &&
1328
(elem->comp->inst->doc == def->comp->inst->doc))
1329
{
1330
xsltTransformError(ctxt, style, elem->comp->inst,
1331
"Global variable %s already defined\n", elem->name);
1332
if (style != NULL) style->errors++;
1333
}
1334
}
1335
elem = elem->next;
1336
}
1337
1338
style = xsltNextImport(style);
1339
}
1340
1341
/*
1342
* This part does the actual evaluation. Note that scanning the hash
1343
* table would result in a non-deterministic order, leading to
1344
* non-deterministic generated IDs.
1345
*/
1346
elem = head;
1347
while (elem != NULL) {
1348
xsltStackElemPtr next;
1349
1350
xsltEvalGlobalVariable(elem, ctxt);
1351
next = elem->next;
1352
elem->next = NULL;
1353
elem = next;
1354
}
1355
1356
return(0);
1357
}
1358
1359
/**
1360
* xsltRegisterGlobalVariable:
1361
* @style: the XSLT transformation context
1362
* @name: the variable name
1363
* @ns_uri: the variable namespace URI
1364
* @sel: the expression which need to be evaluated to generate a value
1365
* @tree: the subtree if sel is NULL
1366
* @comp: the precompiled value
1367
* @value: the string value if available
1368
*
1369
* Register a new variable value. If @value is NULL it unregisters
1370
* the variable
1371
*
1372
* Returns 0 in case of success, -1 in case of error
1373
*/
1374
static int
1375
xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
1376
const xmlChar *ns_uri, const xmlChar *sel,
1377
xmlNodePtr tree, xsltStylePreCompPtr comp,
1378
const xmlChar *value) {
1379
xsltStackElemPtr elem, tmp;
1380
if (style == NULL)
1381
return(-1);
1382
if (name == NULL)
1383
return(-1);
1384
if (comp == NULL)
1385
return(-1);
1386
1387
#ifdef WITH_XSLT_DEBUG_VARIABLE
1388
if (comp->type == XSLT_FUNC_PARAM)
1389
xsltGenericDebug(xsltGenericDebugContext,
1390
"Defining global param %s\n", name);
1391
else
1392
xsltGenericDebug(xsltGenericDebugContext,
1393
"Defining global variable %s\n", name);
1394
#endif
1395
1396
elem = xsltNewStackElem(NULL);
1397
if (elem == NULL)
1398
return(-1);
1399
elem->comp = comp;
1400
elem->name = xmlDictLookup(style->dict, name, -1);
1401
elem->select = xmlDictLookup(style->dict, sel, -1);
1402
if (ns_uri)
1403
elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
1404
elem->tree = tree;
1405
tmp = style->variables;
1406
while (tmp != NULL) {
1407
if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
1408
(tmp->comp->type == XSLT_FUNC_VARIABLE) &&
1409
(xmlStrEqual(elem->name, tmp->name)) &&
1410
((elem->nameURI == tmp->nameURI) ||
1411
(xmlStrEqual(elem->nameURI, tmp->nameURI))))
1412
{
1413
xsltTransformError(NULL, style, comp->inst,
1414
"redefinition of global variable %s\n", elem->name);
1415
style->errors++;
1416
}
1417
tmp = tmp->next;
1418
}
1419
elem->next = style->variables;
1420
style->variables = elem;
1421
if (value != NULL) {
1422
elem->computed = 1;
1423
elem->value = xmlXPathNewString(value);
1424
}
1425
return(0);
1426
}
1427
1428
/**
1429
* xsltProcessUserParamInternal
1430
*
1431
* @ctxt: the XSLT transformation context
1432
* @name: a null terminated parameter name
1433
* @value: a null terminated value (may be an XPath expression)
1434
* @eval: 0 to treat the value literally, else evaluate as XPath expression
1435
*
1436
* If @eval is 0 then @value is treated literally and is stored in the global
1437
* parameter/variable table without any change.
1438
*
1439
* Uf @eval is 1 then @value is treated as an XPath expression and is
1440
* evaluated. In this case, if you want to pass a string which will be
1441
* interpreted literally then it must be enclosed in single or double quotes.
1442
* If the string contains single quotes (double quotes) then it cannot be
1443
* enclosed single quotes (double quotes). If the string which you want to
1444
* be treated literally contains both single and double quotes (e.g. Meet
1445
* at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1446
* quoting character. You cannot use &apos; or &quot; inside the string
1447
* because the replacement of character entities with their equivalents is
1448
* done at a different stage of processing. The solution is to call
1449
* xsltQuoteUserParams or xsltQuoteOneUserParam.
1450
*
1451
* This needs to be done on parsed stylesheets before starting to apply
1452
* transformations. Normally this will be called (directly or indirectly)
1453
* only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1454
* or xsltQuoteOneUserParam.
1455
*
1456
* Returns 0 in case of success, -1 in case of error
1457
*/
1458
1459
static
1460
int
1461
xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
1462
const xmlChar * name,
1463
const xmlChar * value,
1464
int eval) {
1465
1466
xsltStylesheetPtr style;
1467
const xmlChar *prefix;
1468
const xmlChar *href;
1469
xmlXPathCompExprPtr xpExpr;
1470
xmlXPathObjectPtr result;
1471
1472
xsltStackElemPtr elem;
1473
int res;
1474
void *res_ptr;
1475
1476
if (ctxt == NULL)
1477
return(-1);
1478
if (name == NULL)
1479
return(0);
1480
if (value == NULL)
1481
return(0);
1482
1483
style = ctxt->style;
1484
1485
#ifdef WITH_XSLT_DEBUG_VARIABLE
1486
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1487
"Evaluating user parameter %s=%s\n", name, value));
1488
#endif
1489
1490
/*
1491
* Name lookup
1492
*/
1493
href = NULL;
1494
1495
if (name[0] == '{') {
1496
int len = 0;
1497
1498
while ((name[len] != 0) && (name[len] != '}')) len++;
1499
if (name[len] == 0) {
1500
xsltTransformError(ctxt, style, NULL,
1501
"user param : malformed parameter name : %s\n", name);
1502
} else {
1503
href = xmlDictLookup(ctxt->dict, &name[1], len-1);
1504
name = xmlDictLookup(ctxt->dict, &name[len + 1], -1);
1505
}
1506
}
1507
else {
1508
name = xsltSplitQName(ctxt->dict, name, &prefix);
1509
if (prefix != NULL) {
1510
xmlNsPtr ns;
1511
1512
ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
1513
prefix);
1514
if (ns == NULL) {
1515
xsltTransformError(ctxt, style, NULL,
1516
"user param : no namespace bound to prefix %s\n", prefix);
1517
href = NULL;
1518
} else {
1519
href = ns->href;
1520
}
1521
}
1522
}
1523
1524
if (name == NULL)
1525
return (-1);
1526
1527
res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
1528
if (res_ptr != 0) {
1529
xsltTransformError(ctxt, style, NULL,
1530
"Global parameter %s already defined\n", name);
1531
}
1532
if (ctxt->globalVars == NULL)
1533
ctxt->globalVars = xmlHashCreate(20);
1534
1535
/*
1536
* do not overwrite variables with parameters from the command line
1537
*/
1538
while (style != NULL) {
1539
elem = ctxt->style->variables;
1540
while (elem != NULL) {
1541
if ((elem->comp != NULL) &&
1542
(elem->comp->type == XSLT_FUNC_VARIABLE) &&
1543
(xmlStrEqual(elem->name, name)) &&
1544
(xmlStrEqual(elem->nameURI, href))) {
1545
return(0);
1546
}
1547
elem = elem->next;
1548
}
1549
style = xsltNextImport(style);
1550
}
1551
style = ctxt->style;
1552
elem = NULL;
1553
1554
/*
1555
* Do the evaluation if @eval is non-zero.
1556
*/
1557
1558
result = NULL;
1559
if (eval != 0) {
1560
xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, value);
1561
if (xpExpr != NULL) {
1562
xmlDocPtr oldXPDoc;
1563
xmlNodePtr oldXPContextNode;
1564
int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1565
xmlNsPtr *oldXPNamespaces;
1566
xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1567
1568
/*
1569
* Save context states.
1570
*/
1571
oldXPDoc = xpctxt->doc;
1572
oldXPContextNode = xpctxt->node;
1573
oldXPProximityPosition = xpctxt->proximityPosition;
1574
oldXPContextSize = xpctxt->contextSize;
1575
oldXPNamespaces = xpctxt->namespaces;
1576
oldXPNsNr = xpctxt->nsNr;
1577
1578
/*
1579
* SPEC XSLT 1.0:
1580
* "At top-level, the expression or template specifying the
1581
* variable value is evaluated with the same context as that used
1582
* to process the root node of the source document: the current
1583
* node is the root node of the source document and the current
1584
* node list is a list containing just the root node of the source
1585
* document."
1586
*/
1587
xpctxt->doc = ctxt->initialContextDoc;
1588
xpctxt->node = ctxt->initialContextNode;
1589
xpctxt->contextSize = 1;
1590
xpctxt->proximityPosition = 1;
1591
/*
1592
* There is really no in scope namespace for parameters on the
1593
* command line.
1594
*/
1595
xpctxt->namespaces = NULL;
1596
xpctxt->nsNr = 0;
1597
1598
result = xmlXPathCompiledEval(xpExpr, xpctxt);
1599
1600
/*
1601
* Restore Context states.
1602
*/
1603
xpctxt->doc = oldXPDoc;
1604
xpctxt->node = oldXPContextNode;
1605
xpctxt->contextSize = oldXPContextSize;
1606
xpctxt->proximityPosition = oldXPProximityPosition;
1607
xpctxt->namespaces = oldXPNamespaces;
1608
xpctxt->nsNr = oldXPNsNr;
1609
1610
xmlXPathFreeCompExpr(xpExpr);
1611
}
1612
if (result == NULL) {
1613
xsltTransformError(ctxt, style, NULL,
1614
"Evaluating user parameter %s failed\n", name);
1615
ctxt->state = XSLT_STATE_STOPPED;
1616
return(-1);
1617
}
1618
}
1619
1620
/*
1621
* If @eval is 0 then @value is to be taken literally and result is NULL
1622
*
1623
* If @eval is not 0, then @value is an XPath expression and has been
1624
* successfully evaluated and result contains the resulting value and
1625
* is not NULL.
1626
*
1627
* Now create an xsltStackElemPtr for insertion into the context's
1628
* global variable/parameter hash table.
1629
*/
1630
1631
#ifdef WITH_XSLT_DEBUG_VARIABLE
1632
#ifdef LIBXML_DEBUG_ENABLED
1633
if ((xsltGenericDebugContext == stdout) ||
1634
(xsltGenericDebugContext == stderr))
1635
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1636
result, 0);
1637
#endif
1638
#endif
1639
1640
elem = xsltNewStackElem(NULL);
1641
if (elem != NULL) {
1642
elem->name = name;
1643
elem->select = xmlDictLookup(ctxt->dict, value, -1);
1644
if (href != NULL)
1645
elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
1646
elem->tree = NULL;
1647
elem->computed = 1;
1648
if (eval == 0) {
1649
elem->value = xmlXPathNewString(value);
1650
}
1651
else {
1652
elem->value = result;
1653
}
1654
}
1655
1656
/*
1657
* Global parameters are stored in the XPath context variables pool.
1658
*/
1659
1660
res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
1661
if (res != 0) {
1662
xsltFreeStackElem(elem);
1663
xsltTransformError(ctxt, style, NULL,
1664
"Global parameter %s already defined\n", name);
1665
}
1666
return(0);
1667
}
1668
1669
/**
1670
* xsltEvalUserParams:
1671
*
1672
* @ctxt: the XSLT transformation context
1673
* @params: a NULL terminated array of parameters name/value tuples
1674
*
1675
* Evaluate the global variables of a stylesheet. This needs to be
1676
* done on parsed stylesheets before starting to apply transformations.
1677
* Each of the parameters is evaluated as an XPath expression and stored
1678
* in the global variables/parameter hash table. If you want your
1679
* parameter used literally, use xsltQuoteUserParams.
1680
*
1681
* Returns 0 in case of success, -1 in case of error
1682
*/
1683
1684
int
1685
xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1686
size_t indx = 0;
1687
const xmlChar *name;
1688
const xmlChar *value;
1689
1690
if (params == NULL)
1691
return(0);
1692
while (params[indx] != NULL) {
1693
name = (const xmlChar *) params[indx++];
1694
value = (const xmlChar *) params[indx++];
1695
if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1696
return(-1);
1697
}
1698
return 0;
1699
}
1700
1701
/**
1702
* xsltQuoteUserParams:
1703
*
1704
* @ctxt: the XSLT transformation context
1705
* @params: a NULL terminated arry of parameters names/values tuples
1706
*
1707
* Similar to xsltEvalUserParams, but the values are treated literally and
1708
* are * *not* evaluated as XPath expressions. This should be done on parsed
1709
* stylesheets before starting to apply transformations.
1710
*
1711
* Returns 0 in case of success, -1 in case of error.
1712
*/
1713
1714
int
1715
xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1716
size_t indx = 0;
1717
const xmlChar *name;
1718
const xmlChar *value;
1719
1720
if (params == NULL)
1721
return(0);
1722
while (params[indx] != NULL) {
1723
name = (const xmlChar *) params[indx++];
1724
value = (const xmlChar *) params[indx++];
1725
if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1726
return(-1);
1727
}
1728
return 0;
1729
}
1730
1731
/**
1732
* xsltEvalOneUserParam:
1733
* @ctxt: the XSLT transformation context
1734
* @name: a null terminated string giving the name of the parameter
1735
* @value: a null terminated string giving the XPath expression to be evaluated
1736
*
1737
* This is normally called from xsltEvalUserParams to process a single
1738
* parameter from a list of parameters. The @value is evaluated as an
1739
* XPath expression and the result is stored in the context's global
1740
* variable/parameter hash table.
1741
*
1742
* To have a parameter treated literally (not as an XPath expression)
1743
* use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
1744
* details see description of xsltProcessOneUserParamInternal.
1745
*
1746
* Returns 0 in case of success, -1 in case of error.
1747
*/
1748
1749
int
1750
xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1751
const xmlChar * name,
1752
const xmlChar * value) {
1753
return xsltProcessUserParamInternal(ctxt, name, value,
1754
1 /* xpath eval ? */);
1755
}
1756
1757
/**
1758
* xsltQuoteOneUserParam:
1759
* @ctxt: the XSLT transformation context
1760
* @name: a null terminated string giving the name of the parameter
1761
* @value: a null terminated string giving the parameter value
1762
*
1763
* This is normally called from xsltQuoteUserParams to process a single
1764
* parameter from a list of parameters. The @value is stored in the
1765
* context's global variable/parameter hash table.
1766
*
1767
* Returns 0 in case of success, -1 in case of error.
1768
*/
1769
1770
int
1771
xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1772
const xmlChar * name,
1773
const xmlChar * value) {
1774
return xsltProcessUserParamInternal(ctxt, name, value,
1775
0 /* xpath eval ? */);
1776
}
1777
1778
/**
1779
* xsltBuildVariable:
1780
* @ctxt: the XSLT transformation context
1781
* @comp: the precompiled form
1782
* @tree: the tree if select is NULL
1783
*
1784
* Computes a new variable value.
1785
*
1786
* Returns the xsltStackElemPtr or NULL in case of error
1787
*/
1788
static xsltStackElemPtr
1789
xsltBuildVariable(xsltTransformContextPtr ctxt,
1790
xsltStylePreCompPtr castedComp,
1791
xmlNodePtr tree)
1792
{
1793
#ifdef XSLT_REFACTORED
1794
xsltStyleBasicItemVariablePtr comp =
1795
(xsltStyleBasicItemVariablePtr) castedComp;
1796
#else
1797
xsltStylePreCompPtr comp = castedComp;
1798
#endif
1799
xsltStackElemPtr elem;
1800
1801
#ifdef WITH_XSLT_DEBUG_VARIABLE
1802
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1803
"Building variable %s", comp->name));
1804
if (comp->select != NULL)
1805
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1806
" select %s", comp->select));
1807
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
1808
#endif
1809
1810
elem = xsltNewStackElem(ctxt);
1811
if (elem == NULL)
1812
return(NULL);
1813
elem->comp = (xsltStylePreCompPtr) comp;
1814
elem->name = comp->name;
1815
elem->select = comp->select;
1816
elem->nameURI = comp->ns;
1817
elem->tree = tree;
1818
elem->value = xsltEvalVariable(ctxt, elem,
1819
(xsltStylePreCompPtr) comp);
1820
elem->computed = 1;
1821
return(elem);
1822
}
1823
1824
/**
1825
* xsltRegisterVariable:
1826
* @ctxt: the XSLT transformation context
1827
* @comp: the compiled XSLT-variable (or param) instruction
1828
* @tree: the tree if select is NULL
1829
* @isParam: indicates if this is a parameter
1830
*
1831
* Computes and registers a new variable.
1832
*
1833
* Returns 0 in case of success, -1 in case of error
1834
*/
1835
static int
1836
xsltRegisterVariable(xsltTransformContextPtr ctxt,
1837
xsltStylePreCompPtr castedComp,
1838
xmlNodePtr tree, int isParam)
1839
{
1840
#ifdef XSLT_REFACTORED
1841
xsltStyleBasicItemVariablePtr comp =
1842
(xsltStyleBasicItemVariablePtr) castedComp;
1843
#else
1844
xsltStylePreCompPtr comp = castedComp;
1845
int present;
1846
#endif
1847
xsltStackElemPtr variable;
1848
1849
#ifdef XSLT_REFACTORED
1850
/*
1851
* REFACTORED NOTE: Redefinitions of vars/params are checked
1852
* at compilation time in the refactored code.
1853
* xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1854
*/
1855
#else
1856
present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1857
if (isParam == 0) {
1858
if ((present != 0) && (present != 3)) {
1859
/* TODO: report QName. */
1860
xsltTransformError(ctxt, NULL, comp->inst,
1861
"XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
1862
return(0);
1863
}
1864
} else if (present != 0) {
1865
if ((present == 1) || (present == 2)) {
1866
/* TODO: report QName. */
1867
xsltTransformError(ctxt, NULL, comp->inst,
1868
"XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
1869
return(0);
1870
}
1871
#ifdef WITH_XSLT_DEBUG_VARIABLE
1872
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1873
"param %s defined by caller\n", comp->name));
1874
#endif
1875
return(0);
1876
}
1877
#endif /* else of XSLT_REFACTORED */
1878
1879
variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1880
if (xsltAddStackElem(ctxt, variable) < 0) {
1881
xsltFreeStackElem(variable);
1882
return(-1);
1883
}
1884
return(0);
1885
}
1886
1887
/**
1888
* xsltGlobalVariableLookup:
1889
* @ctxt: the XSLT transformation context
1890
* @name: the variable name
1891
* @ns_uri: the variable namespace URI
1892
*
1893
* Search in the Variable array of the context for the given
1894
* variable value.
1895
*
1896
* Returns the value or NULL if not found
1897
*/
1898
static xmlXPathObjectPtr
1899
xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1900
const xmlChar *ns_uri) {
1901
xsltStackElemPtr elem;
1902
xmlXPathObjectPtr ret = NULL;
1903
1904
/*
1905
* Lookup the global variables in XPath global variable hash table
1906
*/
1907
if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1908
return(NULL);
1909
elem = (xsltStackElemPtr)
1910
xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1911
if (elem == NULL) {
1912
#ifdef WITH_XSLT_DEBUG_VARIABLE
1913
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1914
"global variable not found %s\n", name));
1915
#endif
1916
return(NULL);
1917
}
1918
/*
1919
* URGENT TODO: Move the detection of recursive definitions
1920
* to compile-time.
1921
*/
1922
if (elem->computed == 0) {
1923
if (elem->name == xsltComputingGlobalVarMarker) {
1924
xsltTransformError(ctxt, NULL, elem->comp->inst,
1925
"Recursive definition of %s\n", name);
1926
return(NULL);
1927
}
1928
ret = xsltEvalGlobalVariable(elem, ctxt);
1929
} else
1930
ret = elem->value;
1931
return(xmlXPathObjectCopy(ret));
1932
}
1933
1934
/**
1935
* xsltVariableLookup:
1936
* @ctxt: the XSLT transformation context
1937
* @name: the variable name
1938
* @ns_uri: the variable namespace URI
1939
*
1940
* Search in the Variable array of the context for the given
1941
* variable value.
1942
*
1943
* Returns the value or NULL if not found
1944
*/
1945
xmlXPathObjectPtr
1946
xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1947
const xmlChar *ns_uri) {
1948
xsltStackElemPtr elem;
1949
1950
if (ctxt == NULL)
1951
return(NULL);
1952
1953
elem = xsltStackLookup(ctxt, name, ns_uri);
1954
if (elem == NULL) {
1955
return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1956
}
1957
if (elem->computed == 0) {
1958
#ifdef WITH_XSLT_DEBUG_VARIABLE
1959
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1960
"uncomputed variable %s\n", name));
1961
#endif
1962
elem->value = xsltEvalVariable(ctxt, elem, NULL);
1963
elem->computed = 1;
1964
}
1965
if (elem->value != NULL)
1966
return(xmlXPathObjectCopy(elem->value));
1967
#ifdef WITH_XSLT_DEBUG_VARIABLE
1968
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1969
"variable not found %s\n", name));
1970
#endif
1971
return(NULL);
1972
}
1973
1974
/**
1975
* xsltParseStylesheetCallerParam:
1976
* @ctxt: the XSLT transformation context
1977
* @inst: the xsl:with-param instruction element
1978
*
1979
* Processes an xsl:with-param instruction at transformation time.
1980
* The value is computed, but not recorded.
1981
* NOTE that this is also called with an *xsl:param* element
1982
* from exsltFuncFunctionFunction().
1983
*
1984
* Returns the new xsltStackElemPtr or NULL
1985
*/
1986
1987
xsltStackElemPtr
1988
xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
1989
{
1990
#ifdef XSLT_REFACTORED
1991
xsltStyleBasicItemVariablePtr comp;
1992
#else
1993
xsltStylePreCompPtr comp;
1994
#endif
1995
xmlNodePtr tree = NULL; /* The first child node of the instruction or
1996
the instruction itself. */
1997
xsltStackElemPtr param = NULL;
1998
1999
if ((ctxt == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
2000
return(NULL);
2001
2002
#ifdef XSLT_REFACTORED
2003
comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
2004
#else
2005
comp = (xsltStylePreCompPtr) inst->psvi;
2006
#endif
2007
2008
if (comp == NULL) {
2009
xsltTransformError(ctxt, NULL, inst,
2010
"Internal error in xsltParseStylesheetCallerParam(): "
2011
"The XSLT 'with-param' instruction was not compiled.\n");
2012
return(NULL);
2013
}
2014
if (comp->name == NULL) {
2015
xsltTransformError(ctxt, NULL, inst,
2016
"Internal error in xsltParseStylesheetCallerParam(): "
2017
"XSLT 'with-param': The attribute 'name' was not compiled.\n");
2018
return(NULL);
2019
}
2020
2021
#ifdef WITH_XSLT_DEBUG_VARIABLE
2022
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2023
"Handling xsl:with-param %s\n", comp->name));
2024
#endif
2025
2026
if (comp->select == NULL) {
2027
tree = inst->children;
2028
} else {
2029
#ifdef WITH_XSLT_DEBUG_VARIABLE
2030
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2031
" select %s\n", comp->select));
2032
#endif
2033
tree = inst;
2034
}
2035
2036
param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
2037
2038
return(param);
2039
}
2040
2041
/**
2042
* xsltParseGlobalVariable:
2043
* @style: the XSLT stylesheet
2044
* @cur: the "variable" element
2045
*
2046
* Parses a global XSLT 'variable' declaration at compilation time
2047
* and registers it
2048
*/
2049
void
2050
xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
2051
{
2052
#ifdef XSLT_REFACTORED
2053
xsltStyleItemVariablePtr comp;
2054
#else
2055
xsltStylePreCompPtr comp;
2056
#endif
2057
2058
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
2059
return;
2060
2061
#ifdef XSLT_REFACTORED
2062
/*
2063
* Note that xsltStylePreCompute() will be called from
2064
* xslt.c only.
2065
*/
2066
comp = (xsltStyleItemVariablePtr) cur->psvi;
2067
#else
2068
xsltStylePreCompute(style, cur);
2069
comp = (xsltStylePreCompPtr) cur->psvi;
2070
#endif
2071
if (comp == NULL) {
2072
xsltTransformError(NULL, style, cur,
2073
"xsl:variable : compilation failed\n");
2074
return;
2075
}
2076
2077
if (comp->name == NULL) {
2078
xsltTransformError(NULL, style, cur,
2079
"xsl:variable : missing name attribute\n");
2080
return;
2081
}
2082
2083
/*
2084
* Parse the content (a sequence constructor) of xsl:variable.
2085
*/
2086
if (cur->children != NULL) {
2087
#ifdef XSLT_REFACTORED
2088
xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2089
#else
2090
xsltParseTemplateContent(style, cur);
2091
#endif
2092
}
2093
#ifdef WITH_XSLT_DEBUG_VARIABLE
2094
xsltGenericDebug(xsltGenericDebugContext,
2095
"Registering global variable %s\n", comp->name);
2096
#endif
2097
2098
xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2099
comp->select, cur->children, (xsltStylePreCompPtr) comp,
2100
NULL);
2101
}
2102
2103
/**
2104
* xsltParseGlobalParam:
2105
* @style: the XSLT stylesheet
2106
* @cur: the "param" element
2107
*
2108
* parse an XSLT transformation param declaration and record
2109
* its value.
2110
*/
2111
2112
void
2113
xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
2114
#ifdef XSLT_REFACTORED
2115
xsltStyleItemParamPtr comp;
2116
#else
2117
xsltStylePreCompPtr comp;
2118
#endif
2119
2120
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
2121
return;
2122
2123
#ifdef XSLT_REFACTORED
2124
/*
2125
* Note that xsltStylePreCompute() will be called from
2126
* xslt.c only.
2127
*/
2128
comp = (xsltStyleItemParamPtr) cur->psvi;
2129
#else
2130
xsltStylePreCompute(style, cur);
2131
comp = (xsltStylePreCompPtr) cur->psvi;
2132
#endif
2133
if (comp == NULL) {
2134
xsltTransformError(NULL, style, cur,
2135
"xsl:param : compilation failed\n");
2136
return;
2137
}
2138
2139
if (comp->name == NULL) {
2140
xsltTransformError(NULL, style, cur,
2141
"xsl:param : missing name attribute\n");
2142
return;
2143
}
2144
2145
/*
2146
* Parse the content (a sequence constructor) of xsl:param.
2147
*/
2148
if (cur->children != NULL) {
2149
#ifdef XSLT_REFACTORED
2150
xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2151
#else
2152
xsltParseTemplateContent(style, cur);
2153
#endif
2154
}
2155
2156
#ifdef WITH_XSLT_DEBUG_VARIABLE
2157
xsltGenericDebug(xsltGenericDebugContext,
2158
"Registering global param %s\n", comp->name);
2159
#endif
2160
2161
xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2162
comp->select, cur->children, (xsltStylePreCompPtr) comp,
2163
NULL);
2164
}
2165
2166
/**
2167
* xsltParseStylesheetVariable:
2168
* @ctxt: the XSLT transformation context
2169
* @inst: the xsl:variable instruction element
2170
*
2171
* Registers a local XSLT 'variable' instruction at transformation time
2172
* and evaluates its value.
2173
*/
2174
void
2175
xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
2176
{
2177
#ifdef XSLT_REFACTORED
2178
xsltStyleItemVariablePtr comp;
2179
#else
2180
xsltStylePreCompPtr comp;
2181
#endif
2182
2183
if ((inst == NULL) || (ctxt == NULL) || (inst->type != XML_ELEMENT_NODE))
2184
return;
2185
2186
comp = inst->psvi;
2187
if (comp == NULL) {
2188
xsltTransformError(ctxt, NULL, inst,
2189
"Internal error in xsltParseStylesheetVariable(): "
2190
"The XSLT 'variable' instruction was not compiled.\n");
2191
return;
2192
}
2193
if (comp->name == NULL) {
2194
xsltTransformError(ctxt, NULL, inst,
2195
"Internal error in xsltParseStylesheetVariable(): "
2196
"The attribute 'name' was not compiled.\n");
2197
return;
2198
}
2199
2200
#ifdef WITH_XSLT_DEBUG_VARIABLE
2201
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2202
"Registering variable '%s'\n", comp->name));
2203
#endif
2204
2205
xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
2206
}
2207
2208
/**
2209
* xsltParseStylesheetParam:
2210
* @ctxt: the XSLT transformation context
2211
* @cur: the XSLT 'param' element
2212
*
2213
* Registers a local XSLT 'param' declaration at transformation time and
2214
* evaluates its value.
2215
*/
2216
void
2217
xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
2218
{
2219
#ifdef XSLT_REFACTORED
2220
xsltStyleItemParamPtr comp;
2221
#else
2222
xsltStylePreCompPtr comp;
2223
#endif
2224
2225
if ((cur == NULL) || (ctxt == NULL) || (cur->type != XML_ELEMENT_NODE))
2226
return;
2227
2228
comp = cur->psvi;
2229
if ((comp == NULL) || (comp->name == NULL)) {
2230
xsltTransformError(ctxt, NULL, cur,
2231
"Internal error in xsltParseStylesheetParam(): "
2232
"The XSLT 'param' declaration was not compiled correctly.\n");
2233
return;
2234
}
2235
2236
#ifdef WITH_XSLT_DEBUG_VARIABLE
2237
XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2238
"Registering param %s\n", comp->name));
2239
#endif
2240
2241
xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
2242
}
2243
2244
/**
2245
* xsltFreeGlobalVariables:
2246
* @ctxt: the XSLT transformation context
2247
*
2248
* Free up the data associated to the global variables
2249
* its value.
2250
*/
2251
2252
void
2253
xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
2254
xmlHashFree(ctxt->globalVars, xsltFreeStackElemEntry);
2255
}
2256
2257
/**
2258
* xsltXPathVariableLookup:
2259
* @ctxt: a void * but the the XSLT transformation context actually
2260
* @name: the variable name
2261
* @ns_uri: the variable namespace URI
2262
*
2263
* This is the entry point when a varibale is needed by the XPath
2264
* interpretor.
2265
*
2266
* Returns the value or NULL if not found
2267
*/
2268
xmlXPathObjectPtr
2269
xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
2270
const xmlChar *ns_uri) {
2271
xsltTransformContextPtr tctxt;
2272
xmlXPathObjectPtr valueObj = NULL;
2273
2274
if ((ctxt == NULL) || (name == NULL))
2275
return(NULL);
2276
2277
#ifdef WITH_XSLT_DEBUG_VARIABLE
2278
XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2279
"Lookup variable '%s'\n", name));
2280
#endif
2281
2282
tctxt = (xsltTransformContextPtr) ctxt;
2283
/*
2284
* Local variables/params ---------------------------------------------
2285
*
2286
* Do the lookup from the top of the stack, but
2287
* don't use params being computed in a call-param
2288
* First lookup expects the variable name and URI to
2289
* come from the disctionnary and hence pointer comparison.
2290
*/
2291
if (tctxt->varsNr != 0) {
2292
int i;
2293
xsltStackElemPtr variable = NULL, cur;
2294
2295
for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2296
cur = tctxt->varsTab[i-1];
2297
if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2298
variable = cur;
2299
goto local_variable_found;
2300
}
2301
cur = cur->next;
2302
}
2303
/*
2304
* Redo the lookup with interned strings to avoid string comparison.
2305
*
2306
* OPTIMIZE TODO: The problem here is, that if we request a
2307
* global variable, then this will be also executed.
2308
*/
2309
{
2310
const xmlChar *tmpName = name, *tmpNsName = ns_uri;
2311
2312
name = xmlDictLookup(tctxt->dict, name, -1);
2313
if (ns_uri)
2314
ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
2315
if ((tmpName != name) || (tmpNsName != ns_uri)) {
2316
for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2317
cur = tctxt->varsTab[i-1];
2318
if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2319
variable = cur;
2320
goto local_variable_found;
2321
}
2322
}
2323
}
2324
}
2325
2326
local_variable_found:
2327
2328
if (variable) {
2329
if (variable->computed == 0) {
2330
2331
#ifdef WITH_XSLT_DEBUG_VARIABLE
2332
XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2333
"uncomputed variable '%s'\n", name));
2334
#endif
2335
variable->value = xsltEvalVariable(tctxt, variable, NULL);
2336
variable->computed = 1;
2337
}
2338
if (variable->value != NULL) {
2339
valueObj = xmlXPathObjectCopy(variable->value);
2340
}
2341
return(valueObj);
2342
}
2343
}
2344
/*
2345
* Global variables/params --------------------------------------------
2346
*/
2347
if (tctxt->globalVars) {
2348
valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
2349
}
2350
2351
if (valueObj == NULL) {
2352
2353
#ifdef WITH_XSLT_DEBUG_VARIABLE
2354
XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2355
"variable not found '%s'\n", name));
2356
#endif
2357
2358
if (ns_uri) {
2359
xsltTransformError(tctxt, NULL, tctxt->inst,
2360
"Variable '{%s}%s' has not been declared.\n", ns_uri, name);
2361
} else {
2362
xsltTransformError(tctxt, NULL, tctxt->inst,
2363
"Variable '%s' has not been declared.\n", name);
2364
}
2365
} else {
2366
2367
#ifdef WITH_XSLT_DEBUG_VARIABLE
2368
XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2369
"found variable '%s'\n", name));
2370
#endif
2371
}
2372
2373
return(valueObj);
2374
}
2375
2376