Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: third_party/libxslt/libxslt/transform.c

Issue 2865973002: Check in the libxslt roll script. (Closed)
Patch Set: Consistent quotes. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libxslt/libxslt/transform.h ('k') | third_party/libxslt/libxslt/trio.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * transform.c: Implementation of the XSL Transformation 1.0 engine
3 * transform part, i.e. applying a Stylesheet to a document
4 *
5 * References:
6 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 *
8 * Michael Kay "XSLT Programmer's Reference" pp 637-643
9 * Writing Multiple Output Files
10 *
11 * XSLT-1.1 Working Draft
12 * http://www.w3.org/TR/xslt11#multiple-output
13 *
14 * See Copyright for the status of this software.
15 *
16 * daniel@veillard.com
17 */
18
19 #define IN_LIBXSLT
20 #include "libxslt.h"
21
22 #include <string.h>
23 #include <stdio.h>
24
25 #include <libxml/xmlmemory.h>
26 #include <libxml/parser.h>
27 #include <libxml/tree.h>
28 #include <libxml/valid.h>
29 #include <libxml/hash.h>
30 #include <libxml/encoding.h>
31 #include <libxml/xmlerror.h>
32 #include <libxml/xpath.h>
33 #include <libxml/parserInternals.h>
34 #include <libxml/xpathInternals.h>
35 #include <libxml/HTMLtree.h>
36 #include <libxml/debugXML.h>
37 #include <libxml/uri.h>
38 #include "xslt.h"
39 #include "xsltInternals.h"
40 #include "xsltutils.h"
41 #include "pattern.h"
42 #include "transform.h"
43 #include "variables.h"
44 #include "numbersInternals.h"
45 #include "namespaces.h"
46 #include "attributes.h"
47 #include "templates.h"
48 #include "imports.h"
49 #include "keys.h"
50 #include "documents.h"
51 #include "extensions.h"
52 #include "extra.h"
53 #include "preproc.h"
54 #include "security.h"
55
56 #ifdef WITH_XSLT_DEBUG
57 #define WITH_XSLT_DEBUG_EXTRA
58 #define WITH_XSLT_DEBUG_PROCESS
59 #define WITH_XSLT_DEBUG_VARIABLE
60 #endif
61
62 #define XSLT_GENERATE_HTML_DOCTYPE
63 #ifdef XSLT_GENERATE_HTML_DOCTYPE
64 static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
65 const xmlChar **systemID);
66 #endif
67
68 int xsltMaxDepth = 3000;
69 int xsltMaxVars = 15000;
70
71 /*
72 * Useful macros
73 */
74
75 #ifndef FALSE
76 # define FALSE (0 == 1)
77 # define TRUE (!FALSE)
78 #endif
79
80 #define IS_BLANK_NODE(n) \
81 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
82
83
84 /*
85 * Forward declarations
86 */
87
88 static xmlNsPtr
89 xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
90
91 static xmlNodePtr
92 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
93 xmlNodePtr node, xmlNodePtr insert, int isLRE,
94 int topElemVisited);
95
96 static void
97 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
98 xmlNodePtr contextNode, xmlNodePtr list,
99 xsltTemplatePtr templ);
100
101 static void
102 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
103 xmlNodePtr contextNode,
104 xmlNodePtr list,
105 xsltTemplatePtr templ,
106 xsltStackElemPtr withParams);
107
108 /**
109 * templPush:
110 * @ctxt: the transformation context
111 * @value: the template to push on the stack
112 *
113 * Push a template on the stack
114 *
115 * Returns the new index in the stack or 0 in case of error
116 */
117 static int
118 templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
119 {
120 if (ctxt->templMax == 0) {
121 ctxt->templMax = 4;
122 ctxt->templTab =
123 (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *
124 sizeof(ctxt->templTab[0]));
125 if (ctxt->templTab == NULL) {
126 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
127 return (0);
128 }
129 }
130 else if (ctxt->templNr >= ctxt->templMax) {
131 ctxt->templMax *= 2;
132 ctxt->templTab =
133 (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
134 ctxt->templMax *
135 sizeof(ctxt->templTab[0]));
136 if (ctxt->templTab == NULL) {
137 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
138 return (0);
139 }
140 }
141 ctxt->templTab[ctxt->templNr] = value;
142 ctxt->templ = value;
143 return (ctxt->templNr++);
144 }
145 /**
146 * templPop:
147 * @ctxt: the transformation context
148 *
149 * Pop a template value from the stack
150 *
151 * Returns the stored template value
152 */
153 static xsltTemplatePtr
154 templPop(xsltTransformContextPtr ctxt)
155 {
156 xsltTemplatePtr ret;
157
158 if (ctxt->templNr <= 0)
159 return (0);
160 ctxt->templNr--;
161 if (ctxt->templNr > 0)
162 ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
163 else
164 ctxt->templ = (xsltTemplatePtr) 0;
165 ret = ctxt->templTab[ctxt->templNr];
166 ctxt->templTab[ctxt->templNr] = 0;
167 return (ret);
168 }
169
170 /**
171 * xsltLocalVariablePop:
172 * @ctxt: the transformation context
173 * @limitNr: number of variables which should remain
174 * @level: the depth in the xsl:template's tree
175 *
176 * Pops all variable values at the given @depth from the stack.
177 *
178 * Returns the stored variable value
179 * **NOTE:**
180 * This is an internal routine and should not be called by users!
181 */
182 void
183 xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
184 {
185 xsltStackElemPtr variable;
186
187 if (ctxt->varsNr <= 0)
188 return;
189
190 do {
191 if (ctxt->varsNr <= limitNr)
192 break;
193 variable = ctxt->varsTab[ctxt->varsNr - 1];
194 if (variable->level <= level)
195 break;
196 if (variable->level >= 0)
197 xsltFreeStackElemList(variable);
198 ctxt->varsNr--;
199 } while (ctxt->varsNr != 0);
200 if (ctxt->varsNr > 0)
201 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
202 else
203 ctxt->vars = NULL;
204 }
205
206 /**
207 * xsltTemplateParamsCleanup:
208 *
209 * Removes xsl:param and xsl:with-param items from the
210 * variable-stack. Only xsl:with-param items are not freed.
211 */
212 static void
213 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
214 {
215 xsltStackElemPtr param;
216
217 for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
218 param = ctxt->varsTab[ctxt->varsNr -1];
219 /*
220 * Free xsl:param items.
221 * xsl:with-param items will have a level of -1 or -2.
222 */
223 if (param->level >= 0) {
224 xsltFreeStackElemList(param);
225 }
226 }
227 if (ctxt->varsNr > 0)
228 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
229 else
230 ctxt->vars = NULL;
231 }
232
233 /**
234 * profPush:
235 * @ctxt: the transformation context
236 * @value: the profiling value to push on the stack
237 *
238 * Push a profiling value on the stack
239 *
240 * Returns the new index in the stack or 0 in case of error
241 */
242 static int
243 profPush(xsltTransformContextPtr ctxt, long value)
244 {
245 if (ctxt->profMax == 0) {
246 ctxt->profMax = 4;
247 ctxt->profTab =
248 (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
249 if (ctxt->profTab == NULL) {
250 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
251 return (0);
252 }
253 }
254 else if (ctxt->profNr >= ctxt->profMax) {
255 ctxt->profMax *= 2;
256 ctxt->profTab =
257 (long *) xmlRealloc(ctxt->profTab,
258 ctxt->profMax * sizeof(ctxt->profTab[0]));
259 if (ctxt->profTab == NULL) {
260 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
261 return (0);
262 }
263 }
264 ctxt->profTab[ctxt->profNr] = value;
265 ctxt->prof = value;
266 return (ctxt->profNr++);
267 }
268 /**
269 * profPop:
270 * @ctxt: the transformation context
271 *
272 * Pop a profiling value from the stack
273 *
274 * Returns the stored profiling value
275 */
276 static long
277 profPop(xsltTransformContextPtr ctxt)
278 {
279 long ret;
280
281 if (ctxt->profNr <= 0)
282 return (0);
283 ctxt->profNr--;
284 if (ctxt->profNr > 0)
285 ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
286 else
287 ctxt->prof = (long) 0;
288 ret = ctxt->profTab[ctxt->profNr];
289 ctxt->profTab[ctxt->profNr] = 0;
290 return (ret);
291 }
292
293 static void
294 profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
295 {
296 int i;
297
298 if (templ->templMax == 0) {
299 templ->templMax = 4;
300 templ->templCalledTab =
301 (xsltTemplatePtr *) xmlMalloc(templ->templMax *
302 sizeof(templ->templCalledTab[0]));
303 templ->templCountTab =
304 (int *) xmlMalloc(templ->templMax *
305 sizeof(templ->templCountTab[0]));
306 if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
307 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
308 return;
309 }
310 }
311 else if (templ->templNr >= templ->templMax) {
312 templ->templMax *= 2;
313 templ->templCalledTab =
314 (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab,
315 templ->templMax *
316 sizeof(templ->templCalledTab[0]));
317 templ->templCountTab =
318 (int *) xmlRealloc(templ->templCountTab,
319 templ->templMax *
320 sizeof(templ->templCountTab[0]));
321 if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
322 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
323 return;
324 }
325 }
326
327 for (i = 0; i < templ->templNr; i++) {
328 if (templ->templCalledTab[i] == parent) {
329 templ->templCountTab[i]++;
330 break;
331 }
332 }
333 if (i == templ->templNr) {
334 /* not found, add new one */
335 templ->templCalledTab[templ->templNr] = parent;
336 templ->templCountTab[templ->templNr] = 1;
337 templ->templNr++;
338 }
339 }
340
341 /**
342 * xsltPreCompEval:
343 * @ctxt: transform context
344 * @node: context node
345 * @comp: precompiled expression
346 *
347 * Evaluate a precompiled XPath expression.
348 */
349 static xmlXPathObjectPtr
350 xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node,
351 xsltStylePreCompPtr comp) {
352 xmlXPathObjectPtr res;
353 xmlXPathContextPtr xpctxt;
354 xmlNodePtr oldXPContextNode;
355 xmlNsPtr *oldXPNamespaces;
356 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
357
358 xpctxt = ctxt->xpathCtxt;
359 oldXPContextNode = xpctxt->node;
360 oldXPProximityPosition = xpctxt->proximityPosition;
361 oldXPContextSize = xpctxt->contextSize;
362 oldXPNsNr = xpctxt->nsNr;
363 oldXPNamespaces = xpctxt->namespaces;
364
365 xpctxt->node = node;
366 #ifdef XSLT_REFACTORED
367 if (comp->inScopeNs != NULL) {
368 xpctxt->namespaces = comp->inScopeNs->list;
369 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
370 } else {
371 xpctxt->namespaces = NULL;
372 xpctxt->nsNr = 0;
373 }
374 #else
375 xpctxt->namespaces = comp->nsList;
376 xpctxt->nsNr = comp->nsNr;
377 #endif
378
379 res = xmlXPathCompiledEval(comp->comp, xpctxt);
380
381 xpctxt->node = oldXPContextNode;
382 xpctxt->proximityPosition = oldXPProximityPosition;
383 xpctxt->contextSize = oldXPContextSize;
384 xpctxt->nsNr = oldXPNsNr;
385 xpctxt->namespaces = oldXPNamespaces;
386
387 return(res);
388 }
389
390 /**
391 * xsltPreCompEvalToBoolean:
392 * @ctxt: transform context
393 * @node: context node
394 * @comp: precompiled expression
395 *
396 * Evaluate a precompiled XPath expression as boolean.
397 */
398 static int
399 xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node,
400 xsltStylePreCompPtr comp) {
401 int res;
402 xmlXPathContextPtr xpctxt;
403 xmlNodePtr oldXPContextNode;
404 xmlNsPtr *oldXPNamespaces;
405 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
406
407 xpctxt = ctxt->xpathCtxt;
408 oldXPContextNode = xpctxt->node;
409 oldXPProximityPosition = xpctxt->proximityPosition;
410 oldXPContextSize = xpctxt->contextSize;
411 oldXPNsNr = xpctxt->nsNr;
412 oldXPNamespaces = xpctxt->namespaces;
413
414 xpctxt->node = node;
415 #ifdef XSLT_REFACTORED
416 if (comp->inScopeNs != NULL) {
417 xpctxt->namespaces = comp->inScopeNs->list;
418 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
419 } else {
420 xpctxt->namespaces = NULL;
421 xpctxt->nsNr = 0;
422 }
423 #else
424 xpctxt->namespaces = comp->nsList;
425 xpctxt->nsNr = comp->nsNr;
426 #endif
427
428 res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
429
430 xpctxt->node = oldXPContextNode;
431 xpctxt->proximityPosition = oldXPProximityPosition;
432 xpctxt->contextSize = oldXPContextSize;
433 xpctxt->nsNr = oldXPNsNr;
434 xpctxt->namespaces = oldXPNamespaces;
435
436 return(res);
437 }
438
439 /************************************************************************
440 * *
441 * XInclude default settings *
442 * *
443 ************************************************************************/
444
445 static int xsltDoXIncludeDefault = 0;
446
447 /**
448 * xsltSetXIncludeDefault:
449 * @xinclude: whether to do XInclude processing
450 *
451 * Set whether XInclude should be processed on document being loaded by default
452 */
453 void
454 xsltSetXIncludeDefault(int xinclude) {
455 xsltDoXIncludeDefault = (xinclude != 0);
456 }
457
458 /**
459 * xsltGetXIncludeDefault:
460 *
461 * Provides the default state for XInclude processing
462 *
463 * Returns 0 if there is no processing 1 otherwise
464 */
465 int
466 xsltGetXIncludeDefault(void) {
467 return(xsltDoXIncludeDefault);
468 }
469
470 static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
471
472 /**
473 * xsltDebugSetDefaultTrace:
474 * @val: tracing level mask
475 *
476 * Set the default debug tracing level mask
477 */
478 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
479 xsltDefaultTrace = val;
480 }
481
482 /**
483 * xsltDebugGetDefaultTrace:
484 *
485 * Get the current default debug tracing level mask
486 *
487 * Returns the current default debug tracing level mask
488 */
489 xsltDebugTraceCodes xsltDebugGetDefaultTrace() {
490 return xsltDefaultTrace;
491 }
492
493 /************************************************************************
494 * *
495 * Handling of Transformation Contexts *
496 * *
497 ************************************************************************/
498
499 static xsltTransformCachePtr
500 xsltTransformCacheCreate(void)
501 {
502 xsltTransformCachePtr ret;
503
504 ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
505 if (ret == NULL) {
506 xsltTransformError(NULL, NULL, NULL,
507 "xsltTransformCacheCreate : malloc failed\n");
508 return(NULL);
509 }
510 memset(ret, 0, sizeof(xsltTransformCache));
511 return(ret);
512 }
513
514 static void
515 xsltTransformCacheFree(xsltTransformCachePtr cache)
516 {
517 if (cache == NULL)
518 return;
519 /*
520 * Free tree fragments.
521 */
522 if (cache->RVT) {
523 xmlDocPtr tmp, cur = cache->RVT;
524 while (cur) {
525 tmp = cur;
526 cur = (xmlDocPtr) cur->next;
527 if (tmp->_private != NULL) {
528 /*
529 * Tree the document info.
530 */
531 xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
532 xmlFree(tmp->_private);
533 }
534 xmlFreeDoc(tmp);
535 }
536 }
537 /*
538 * Free vars/params.
539 */
540 if (cache->stackItems) {
541 xsltStackElemPtr tmp, cur = cache->stackItems;
542 while (cur) {
543 tmp = cur;
544 cur = cur->next;
545 /*
546 * REVISIT TODO: Should be call a destruction-function
547 * instead?
548 */
549 xmlFree(tmp);
550 }
551 }
552 xmlFree(cache);
553 }
554
555 /**
556 * xsltNewTransformContext:
557 * @style: a parsed XSLT stylesheet
558 * @doc: the input document
559 *
560 * Create a new XSLT TransformContext
561 *
562 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
563 */
564 xsltTransformContextPtr
565 xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
566 xsltTransformContextPtr cur;
567 xsltDocumentPtr docu;
568 int i;
569
570 xsltInitGlobals();
571
572 cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
573 if (cur == NULL) {
574 xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
575 "xsltNewTransformContext : malloc failed\n");
576 return(NULL);
577 }
578 memset(cur, 0, sizeof(xsltTransformContext));
579
580 cur->cache = xsltTransformCacheCreate();
581 if (cur->cache == NULL)
582 goto internal_err;
583 /*
584 * setup of the dictionary must be done early as some of the
585 * processing later like key handling may need it.
586 */
587 cur->dict = xmlDictCreateSub(style->dict);
588 cur->internalized = ((style->internalized) && (cur->dict != NULL));
589 #ifdef WITH_XSLT_DEBUG
590 xsltGenericDebug(xsltGenericDebugContext,
591 "Creating sub-dictionary from stylesheet for transformation\n");
592 #endif
593
594 /*
595 * initialize the template stack
596 */
597 cur->templTab = (xsltTemplatePtr *)
598 xmlMalloc(10 * sizeof(xsltTemplatePtr));
599 if (cur->templTab == NULL) {
600 xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
601 "xsltNewTransformContext: out of memory\n");
602 goto internal_err;
603 }
604 cur->templNr = 0;
605 cur->templMax = 5;
606 cur->templ = NULL;
607 cur->maxTemplateDepth = xsltMaxDepth;
608
609 /*
610 * initialize the variables stack
611 */
612 cur->varsTab = (xsltStackElemPtr *)
613 xmlMalloc(10 * sizeof(xsltStackElemPtr));
614 if (cur->varsTab == NULL) {
615 xmlGenericError(xmlGenericErrorContext,
616 "xsltNewTransformContext: out of memory\n");
617 goto internal_err;
618 }
619 cur->varsNr = 0;
620 cur->varsMax = 10;
621 cur->vars = NULL;
622 cur->varsBase = 0;
623 cur->maxTemplateVars = xsltMaxVars;
624
625 /*
626 * the profiling stack is not initialized by default
627 */
628 cur->profTab = NULL;
629 cur->profNr = 0;
630 cur->profMax = 0;
631 cur->prof = 0;
632
633 cur->style = style;
634 xmlXPathInit();
635 cur->xpathCtxt = xmlXPathNewContext(doc);
636 if (cur->xpathCtxt == NULL) {
637 xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
638 "xsltNewTransformContext : xmlXPathNewContext failed\n");
639 goto internal_err;
640 }
641 /*
642 * Create an XPath cache.
643 */
644 if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
645 goto internal_err;
646 /*
647 * Initialize the extras array
648 */
649 if (style->extrasNr != 0) {
650 cur->extrasMax = style->extrasNr + 20;
651 cur->extras = (xsltRuntimeExtraPtr)
652 xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
653 if (cur->extras == NULL) {
654 xmlGenericError(xmlGenericErrorContext,
655 "xsltNewTransformContext: out of memory\n");
656 goto internal_err;
657 }
658 cur->extrasNr = style->extrasNr;
659 for (i = 0;i < cur->extrasMax;i++) {
660 cur->extras[i].info = NULL;
661 cur->extras[i].deallocate = NULL;
662 cur->extras[i].val.ptr = NULL;
663 }
664 } else {
665 cur->extras = NULL;
666 cur->extrasNr = 0;
667 cur->extrasMax = 0;
668 }
669
670 XSLT_REGISTER_VARIABLE_LOOKUP(cur);
671 XSLT_REGISTER_FUNCTION_LOOKUP(cur);
672 cur->xpathCtxt->nsHash = style->nsHash;
673 /*
674 * Initialize the registered external modules
675 */
676 xsltInitCtxtExts(cur);
677 /*
678 * Setup document element ordering for later efficiencies
679 * (bug 133289)
680 */
681 if (xslDebugStatus == XSLT_DEBUG_NONE)
682 xmlXPathOrderDocElems(doc);
683 /*
684 * Must set parserOptions before calling xsltNewDocument
685 * (bug 164530)
686 */
687 cur->parserOptions = XSLT_PARSE_OPTIONS;
688 docu = xsltNewDocument(cur, doc);
689 if (docu == NULL) {
690 xsltTransformError(cur, NULL, (xmlNodePtr)doc,
691 "xsltNewTransformContext : xsltNewDocument failed\n");
692 goto internal_err;
693 }
694 docu->main = 1;
695 cur->document = docu;
696 cur->inst = NULL;
697 cur->outputFile = NULL;
698 cur->sec = xsltGetDefaultSecurityPrefs();
699 cur->debugStatus = xslDebugStatus;
700 cur->traceCode = (unsigned long*) &xsltDefaultTrace;
701 cur->xinclude = xsltGetXIncludeDefault();
702 cur->keyInitLevel = 0;
703
704 return(cur);
705
706 internal_err:
707 if (cur != NULL)
708 xsltFreeTransformContext(cur);
709 return(NULL);
710 }
711
712 /**
713 * xsltFreeTransformContext:
714 * @ctxt: an XSLT parser context
715 *
716 * Free up the memory allocated by @ctxt
717 */
718 void
719 xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
720 if (ctxt == NULL)
721 return;
722
723 /*
724 * Shutdown the extension modules associated to the stylesheet
725 * used if needed.
726 */
727 xsltShutdownCtxtExts(ctxt);
728
729 if (ctxt->xpathCtxt != NULL) {
730 ctxt->xpathCtxt->nsHash = NULL;
731 xmlXPathFreeContext(ctxt->xpathCtxt);
732 }
733 if (ctxt->templTab != NULL)
734 xmlFree(ctxt->templTab);
735 if (ctxt->varsTab != NULL)
736 xmlFree(ctxt->varsTab);
737 if (ctxt->profTab != NULL)
738 xmlFree(ctxt->profTab);
739 if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
740 int i;
741
742 for (i = 0;i < ctxt->extrasNr;i++) {
743 if ((ctxt->extras[i].deallocate != NULL) &&
744 (ctxt->extras[i].info != NULL))
745 ctxt->extras[i].deallocate(ctxt->extras[i].info);
746 }
747 xmlFree(ctxt->extras);
748 }
749 xsltFreeGlobalVariables(ctxt);
750 xsltFreeDocuments(ctxt);
751 xsltFreeCtxtExts(ctxt);
752 xsltFreeRVTs(ctxt);
753 xsltTransformCacheFree(ctxt->cache);
754 xmlDictFree(ctxt->dict);
755 #ifdef WITH_XSLT_DEBUG
756 xsltGenericDebug(xsltGenericDebugContext,
757 "freeing transformation dictionary\n");
758 #endif
759 memset(ctxt, -1, sizeof(xsltTransformContext));
760 xmlFree(ctxt);
761 }
762
763 /************************************************************************
764 * *
765 * Copy of Nodes in an XSLT fashion *
766 * *
767 ************************************************************************/
768
769 /**
770 * xsltAddChild:
771 * @parent: the parent node
772 * @cur: the child node
773 *
774 * Wrapper version of xmlAddChild with a more consistent behaviour on
775 * error. One expect the use to be child = xsltAddChild(parent, child);
776 * and the routine will take care of not leaking on errors or node merge
777 *
778 * Returns the child is successfully attached or NULL if merged or freed
779 */
780 static xmlNodePtr
781 xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
782 xmlNodePtr ret;
783
784 if (cur == NULL)
785 return(NULL);
786 if (parent == NULL) {
787 xmlFreeNode(cur);
788 return(NULL);
789 }
790 ret = xmlAddChild(parent, cur);
791
792 return(ret);
793 }
794
795 /**
796 * xsltAddTextString:
797 * @ctxt: a XSLT process context
798 * @target: the text node where the text will be attached
799 * @string: the text string
800 * @len: the string length in byte
801 *
802 * Extend the current text node with the new string, it handles coalescing
803 *
804 * Returns: the text node
805 */
806 static xmlNodePtr
807 xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
808 const xmlChar *string, int len) {
809 /*
810 * optimization
811 */
812 if ((len <= 0) || (string == NULL) || (target == NULL))
813 return(target);
814
815 if (ctxt->lasttext == target->content) {
816 int minSize;
817
818 /* Check for integer overflow accounting for NUL terminator. */
819 if (len >= INT_MAX - ctxt->lasttuse) {
820 xsltTransformError(ctxt, NULL, target,
821 "xsltCopyText: text allocation failed\n");
822 return(NULL);
823 }
824 minSize = ctxt->lasttuse + len + 1;
825
826 if (ctxt->lasttsize < minSize) {
827 xmlChar *newbuf;
828 int size;
829 int extra;
830
831 /* Double buffer size but increase by at least 100 bytes. */
832 extra = minSize < 100 ? 100 : minSize;
833
834 /* Check for integer overflow. */
835 if (extra > INT_MAX - ctxt->lasttsize) {
836 size = INT_MAX;
837 }
838 else {
839 size = ctxt->lasttsize + extra;
840 }
841
842 newbuf = (xmlChar *) xmlRealloc(target->content,size);
843 if (newbuf == NULL) {
844 xsltTransformError(ctxt, NULL, target,
845 "xsltCopyText: text allocation failed\n");
846 return(NULL);
847 }
848 ctxt->lasttsize = size;
849 ctxt->lasttext = newbuf;
850 target->content = newbuf;
851 }
852 memcpy(&(target->content[ctxt->lasttuse]), string, len);
853 ctxt->lasttuse += len;
854 target->content[ctxt->lasttuse] = 0;
855 } else {
856 xmlNodeAddContent(target, string);
857 ctxt->lasttext = target->content;
858 len = xmlStrlen(target->content);
859 ctxt->lasttsize = len;
860 ctxt->lasttuse = len;
861 }
862 return(target);
863 }
864
865 /**
866 * xsltCopyTextString:
867 * @ctxt: a XSLT process context
868 * @target: the element where the text will be attached
869 * @string: the text string
870 * @noescape: should disable-escaping be activated for this text node.
871 *
872 * Adds @string to a newly created or an existent text node child of
873 * @target.
874 *
875 * Returns: the text node, where the text content of @cur is copied to.
876 * NULL in case of API or internal errors.
877 */
878 xmlNodePtr
879 xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
880 const xmlChar *string, int noescape)
881 {
882 xmlNodePtr copy;
883 int len;
884
885 if (string == NULL)
886 return(NULL);
887
888 #ifdef WITH_XSLT_DEBUG_PROCESS
889 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContex t,
890 "xsltCopyTextString: copy text %s\n",
891 string));
892 #endif
893
894 /*
895 * Play safe and reset the merging mechanism for every new
896 * target node.
897 */
898 if ((target == NULL) || (target->children == NULL)) {
899 ctxt->lasttext = NULL;
900 }
901
902 /* handle coalescing of text nodes here */
903 len = xmlStrlen(string);
904 if ((ctxt->type == XSLT_OUTPUT_XML) &&
905 (ctxt->style->cdataSection != NULL) &&
906 (target != NULL) &&
907 (target->type == XML_ELEMENT_NODE) &&
908 (((target->ns == NULL) &&
909 (xmlHashLookup2(ctxt->style->cdataSection,
910 target->name, NULL) != NULL)) ||
911 ((target->ns != NULL) &&
912 (xmlHashLookup2(ctxt->style->cdataSection,
913 target->name, target->ns->href) != NULL))))
914 {
915 /*
916 * Process "cdata-section-elements".
917 */
918 if ((target->last != NULL) &&
919 (target->last->type == XML_CDATA_SECTION_NODE))
920 {
921 return(xsltAddTextString(ctxt, target->last, string, len));
922 }
923 copy = xmlNewCDataBlock(ctxt->output, string, len);
924 } else if (noescape) {
925 /*
926 * Process "disable-output-escaping".
927 */
928 if ((target != NULL) && (target->last != NULL) &&
929 (target->last->type == XML_TEXT_NODE) &&
930 (target->last->name == xmlStringTextNoenc))
931 {
932 return(xsltAddTextString(ctxt, target->last, string, len));
933 }
934 copy = xmlNewTextLen(string, len);
935 if (copy != NULL)
936 copy->name = xmlStringTextNoenc;
937 } else {
938 /*
939 * Default processing.
940 */
941 if ((target != NULL) && (target->last != NULL) &&
942 (target->last->type == XML_TEXT_NODE) &&
943 (target->last->name == xmlStringText)) {
944 return(xsltAddTextString(ctxt, target->last, string, len));
945 }
946 copy = xmlNewTextLen(string, len);
947 }
948 if (copy != NULL && target != NULL)
949 copy = xsltAddChild(target, copy);
950 if (copy != NULL) {
951 ctxt->lasttext = copy->content;
952 ctxt->lasttsize = len;
953 ctxt->lasttuse = len;
954 } else {
955 xsltTransformError(ctxt, NULL, target,
956 "xsltCopyTextString: text copy failed\n");
957 ctxt->lasttext = NULL;
958 }
959 return(copy);
960 }
961
962 /**
963 * xsltCopyText:
964 * @ctxt: a XSLT process context
965 * @target: the element where the text will be attached
966 * @cur: the text or CDATA node
967 * @interned: the string is in the target doc dictionary
968 *
969 * Copy the text content of @cur and append it to @target's children.
970 *
971 * Returns: the text node, where the text content of @cur is copied to.
972 * NULL in case of API or internal errors.
973 */
974 static xmlNodePtr
975 xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
976 xmlNodePtr cur, int interned)
977 {
978 xmlNodePtr copy;
979
980 if ((cur->type != XML_TEXT_NODE) &&
981 (cur->type != XML_CDATA_SECTION_NODE))
982 return(NULL);
983 if (cur->content == NULL)
984 return(NULL);
985
986 #ifdef WITH_XSLT_DEBUG_PROCESS
987 if (cur->type == XML_CDATA_SECTION_NODE) {
988 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugCo ntext,
989 "xsltCopyText: copy CDATA text %s\n",
990 cur->content));
991 } else if (cur->name == xmlStringTextNoenc) {
992 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugCo ntext,
993 "xsltCopyText: copy unescaped text %s\n",
994 cur->content));
995 } else {
996 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugCo ntext,
997 "xsltCopyText: copy text %s\n",
998 cur->content));
999 }
1000 #endif
1001
1002 /*
1003 * Play save and reset the merging mechanism for every new
1004 * target node.
1005 */
1006 if ((target == NULL) || (target->children == NULL)) {
1007 ctxt->lasttext = NULL;
1008 }
1009
1010 if ((ctxt->style->cdataSection != NULL) &&
1011 (ctxt->type == XSLT_OUTPUT_XML) &&
1012 (target != NULL) &&
1013 (target->type == XML_ELEMENT_NODE) &&
1014 (((target->ns == NULL) &&
1015 (xmlHashLookup2(ctxt->style->cdataSection,
1016 target->name, NULL) != NULL)) ||
1017 ((target->ns != NULL) &&
1018 (xmlHashLookup2(ctxt->style->cdataSection,
1019 target->name, target->ns->href) != NULL))))
1020 {
1021 /*
1022 * Process "cdata-section-elements".
1023 */
1024 /*
1025 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
1026 */
1027 /*
1028 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
1029 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
1030 * TODO: Reported in #321505.
1031 */
1032 if ((target->last != NULL) &&
1033 (target->last->type == XML_CDATA_SECTION_NODE))
1034 {
1035 /*
1036 * Append to existing CDATA-section node.
1037 */
1038 copy = xsltAddTextString(ctxt, target->last, cur->content,
1039 xmlStrlen(cur->content));
1040 goto exit;
1041 } else {
1042 unsigned int len;
1043
1044 len = xmlStrlen(cur->content);
1045 copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
1046 if (copy == NULL)
1047 goto exit;
1048 ctxt->lasttext = copy->content;
1049 ctxt->lasttsize = len;
1050 ctxt->lasttuse = len;
1051 }
1052 } else if ((target != NULL) &&
1053 (target->last != NULL) &&
1054 /* both escaped or both non-escaped text-nodes */
1055 (((target->last->type == XML_TEXT_NODE) &&
1056 (target->last->name == cur->name)) ||
1057 /* non-escaped text nodes and CDATA-section nodes */
1058 (((target->last->type == XML_CDATA_SECTION_NODE) &&
1059 (cur->name == xmlStringTextNoenc)))))
1060 {
1061 /*
1062 * we are appending to an existing text node
1063 */
1064 copy = xsltAddTextString(ctxt, target->last, cur->content,
1065 xmlStrlen(cur->content));
1066 goto exit;
1067 } else if ((interned) && (target != NULL) &&
1068 (target->doc != NULL) &&
1069 (target->doc->dict == ctxt->dict))
1070 {
1071 /*
1072 * TODO: DO we want to use this also for "text" output?
1073 */
1074 copy = xmlNewTextLen(NULL, 0);
1075 if (copy == NULL)
1076 goto exit;
1077 if (cur->name == xmlStringTextNoenc)
1078 copy->name = xmlStringTextNoenc;
1079
1080 /*
1081 * Must confirm that content is in dict (bug 302821)
1082 * TODO: This check should be not needed for text coming
1083 * from the stylesheets
1084 */
1085 if (xmlDictOwns(ctxt->dict, cur->content))
1086 copy->content = cur->content;
1087 else {
1088 if ((copy->content = xmlStrdup(cur->content)) == NULL)
1089 return NULL;
1090 }
1091 } else {
1092 /*
1093 * normal processing. keep counters to extend the text node
1094 * in xsltAddTextString if needed.
1095 */
1096 unsigned int len;
1097
1098 len = xmlStrlen(cur->content);
1099 copy = xmlNewTextLen(cur->content, len);
1100 if (copy == NULL)
1101 goto exit;
1102 if (cur->name == xmlStringTextNoenc)
1103 copy->name = xmlStringTextNoenc;
1104 ctxt->lasttext = copy->content;
1105 ctxt->lasttsize = len;
1106 ctxt->lasttuse = len;
1107 }
1108 if (copy != NULL) {
1109 if (target != NULL) {
1110 copy->doc = target->doc;
1111 /*
1112 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1113 * to ensure that the optimized text-merging mechanism
1114 * won't interfere with normal node-merging in any case.
1115 */
1116 copy = xsltAddChild(target, copy);
1117 }
1118 } else {
1119 xsltTransformError(ctxt, NULL, target,
1120 "xsltCopyText: text copy failed\n");
1121 }
1122
1123 exit:
1124 if ((copy == NULL) || (copy->content == NULL)) {
1125 xsltTransformError(ctxt, NULL, target,
1126 "Internal error in xsltCopyText(): "
1127 "Failed to copy the string.\n");
1128 ctxt->state = XSLT_STATE_STOPPED;
1129 }
1130 return(copy);
1131 }
1132
1133 /**
1134 * xsltShallowCopyAttr:
1135 * @ctxt: a XSLT process context
1136 * @invocNode: responsible node in the stylesheet; used for error reports
1137 * @target: the element where the attribute will be grafted
1138 * @attr: the attribute to be copied
1139 *
1140 * Do a copy of an attribute.
1141 * Called by:
1142 * - xsltCopyTree()
1143 * - xsltCopyOf()
1144 * - xsltCopy()
1145 *
1146 * Returns: a new xmlAttrPtr, or NULL in case of error.
1147 */
1148 static xmlAttrPtr
1149 xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1150 xmlNodePtr target, xmlAttrPtr attr)
1151 {
1152 xmlAttrPtr copy;
1153 xmlChar *value;
1154
1155 if (attr == NULL)
1156 return(NULL);
1157
1158 if (target->type != XML_ELEMENT_NODE) {
1159 xsltTransformError(ctxt, NULL, invocNode,
1160 "Cannot add an attribute node to a non-element node.\n");
1161 return(NULL);
1162 }
1163
1164 if (target->children != NULL) {
1165 xsltTransformError(ctxt, NULL, invocNode,
1166 "Attribute nodes must be added before "
1167 "any child nodes to an element.\n");
1168 return(NULL);
1169 }
1170
1171 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1172 if (attr->ns != NULL) {
1173 xmlNsPtr ns;
1174
1175 ns = xsltGetSpecialNamespace(ctxt, invocNode,
1176 attr->ns->href, attr->ns->prefix, target);
1177 if (ns == NULL) {
1178 xsltTransformError(ctxt, NULL, invocNode,
1179 "Namespace fixup error: Failed to acquire an in-scope "
1180 "namespace binding of the copied attribute '{%s}%s'.\n",
1181 attr->ns->href, attr->name);
1182 /*
1183 * TODO: Should we just stop here?
1184 */
1185 }
1186 /*
1187 * Note that xmlSetNsProp() will take care of duplicates
1188 * and assigns the new namespace even to a duplicate.
1189 */
1190 copy = xmlSetNsProp(target, ns, attr->name, value);
1191 } else {
1192 copy = xmlSetNsProp(target, NULL, attr->name, value);
1193 }
1194 if (value != NULL)
1195 xmlFree(value);
1196
1197 if (copy == NULL)
1198 return(NULL);
1199
1200 #if 0
1201 /*
1202 * NOTE: This was optimized according to bug #342695.
1203 * TODO: Can this further be optimized, if source and target
1204 * share the same dict and attr->children is just 1 text node
1205 * which is in the dict? How probable is such a case?
1206 */
1207 /*
1208 * TODO: Do we need to create an empty text node if the value
1209 * is the empty string?
1210 */
1211 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1212 if (value != NULL) {
1213 txtNode = xmlNewDocText(target->doc, NULL);
1214 if (txtNode == NULL)
1215 return(NULL);
1216 if ((target->doc != NULL) &&
1217 (target->doc->dict != NULL))
1218 {
1219 txtNode->content =
1220 (xmlChar *) xmlDictLookup(target->doc->dict,
1221 BAD_CAST value, -1);
1222 xmlFree(value);
1223 } else
1224 txtNode->content = value;
1225 copy->children = txtNode;
1226 }
1227 #endif
1228
1229 return(copy);
1230 }
1231
1232 /**
1233 * xsltCopyAttrListNoOverwrite:
1234 * @ctxt: a XSLT process context
1235 * @invocNode: responsible node in the stylesheet; used for error reports
1236 * @target: the element where the new attributes will be grafted
1237 * @attr: the first attribute in the list to be copied
1238 *
1239 * Copies a list of attribute nodes, starting with @attr, over to the
1240 * @target element node.
1241 *
1242 * Called by:
1243 * - xsltCopyTree()
1244 *
1245 * Returns 0 on success and -1 on errors and internal errors.
1246 */
1247 static int
1248 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
1249 xmlNodePtr invocNode,
1250 xmlNodePtr target, xmlAttrPtr attr)
1251 {
1252 xmlAttrPtr copy;
1253 xmlNsPtr origNs = NULL, copyNs = NULL;
1254 xmlChar *value;
1255
1256 /*
1257 * Don't use xmlCopyProp() here, since it will try to
1258 * reconciliate namespaces.
1259 */
1260 while (attr != NULL) {
1261 /*
1262 * Find a namespace node in the tree of @target.
1263 * Avoid searching for the same ns.
1264 */
1265 if (attr->ns != origNs) {
1266 origNs = attr->ns;
1267 if (attr->ns != NULL) {
1268 copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
1269 attr->ns->href, attr->ns->prefix, target);
1270 if (copyNs == NULL)
1271 return(-1);
1272 } else
1273 copyNs = NULL;
1274 }
1275 /*
1276 * If attribute has a value, we need to copy it (watching out
1277 * for possible entities)
1278 */
1279 if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
1280 (attr->children->next == NULL)) {
1281 copy = xmlNewNsProp(target, copyNs, attr->name,
1282 attr->children->content);
1283 } else if (attr->children != NULL) {
1284 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1285 copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
1286 xmlFree(value);
1287 } else {
1288 copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
1289 }
1290
1291 if (copy == NULL)
1292 return(-1);
1293
1294 attr = attr->next;
1295 }
1296 return(0);
1297 }
1298
1299 /**
1300 * xsltShallowCopyElem:
1301 * @ctxt: the XSLT process context
1302 * @node: the element node in the source tree
1303 * or the Literal Result Element
1304 * @insert: the parent in the result tree
1305 * @isLRE: if @node is a Literal Result Element
1306 *
1307 * Make a copy of the element node @node
1308 * and insert it as last child of @insert.
1309 *
1310 * URGENT TODO: The problem with this one (for the non-refactored code)
1311 * is that it is used for both, Literal Result Elements *and*
1312 * copying input nodes.
1313 *
1314 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1315 *
1316 * Called from:
1317 * xsltApplySequenceConstructor()
1318 * (for Literal Result Elements - which is a problem)
1319 * xsltCopy() (for shallow-copying elements via xsl:copy)
1320 *
1321 * Returns a pointer to the new node, or NULL in case of error
1322 */
1323 static xmlNodePtr
1324 xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
1325 xmlNodePtr insert, int isLRE)
1326 {
1327 xmlNodePtr copy;
1328
1329 if ((node->type == XML_DTD_NODE) || (insert == NULL))
1330 return(NULL);
1331 if ((node->type == XML_TEXT_NODE) ||
1332 (node->type == XML_CDATA_SECTION_NODE))
1333 return(xsltCopyText(ctxt, insert, node, 0));
1334
1335 copy = xmlDocCopyNode(node, insert->doc, 0);
1336 if (copy != NULL) {
1337 copy->doc = ctxt->output;
1338 copy = xsltAddChild(insert, copy);
1339 if (copy == NULL) {
1340 xsltTransformError(ctxt, NULL, node,
1341 "xsltShallowCopyElem: copy failed\n");
1342 return (copy);
1343 }
1344
1345 if (node->type == XML_ELEMENT_NODE) {
1346 /*
1347 * Add namespaces as they are needed
1348 */
1349 if (node->nsDef != NULL) {
1350 /*
1351 * TODO: Remove the LRE case in the refactored code
1352 * gets enabled.
1353 */
1354 if (isLRE)
1355 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1356 else
1357 xsltCopyNamespaceListInternal(copy, node->nsDef);
1358 }
1359
1360 /*
1361 * URGENT TODO: The problem with this is that it does not
1362 * copy over all namespace nodes in scope.
1363 * The damn thing about this is, that we would need to
1364 * use the xmlGetNsList(), for every single node; this is
1365 * also done in xsltCopyTree(), but only for the top node.
1366 */
1367 if (node->ns != NULL) {
1368 if (isLRE) {
1369 /*
1370 * REVISIT TODO: Since the non-refactored code still does
1371 * ns-aliasing, we need to call xsltGetNamespace() here.
1372 * Remove this when ready.
1373 */
1374 copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
1375 } else {
1376 copy->ns = xsltGetSpecialNamespace(ctxt,
1377 node, node->ns->href, node->ns->prefix, copy);
1378
1379 }
1380 } else if ((insert->type == XML_ELEMENT_NODE) &&
1381 (insert->ns != NULL))
1382 {
1383 /*
1384 * "Undeclare" the default namespace.
1385 */
1386 xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
1387 }
1388 }
1389 } else {
1390 xsltTransformError(ctxt, NULL, node,
1391 "xsltShallowCopyElem: copy %s failed\n", node->name);
1392 }
1393 return(copy);
1394 }
1395
1396 /**
1397 * xsltCopyTreeList:
1398 * @ctxt: a XSLT process context
1399 * @invocNode: responsible node in the stylesheet; used for error reports
1400 * @list: the list of element nodes in the source tree.
1401 * @insert: the parent in the result tree.
1402 * @isLRE: is this a literal result element list
1403 * @topElemVisited: indicates if a top-most element was already processed
1404 *
1405 * Make a copy of the full list of tree @list
1406 * and insert it as last children of @insert
1407 *
1408 * NOTE: Not to be used for Literal Result Elements.
1409 *
1410 * Used by:
1411 * - xsltCopyOf()
1412 *
1413 * Returns a pointer to the new list, or NULL in case of error
1414 */
1415 static xmlNodePtr
1416 xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1417 xmlNodePtr list,
1418 xmlNodePtr insert, int isLRE, int topElemVisited)
1419 {
1420 xmlNodePtr copy, ret = NULL;
1421
1422 while (list != NULL) {
1423 copy = xsltCopyTree(ctxt, invocNode,
1424 list, insert, isLRE, topElemVisited);
1425 if (copy != NULL) {
1426 if (ret == NULL) {
1427 ret = copy;
1428 }
1429 }
1430 list = list->next;
1431 }
1432 return(ret);
1433 }
1434
1435 /**
1436 * xsltCopyNamespaceListInternal:
1437 * @node: the target node
1438 * @cur: the first namespace
1439 *
1440 * Do a copy of a namespace list. If @node is non-NULL the
1441 * new namespaces are added automatically.
1442 * Called by:
1443 * xsltCopyTree()
1444 *
1445 * QUESTION: What is the exact difference between this function
1446 * and xsltCopyNamespaceList() in "namespaces.c"?
1447 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1448 *
1449 * Returns: a new xmlNsPtr, or NULL in case of error.
1450 */
1451 static xmlNsPtr
1452 xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
1453 xmlNsPtr ret = NULL;
1454 xmlNsPtr p = NULL, q, luNs;
1455
1456 if (ns == NULL)
1457 return(NULL);
1458 /*
1459 * One can add namespaces only on element nodes
1460 */
1461 if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
1462 elem = NULL;
1463
1464 do {
1465 if (ns->type != XML_NAMESPACE_DECL)
1466 break;
1467 /*
1468 * Avoid duplicating namespace declarations on the tree.
1469 */
1470 if (elem != NULL) {
1471 if ((elem->ns != NULL) &&
1472 xmlStrEqual(elem->ns->prefix, ns->prefix) &&
1473 xmlStrEqual(elem->ns->href, ns->href))
1474 {
1475 ns = ns->next;
1476 continue;
1477 }
1478 luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
1479 if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
1480 {
1481 ns = ns->next;
1482 continue;
1483 }
1484 }
1485 q = xmlNewNs(elem, ns->href, ns->prefix);
1486 if (p == NULL) {
1487 ret = p = q;
1488 } else if (q != NULL) {
1489 p->next = q;
1490 p = q;
1491 }
1492 ns = ns->next;
1493 } while (ns != NULL);
1494 return(ret);
1495 }
1496
1497 /**
1498 * xsltShallowCopyNsNode:
1499 * @ctxt: the XSLT transformation context
1500 * @invocNode: responsible node in the stylesheet; used for error reports
1501 * @insert: the target element node in the result tree
1502 * @ns: the namespace node
1503 *
1504 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1505 *
1506 * Returns a new/existing ns-node, or NULL.
1507 */
1508 static xmlNsPtr
1509 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
1510 xmlNodePtr invocNode,
1511 xmlNodePtr insert,
1512 xmlNsPtr ns)
1513 {
1514 /*
1515 * TODO: Contrary to header comments, this is declared as int.
1516 * be modified to return a node pointer, or NULL if any error
1517 */
1518 xmlNsPtr tmpns;
1519
1520 if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
1521 return(NULL);
1522
1523 if (insert->children != NULL) {
1524 xsltTransformError(ctxt, NULL, invocNode,
1525 "Namespace nodes must be added before "
1526 "any child nodes are added to an element.\n");
1527 return(NULL);
1528 }
1529 /*
1530 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1531 * an equal prefix. We definitively won't do that.
1532 *
1533 * MSXML 4.0 and the .NET ignores ns-decls for which an
1534 * equal prefix is already in use.
1535 *
1536 * Saxon raises an error like:
1537 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1538 * nodes with the same name".
1539 *
1540 * NOTE: We'll currently follow MSXML here.
1541 * REVISIT TODO: Check if it's better to follow Saxon here.
1542 */
1543 if (ns->prefix == NULL) {
1544 /*
1545 * If we are adding ns-nodes to an element using e.g.
1546 * <xsl:copy-of select="/foo/namespace::*">, then we need
1547 * to ensure that we don't incorrectly declare a default
1548 * namespace on an element in no namespace, which otherwise
1549 * would move the element incorrectly into a namespace, if
1550 * the node tree is serialized.
1551 */
1552 if (insert->ns == NULL)
1553 goto occupied;
1554 } else if ((ns->prefix[0] == 'x') &&
1555 xmlStrEqual(ns->prefix, BAD_CAST "xml"))
1556 {
1557 /*
1558 * The XML namespace is built in.
1559 */
1560 return(NULL);
1561 }
1562
1563 if (insert->nsDef != NULL) {
1564 tmpns = insert->nsDef;
1565 do {
1566 if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
1567 if ((tmpns->prefix == ns->prefix) ||
1568 xmlStrEqual(tmpns->prefix, ns->prefix))
1569 {
1570 /*
1571 * Same prefix.
1572 */
1573 if (xmlStrEqual(tmpns->href, ns->href))
1574 return(NULL);
1575 goto occupied;
1576 }
1577 }
1578 tmpns = tmpns->next;
1579 } while (tmpns != NULL);
1580 }
1581 tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
1582 if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
1583 return(NULL);
1584 /*
1585 * Declare a new namespace.
1586 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1587 * that it will again search the already declared namespaces
1588 * for a duplicate :-/
1589 */
1590 return(xmlNewNs(insert, ns->href, ns->prefix));
1591
1592 occupied:
1593 /*
1594 * TODO: We could as well raise an error here (like Saxon does),
1595 * or at least generate a warning.
1596 */
1597 return(NULL);
1598 }
1599
1600 /**
1601 * xsltCopyTree:
1602 * @ctxt: the XSLT transformation context
1603 * @invocNode: responsible node in the stylesheet; used for error reports
1604 * @node: the element node in the source tree
1605 * @insert: the parent in the result tree
1606 * @isLRE: indicates if @node is a Literal Result Element
1607 * @topElemVisited: indicates if a top-most element was already processed
1608 *
1609 * Make a copy of the full tree under the element node @node
1610 * and insert it as last child of @insert
1611 *
1612 * NOTE: Not to be used for Literal Result Elements.
1613 *
1614 * Used by:
1615 * - xsltCopyOf()
1616 *
1617 * Returns a pointer to the new tree, or NULL in case of error
1618 */
1619 static xmlNodePtr
1620 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1621 xmlNodePtr node, xmlNodePtr insert, int isLRE,
1622 int topElemVisited)
1623 {
1624 xmlNodePtr copy;
1625
1626 if (node == NULL)
1627 return(NULL);
1628 switch (node->type) {
1629 case XML_ELEMENT_NODE:
1630 case XML_ENTITY_REF_NODE:
1631 case XML_ENTITY_NODE:
1632 case XML_PI_NODE:
1633 case XML_COMMENT_NODE:
1634 case XML_DOCUMENT_NODE:
1635 case XML_HTML_DOCUMENT_NODE:
1636 #ifdef LIBXML_DOCB_ENABLED
1637 case XML_DOCB_DOCUMENT_NODE:
1638 #endif
1639 break;
1640 case XML_TEXT_NODE: {
1641 int noenc = (node->name == xmlStringTextNoenc);
1642 return(xsltCopyTextString(ctxt, insert, node->content, noenc));
1643 }
1644 case XML_CDATA_SECTION_NODE:
1645 return(xsltCopyTextString(ctxt, insert, node->content, 0));
1646 case XML_ATTRIBUTE_NODE:
1647 return((xmlNodePtr)
1648 xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node)) ;
1649 case XML_NAMESPACE_DECL:
1650 return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
1651 insert, (xmlNsPtr) node));
1652
1653 case XML_DOCUMENT_TYPE_NODE:
1654 case XML_DOCUMENT_FRAG_NODE:
1655 case XML_NOTATION_NODE:
1656 case XML_DTD_NODE:
1657 case XML_ELEMENT_DECL:
1658 case XML_ATTRIBUTE_DECL:
1659 case XML_ENTITY_DECL:
1660 case XML_XINCLUDE_START:
1661 case XML_XINCLUDE_END:
1662 return(NULL);
1663 }
1664 if (XSLT_IS_RES_TREE_FRAG(node)) {
1665 if (node->children != NULL)
1666 copy = xsltCopyTreeList(ctxt, invocNode,
1667 node->children, insert, 0, 0);
1668 else
1669 copy = NULL;
1670 return(copy);
1671 }
1672 copy = xmlDocCopyNode(node, insert->doc, 0);
1673 if (copy != NULL) {
1674 copy->doc = ctxt->output;
1675 copy = xsltAddChild(insert, copy);
1676 if (copy == NULL) {
1677 xsltTransformError(ctxt, NULL, invocNode,
1678 "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1679 return (copy);
1680 }
1681 /*
1682 * The node may have been coalesced into another text node.
1683 */
1684 if (insert->last != copy)
1685 return(insert->last);
1686 copy->next = NULL;
1687
1688 if (node->type == XML_ELEMENT_NODE) {
1689 /*
1690 * Copy in-scope namespace nodes.
1691 *
1692 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1693 * using xmlSearchNsByHref(), this will eventually change
1694 * the prefix of an original ns-binding; thus it might
1695 * break QNames in element/attribute content.
1696 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1697 * context, plus a ns-lookup function, which writes directly
1698 * to a given list, then we wouldn't need to create/free the
1699 * nsList every time.
1700 */
1701 if ((topElemVisited == 0) &&
1702 (node->parent != NULL) &&
1703 (node->parent->type != XML_DOCUMENT_NODE) &&
1704 (node->parent->type != XML_HTML_DOCUMENT_NODE))
1705 {
1706 xmlNsPtr *nsList, *curns, ns;
1707
1708 /*
1709 * If this is a top-most element in a tree to be
1710 * copied, then we need to ensure that all in-scope
1711 * namespaces are copied over. For nodes deeper in the
1712 * tree, it is sufficient to reconcile only the ns-decls
1713 * (node->nsDef entries).
1714 */
1715
1716 nsList = xmlGetNsList(node->doc, node);
1717 if (nsList != NULL) {
1718 curns = nsList;
1719 do {
1720 /*
1721 * Search by prefix first in order to break as less
1722 * QNames in element/attribute content as possible.
1723 */
1724 ns = xmlSearchNs(insert->doc, insert,
1725 (*curns)->prefix);
1726
1727 if ((ns == NULL) ||
1728 (! xmlStrEqual(ns->href, (*curns)->href)))
1729 {
1730 ns = NULL;
1731 /*
1732 * Search by namespace name.
1733 * REVISIT TODO: Currently disabled.
1734 */
1735 #if 0
1736 ns = xmlSearchNsByHref(insert->doc,
1737 insert, (*curns)->href);
1738 #endif
1739 }
1740 if (ns == NULL) {
1741 /*
1742 * Declare a new namespace on the copied element.
1743 */
1744 ns = xmlNewNs(copy, (*curns)->href,
1745 (*curns)->prefix);
1746 /* TODO: Handle errors */
1747 }
1748 if (node->ns == *curns) {
1749 /*
1750 * If this was the original's namespace then set
1751 * the generated counterpart on the copy.
1752 */
1753 copy->ns = ns;
1754 }
1755 curns++;
1756 } while (*curns != NULL);
1757 xmlFree(nsList);
1758 }
1759 } else if (node->nsDef != NULL) {
1760 /*
1761 * Copy over all namespace declaration attributes.
1762 */
1763 if (node->nsDef != NULL) {
1764 if (isLRE)
1765 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1766 else
1767 xsltCopyNamespaceListInternal(copy, node->nsDef);
1768 }
1769 }
1770 /*
1771 * Set the namespace.
1772 */
1773 if (node->ns != NULL) {
1774 if (copy->ns == NULL) {
1775 /*
1776 * This will map copy->ns to one of the newly created
1777 * in-scope ns-decls, OR create a new ns-decl on @copy.
1778 */
1779 copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
1780 node->ns->href, node->ns->prefix, copy);
1781 }
1782 } else if ((insert->type == XML_ELEMENT_NODE) &&
1783 (insert->ns != NULL))
1784 {
1785 /*
1786 * "Undeclare" the default namespace on @copy with xmlns="".
1787 */
1788 xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
1789 }
1790 /*
1791 * Copy attribute nodes.
1792 */
1793 if (node->properties != NULL) {
1794 xsltCopyAttrListNoOverwrite(ctxt, invocNode,
1795 copy, node->properties);
1796 }
1797 if (topElemVisited == 0)
1798 topElemVisited = 1;
1799 }
1800 /*
1801 * Copy the subtree.
1802 */
1803 if (node->children != NULL) {
1804 xsltCopyTreeList(ctxt, invocNode,
1805 node->children, copy, isLRE, topElemVisited);
1806 }
1807 } else {
1808 xsltTransformError(ctxt, NULL, invocNode,
1809 "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1810 }
1811 return(copy);
1812 }
1813
1814 /************************************************************************
1815 * *
1816 * Error/fallback processing *
1817 * *
1818 ************************************************************************/
1819
1820 /**
1821 * xsltApplyFallbacks:
1822 * @ctxt: a XSLT process context
1823 * @node: the node in the source tree.
1824 * @inst: the node generating the error
1825 *
1826 * Process possible xsl:fallback nodes present under @inst
1827 *
1828 * Returns the number of xsl:fallback element found and processed
1829 */
1830 static int
1831 xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
1832 xmlNodePtr inst) {
1833
1834 xmlNodePtr child;
1835 int ret = 0;
1836
1837 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
1838 (inst->children == NULL))
1839 return(0);
1840
1841 child = inst->children;
1842 while (child != NULL) {
1843 if ((IS_XSLT_ELEM(child)) &&
1844 (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
1845 #ifdef WITH_XSLT_DEBUG_PARSING
1846 xsltGenericDebug(xsltGenericDebugContext,
1847 "applying xsl:fallback\n");
1848 #endif
1849 ret++;
1850 xsltApplySequenceConstructor(ctxt, node, child->children,
1851 NULL);
1852 }
1853 child = child->next;
1854 }
1855 return(ret);
1856 }
1857
1858 /************************************************************************
1859 * *
1860 * Default processing *
1861 * *
1862 ************************************************************************/
1863
1864 /**
1865 * xsltDefaultProcessOneNode:
1866 * @ctxt: a XSLT process context
1867 * @node: the node in the source tree.
1868 * @params: extra parameters passed to the template if any
1869 *
1870 * Process the source node with the default built-in template rule:
1871 * <xsl:template match="*|/">
1872 * <xsl:apply-templates/>
1873 * </xsl:template>
1874 *
1875 * and
1876 *
1877 * <xsl:template match="text()|@*">
1878 * <xsl:value-of select="."/>
1879 * </xsl:template>
1880 *
1881 * Note also that namespace declarations are copied directly:
1882 *
1883 * the built-in template rule is the only template rule that is applied
1884 * for namespace nodes.
1885 */
1886 static void
1887 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
1888 xsltStackElemPtr params) {
1889 xmlNodePtr copy;
1890 xmlNodePtr delete = NULL, cur;
1891 int nbchild = 0, oldSize;
1892 int childno = 0, oldPos;
1893 xsltTemplatePtr template;
1894
1895 CHECK_STOPPED;
1896 /*
1897 * Handling of leaves
1898 */
1899 switch (node->type) {
1900 case XML_DOCUMENT_NODE:
1901 case XML_HTML_DOCUMENT_NODE:
1902 case XML_ELEMENT_NODE:
1903 break;
1904 case XML_CDATA_SECTION_NODE:
1905 #ifdef WITH_XSLT_DEBUG_PROCESS
1906 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
1907 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1908 node->content));
1909 #endif
1910 copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1911 if (copy == NULL) {
1912 xsltTransformError(ctxt, NULL, node,
1913 "xsltDefaultProcessOneNode: cdata copy failed\n");
1914 }
1915 return;
1916 case XML_TEXT_NODE:
1917 #ifdef WITH_XSLT_DEBUG_PROCESS
1918 if (node->content == NULL) {
1919 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGen ericDebugContext,
1920 "xsltDefaultProcessOneNode: copy empty text\n"));
1921 return;
1922 } else {
1923 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGen ericDebugContext,
1924 "xsltDefaultProcessOneNode: copy text %s\n",
1925 node->content));
1926 }
1927 #endif
1928 copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1929 if (copy == NULL) {
1930 xsltTransformError(ctxt, NULL, node,
1931 "xsltDefaultProcessOneNode: text copy failed\n");
1932 }
1933 return;
1934 case XML_ATTRIBUTE_NODE:
1935 cur = node->children;
1936 while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
1937 cur = cur->next;
1938 if (cur == NULL) {
1939 xsltTransformError(ctxt, NULL, node,
1940 "xsltDefaultProcessOneNode: no text for attribute\n");
1941 } else {
1942 #ifdef WITH_XSLT_DEBUG_PROCESS
1943 if (cur->content == NULL) {
1944 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsl tGenericDebugContext,
1945 "xsltDefaultProcessOneNode: copy empty text\n"));
1946 } else {
1947 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsl tGenericDebugContext,
1948 "xsltDefaultProcessOneNode: copy text %s\n",
1949 cur->content));
1950 }
1951 #endif
1952 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1953 if (copy == NULL) {
1954 xsltTransformError(ctxt, NULL, node,
1955 "xsltDefaultProcessOneNode: text copy failed\n");
1956 }
1957 }
1958 return;
1959 default:
1960 return;
1961 }
1962 /*
1963 * Handling of Elements: first pass, cleanup and counting
1964 */
1965 cur = node->children;
1966 while (cur != NULL) {
1967 switch (cur->type) {
1968 case XML_TEXT_NODE:
1969 case XML_CDATA_SECTION_NODE:
1970 case XML_DOCUMENT_NODE:
1971 case XML_HTML_DOCUMENT_NODE:
1972 case XML_ELEMENT_NODE:
1973 case XML_PI_NODE:
1974 case XML_COMMENT_NODE:
1975 nbchild++;
1976 break;
1977 case XML_DTD_NODE:
1978 /* Unlink the DTD, it's still reachable using doc->intSubset */
1979 if (cur->next != NULL)
1980 cur->next->prev = cur->prev;
1981 if (cur->prev != NULL)
1982 cur->prev->next = cur->next;
1983 break;
1984 default:
1985 #ifdef WITH_XSLT_DEBUG_PROCESS
1986 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGen ericDebugContext,
1987 "xsltDefaultProcessOneNode: skipping node type %d\n",
1988 cur->type));
1989 #endif
1990 delete = cur;
1991 }
1992 cur = cur->next;
1993 if (delete != NULL) {
1994 #ifdef WITH_XSLT_DEBUG_PROCESS
1995 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
1996 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1997 #endif
1998 xmlUnlinkNode(delete);
1999 xmlFreeNode(delete);
2000 delete = NULL;
2001 }
2002 }
2003 if (delete != NULL) {
2004 #ifdef WITH_XSLT_DEBUG_PROCESS
2005 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebu gContext,
2006 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
2007 #endif
2008 xmlUnlinkNode(delete);
2009 xmlFreeNode(delete);
2010 delete = NULL;
2011 }
2012
2013 /*
2014 * Handling of Elements: second pass, actual processing
2015 *
2016 * Note that params are passed to the next template. This matches
2017 * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
2018 */
2019 oldSize = ctxt->xpathCtxt->contextSize;
2020 oldPos = ctxt->xpathCtxt->proximityPosition;
2021 cur = node->children;
2022 while (cur != NULL) {
2023 childno++;
2024 switch (cur->type) {
2025 case XML_DOCUMENT_NODE:
2026 case XML_HTML_DOCUMENT_NODE:
2027 case XML_ELEMENT_NODE:
2028 ctxt->xpathCtxt->contextSize = nbchild;
2029 ctxt->xpathCtxt->proximityPosition = childno;
2030 xsltProcessOneNode(ctxt, cur, params);
2031 break;
2032 case XML_CDATA_SECTION_NODE:
2033 template = xsltGetTemplate(ctxt, cur, NULL);
2034 if (template) {
2035 #ifdef WITH_XSLT_DEBUG_PROCESS
2036 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsl tGenericDebugContext,
2037 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2038 cur->content));
2039 #endif
2040 /*
2041 * Instantiate the xsl:template.
2042 */
2043 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2044 template, params);
2045 } else /* if (ctxt->mode == NULL) */ {
2046 #ifdef WITH_XSLT_DEBUG_PROCESS
2047 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsl tGenericDebugContext,
2048 "xsltDefaultProcessOneNode: copy CDATA %s\n",
2049 cur->content));
2050 #endif
2051 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2052 if (copy == NULL) {
2053 xsltTransformError(ctxt, NULL, cur,
2054 "xsltDefaultProcessOneNode: cdata copy failed\n");
2055 }
2056 }
2057 break;
2058 case XML_TEXT_NODE:
2059 template = xsltGetTemplate(ctxt, cur, NULL);
2060 if (template) {
2061 #ifdef WITH_XSLT_DEBUG_PROCESS
2062 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsl tGenericDebugContext,
2063 "xsltDefaultProcessOneNode: applying template for text %s\n",
2064 cur->content));
2065 #endif
2066 ctxt->xpathCtxt->contextSize = nbchild;
2067 ctxt->xpathCtxt->proximityPosition = childno;
2068 /*
2069 * Instantiate the xsl:template.
2070 */
2071 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2072 template, params);
2073 } else /* if (ctxt->mode == NULL) */ {
2074 #ifdef WITH_XSLT_DEBUG_PROCESS
2075 if (cur->content == NULL) {
2076 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug (xsltGenericDebugContext,
2077 "xsltDefaultProcessOneNode: copy empty text\n"));
2078 } else {
2079 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug (xsltGenericDebugContext,
2080 "xsltDefaultProcessOneNode: copy text %s\n",
2081 cur->content));
2082 }
2083 #endif
2084 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2085 if (copy == NULL) {
2086 xsltTransformError(ctxt, NULL, cur,
2087 "xsltDefaultProcessOneNode: text copy failed\n");
2088 }
2089 }
2090 break;
2091 case XML_PI_NODE:
2092 case XML_COMMENT_NODE:
2093 template = xsltGetTemplate(ctxt, cur, NULL);
2094 if (template) {
2095 #ifdef WITH_XSLT_DEBUG_PROCESS
2096 if (cur->type == XML_PI_NODE) {
2097 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug (xsltGenericDebugContext,
2098 "xsltDefaultProcessOneNode: template found for PI %s\n",
2099 cur->name));
2100 } else if (cur->type == XML_COMMENT_NODE) {
2101 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug (xsltGenericDebugContext,
2102 "xsltDefaultProcessOneNode: template found for comment\n")) ;
2103 }
2104 #endif
2105 ctxt->xpathCtxt->contextSize = nbchild;
2106 ctxt->xpathCtxt->proximityPosition = childno;
2107 /*
2108 * Instantiate the xsl:template.
2109 */
2110 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2111 template, params);
2112 }
2113 break;
2114 default:
2115 break;
2116 }
2117 cur = cur->next;
2118 }
2119 ctxt->xpathCtxt->contextSize = oldSize;
2120 ctxt->xpathCtxt->proximityPosition = oldPos;
2121 }
2122
2123 /**
2124 * xsltProcessOneNode:
2125 * @ctxt: a XSLT process context
2126 * @contextNode: the "current node" in the source tree
2127 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
2128 * template if any
2129 *
2130 * Process the source node.
2131 */
2132 void
2133 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
2134 xsltStackElemPtr withParams)
2135 {
2136 xsltTemplatePtr templ;
2137 xmlNodePtr oldNode;
2138
2139 templ = xsltGetTemplate(ctxt, contextNode, NULL);
2140 /*
2141 * If no template is found, apply the default rule.
2142 */
2143 if (templ == NULL) {
2144 #ifdef WITH_XSLT_DEBUG_PROCESS
2145 if (contextNode->type == XML_DOCUMENT_NODE) {
2146 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
2147 "xsltProcessOneNode: no template found for /\n"));
2148 } else if (contextNode->type == XML_CDATA_SECTION_NODE) {
2149 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
2150 "xsltProcessOneNode: no template found for CDATA\n"));
2151 } else if (contextNode->type == XML_ATTRIBUTE_NODE) {
2152 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
2153 "xsltProcessOneNode: no template found for attribute %s\n",
2154 ((xmlAttrPtr) contextNode)->name));
2155 } else {
2156 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
2157 "xsltProcessOneNode: no template found for %s\n", contextNode->name ));
2158 }
2159 #endif
2160 oldNode = ctxt->node;
2161 ctxt->node = contextNode;
2162 xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
2163 ctxt->node = oldNode;
2164 return;
2165 }
2166
2167 if (contextNode->type == XML_ATTRIBUTE_NODE) {
2168 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2169 /*
2170 * Set the "current template rule".
2171 */
2172 ctxt->currentTemplateRule = templ;
2173
2174 #ifdef WITH_XSLT_DEBUG_PROCESS
2175 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebu gContext,
2176 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2177 templ->match, contextNode->name));
2178 #endif
2179 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withPara ms);
2180
2181 ctxt->currentTemplateRule = oldCurTempRule;
2182 } else {
2183 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2184 /*
2185 * Set the "current template rule".
2186 */
2187 ctxt->currentTemplateRule = templ;
2188
2189 #ifdef WITH_XSLT_DEBUG_PROCESS
2190 if (contextNode->type == XML_DOCUMENT_NODE) {
2191 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
2192 "xsltProcessOneNode: applying template '%s' for /\n",
2193 templ->match));
2194 } else {
2195 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGeneric DebugContext,
2196 "xsltProcessOneNode: applying template '%s' for %s\n",
2197 templ->match, contextNode->name));
2198 }
2199 #endif
2200 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withPara ms);
2201
2202 ctxt->currentTemplateRule = oldCurTempRule;
2203 }
2204 }
2205
2206 static xmlNodePtr
2207 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2208 xmlNodePtr contextNode,
2209 xmlNodePtr list,
2210 xsltTemplatePtr templ,
2211 int *addCallResult)
2212 {
2213 xmlNodePtr debugedNode = NULL;
2214
2215 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2216 if (templ) {
2217 *addCallResult = xslAddCall(templ, templ->elem);
2218 } else {
2219 *addCallResult = xslAddCall(NULL, list);
2220 }
2221 switch (ctxt->debugStatus) {
2222 case XSLT_DEBUG_RUN_RESTART:
2223 case XSLT_DEBUG_QUIT:
2224 if (*addCallResult)
2225 xslDropCall();
2226 return(NULL);
2227 }
2228 if (templ) {
2229 xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2230 debugedNode = templ->elem;
2231 } else if (list) {
2232 xslHandleDebugger(list, contextNode, templ, ctxt);
2233 debugedNode = list;
2234 } else if (ctxt->inst) {
2235 xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2236 debugedNode = ctxt->inst;
2237 }
2238 }
2239 return(debugedNode);
2240 }
2241
2242 /**
2243 * xsltLocalVariablePush:
2244 * @ctxt: the transformation context
2245 * @variable: variable to be pushed to the variable stack
2246 * @level: new value for variable's level
2247 *
2248 * Places the variable onto the local variable stack
2249 *
2250 * Returns: 0 for success, -1 for any error
2251 * **NOTE:**
2252 * This is an internal routine and should not be called by users!
2253 */
2254 int
2255 xsltLocalVariablePush(xsltTransformContextPtr ctxt,
2256 xsltStackElemPtr variable,
2257 int level)
2258 {
2259 if (ctxt->varsMax == 0) {
2260 ctxt->varsMax = 10;
2261 ctxt->varsTab =
2262 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
2263 sizeof(ctxt->varsTab[0]));
2264 if (ctxt->varsTab == NULL) {
2265 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
2266 return (-1);
2267 }
2268 }
2269 if (ctxt->varsNr >= ctxt->varsMax) {
2270 ctxt->varsMax *= 2;
2271 ctxt->varsTab =
2272 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
2273 ctxt->varsMax *
2274 sizeof(ctxt->varsTab[0]));
2275 if (ctxt->varsTab == NULL) {
2276 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2277 return (-1);
2278 }
2279 }
2280 ctxt->varsTab[ctxt->varsNr++] = variable;
2281 ctxt->vars = variable;
2282 variable->level = level;
2283 return(0);
2284 }
2285
2286 /**
2287 * xsltReleaseLocalRVTs:
2288 *
2289 * Fragments which are results of extension instructions
2290 * are preserved; all other fragments are freed/cached.
2291 */
2292 static void
2293 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
2294 {
2295 xmlDocPtr cur = ctxt->localRVT, tmp;
2296
2297 if (cur == base)
2298 return;
2299 if (cur->prev != NULL)
2300 xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
2301
2302 do {
2303 tmp = cur;
2304 cur = (xmlDocPtr) cur->next;
2305 if (tmp->psvi == XSLT_RVT_LOCAL) {
2306 xsltReleaseRVT(ctxt, tmp);
2307 } else if (tmp->psvi == XSLT_RVT_GLOBAL) {
2308 xsltRegisterPersistRVT(ctxt, tmp);
2309 } else if (tmp->psvi != XSLT_RVT_FUNC_RESULT) {
2310 xmlGenericError(xmlGenericErrorContext,
2311 "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2312 tmp->psvi);
2313 }
2314 } while (cur != base);
2315
2316 if (base != NULL)
2317 base->prev = NULL;
2318 ctxt->localRVT = base;
2319 }
2320
2321 /**
2322 * xsltApplySequenceConstructor:
2323 * @ctxt: a XSLT process context
2324 * @contextNode: the "current node" in the source tree
2325 * @list: the nodes of a sequence constructor;
2326 * (plus leading xsl:param elements)
2327 * @templ: the compiled xsl:template (optional)
2328 *
2329 * Processes a sequence constructor.
2330 *
2331 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2332 * semantics of "current template rule". I.e. the field ctxt->templ
2333 * is not intended to reflect this, thus always pushed onto the
2334 * template stack.
2335 */
2336 static void
2337 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
2338 xmlNodePtr contextNode, xmlNodePtr list,
2339 xsltTemplatePtr templ)
2340 {
2341 xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2342 xmlNodePtr cur, insert, copy = NULL;
2343 int level = 0, oldVarsNr;
2344 xmlDocPtr oldLocalFragmentTop;
2345
2346 #ifdef XSLT_REFACTORED
2347 xsltStylePreCompPtr info;
2348 #endif
2349
2350 #ifdef WITH_DEBUGGER
2351 int addCallResult = 0;
2352 xmlNodePtr debuggedNode = NULL;
2353 #endif
2354
2355 if (ctxt == NULL)
2356 return;
2357
2358 #ifdef WITH_DEBUGGER
2359 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2360 debuggedNode =
2361 xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2362 list, templ, &addCallResult);
2363 if (debuggedNode == NULL)
2364 return;
2365 }
2366 #endif
2367
2368 if (list == NULL)
2369 return;
2370 CHECK_STOPPED;
2371
2372 /*
2373 * Check for infinite recursion: stop if the maximum of nested templates
2374 * is excceeded. Adjust xsltMaxDepth if you need more.
2375 */
2376 if (ctxt->depth >= ctxt->maxTemplateDepth) {
2377 xsltTransformError(ctxt, NULL, list,
2378 "xsltApplySequenceConstructor: A potential infinite template "
2379 "recursion was detected.\n"
2380 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2381 "raise the maximum number of nested template calls and "
2382 "variables/params (currently set to %d).\n",
2383 ctxt->maxTemplateDepth);
2384 xsltDebug(ctxt, contextNode, list, NULL);
2385 ctxt->state = XSLT_STATE_STOPPED;
2386 return;
2387 }
2388 ctxt->depth++;
2389
2390 oldLocalFragmentTop = ctxt->localRVT;
2391 oldInsert = insert = ctxt->insert;
2392 oldInst = oldCurInst = ctxt->inst;
2393 oldContextNode = ctxt->node;
2394 /*
2395 * Save current number of variables on the stack; new vars are popped when
2396 * exiting.
2397 */
2398 oldVarsNr = ctxt->varsNr;
2399 /*
2400 * Process the sequence constructor.
2401 */
2402 cur = list;
2403 while (cur != NULL) {
2404 ctxt->inst = cur;
2405
2406 #ifdef WITH_DEBUGGER
2407 switch (ctxt->debugStatus) {
2408 case XSLT_DEBUG_RUN_RESTART:
2409 case XSLT_DEBUG_QUIT:
2410 break;
2411
2412 }
2413 #endif
2414 /*
2415 * Test; we must have a valid insertion point.
2416 */
2417 if (insert == NULL) {
2418
2419 #ifdef WITH_XSLT_DEBUG_PROCESS
2420 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGener icDebugContext,
2421 "xsltApplySequenceConstructor: insert == NULL !\n"));
2422 #endif
2423 goto error;
2424 }
2425
2426 #ifdef WITH_DEBUGGER
2427 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2428 xslHandleDebugger(cur, contextNode, templ, ctxt);
2429 #endif
2430
2431 #ifdef XSLT_REFACTORED
2432 if (cur->type == XML_ELEMENT_NODE) {
2433 info = (xsltStylePreCompPtr) cur->psvi;
2434 /*
2435 * We expect a compiled representation on:
2436 * 1) XSLT instructions of this XSLT version (1.0)
2437 * (with a few exceptions)
2438 * 2) Literal result elements
2439 * 3) Extension instructions
2440 * 4) XSLT instructions of future XSLT versions
2441 * (forwards-compatible mode).
2442 */
2443 if (info == NULL) {
2444 /*
2445 * Handle the rare cases where we don't expect a compiled
2446 * representation on an XSLT element.
2447 */
2448 if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2449 xsltMessage(ctxt, contextNode, cur);
2450 goto skip_children;
2451 }
2452 /*
2453 * Something really went wrong:
2454 */
2455 xsltTransformError(ctxt, NULL, cur,
2456 "Internal error in xsltApplySequenceConstructor(): "
2457 "The element '%s' in the stylesheet has no compiled "
2458 "representation.\n",
2459 cur->name);
2460 goto skip_children;
2461 }
2462
2463 if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2464 xsltStyleItemLRElementInfoPtr lrInfo =
2465 (xsltStyleItemLRElementInfoPtr) info;
2466 /*
2467 * Literal result elements
2468 * --------------------------------------------------------
2469 */
2470 #ifdef WITH_XSLT_DEBUG_PROCESS
2471 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2472 xsltGenericDebug(xsltGenericDebugContext,
2473 "xsltApplySequenceConstructor: copy literal result "
2474 "element '%s'\n", cur->name));
2475 #endif
2476 /*
2477 * Copy the raw element-node.
2478 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2479 * == NULL)
2480 * goto error;
2481 */
2482 copy = xmlDocCopyNode(cur, insert->doc, 0);
2483 if (copy == NULL) {
2484 xsltTransformError(ctxt, NULL, cur,
2485 "Internal error in xsltApplySequenceConstructor(): "
2486 "Failed to copy literal result element '%s'.\n",
2487 cur->name);
2488 goto error;
2489 } else {
2490 /*
2491 * Add the element-node to the result tree.
2492 */
2493 copy->doc = ctxt->output;
2494 copy = xsltAddChild(insert, copy);
2495 /*
2496 * Create effective namespaces declarations.
2497 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2498 */
2499 if (lrInfo->effectiveNs != NULL) {
2500 xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2501 xmlNsPtr ns, lastns = NULL;
2502
2503 while (effNs != NULL) {
2504 /*
2505 * Avoid generating redundant namespace
2506 * declarations; thus lookup if there is already
2507 * such a ns-decl in the result.
2508 */
2509 ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2510 if ((ns != NULL) &&
2511 (xmlStrEqual(ns->href, effNs->nsName)))
2512 {
2513 effNs = effNs->next;
2514 continue;
2515 }
2516 ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2517 if (ns == NULL) {
2518 xsltTransformError(ctxt, NULL, cur,
2519 "Internal error in "
2520 "xsltApplySequenceConstructor(): "
2521 "Failed to copy a namespace "
2522 "declaration.\n");
2523 goto error;
2524 }
2525
2526 if (lastns == NULL)
2527 copy->nsDef = ns;
2528 else
2529 lastns->next =ns;
2530 lastns = ns;
2531
2532 effNs = effNs->next;
2533 }
2534
2535 }
2536 /*
2537 * NOTE that we don't need to apply ns-alising: this was
2538 * already done at compile-time.
2539 */
2540 if (cur->ns != NULL) {
2541 /*
2542 * If there's no such ns-decl in the result tree,
2543 * then xsltGetSpecialNamespace() will
2544 * create a ns-decl on the copied node.
2545 */
2546 copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2547 cur->ns->href, cur->ns->prefix, copy);
2548 } else {
2549 /*
2550 * Undeclare the default namespace if needed.
2551 * This can be skipped, if the result element has
2552 * no ns-decls, in which case the result element
2553 * obviously does not declare a default namespace;
2554 * AND there's either no parent, or the parent
2555 * element is in no namespace; this means there's no
2556 * default namespace is scope to care about.
2557 *
2558 * REVISIT: This might result in massive
2559 * generation of ns-decls if nodes in a default
2560 * namespaces are mixed with nodes in no namespace.
2561 *
2562 */
2563 if (copy->nsDef ||
2564 ((insert != NULL) &&
2565 (insert->type == XML_ELEMENT_NODE) &&
2566 (insert->ns != NULL)))
2567 {
2568 xsltGetSpecialNamespace(ctxt, cur,
2569 NULL, NULL, copy);
2570 }
2571 }
2572 }
2573 /*
2574 * SPEC XSLT 2.0 "Each attribute of the literal result
2575 * element, other than an attribute in the XSLT namespace,
2576 * is processed to produce an attribute for the element in
2577 * the result tree."
2578 * NOTE: See bug #341325.
2579 */
2580 if (cur->properties != NULL) {
2581 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2582 }
2583 } else if (IS_XSLT_ELEM_FAST(cur)) {
2584 /*
2585 * XSLT instructions
2586 * --------------------------------------------------------
2587 */
2588 if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2589 /*
2590 * We hit an unknown XSLT element.
2591 * Try to apply one of the fallback cases.
2592 */
2593 ctxt->insert = insert;
2594 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2595 xsltTransformError(ctxt, NULL, cur,
2596 "The is no fallback behaviour defined for "
2597 "the unknown XSLT element '%s'.\n",
2598 cur->name);
2599 }
2600 ctxt->insert = oldInsert;
2601 } else if (info->func != NULL) {
2602 /*
2603 * Execute the XSLT instruction.
2604 */
2605 ctxt->insert = insert;
2606
2607 info->func(ctxt, contextNode, cur,
2608 (xsltElemPreCompPtr) info);
2609
2610 /*
2611 * Cleanup temporary tree fragments.
2612 */
2613 if (oldLocalFragmentTop != ctxt->localRVT)
2614 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2615
2616 ctxt->insert = oldInsert;
2617 } else if (info->type == XSLT_FUNC_VARIABLE) {
2618 xsltStackElemPtr tmpvar = ctxt->vars;
2619
2620 xsltParseStylesheetVariable(ctxt, cur);
2621
2622 if (tmpvar != ctxt->vars) {
2623 /*
2624 * TODO: Using a @tmpvar is an annoying workaround, but
2625 * the current mechanisms do not provide any other way
2626 * of knowing if the var was really pushed onto the
2627 * stack.
2628 */
2629 ctxt->vars->level = level;
2630 }
2631 } else if (info->type == XSLT_FUNC_MESSAGE) {
2632 /*
2633 * TODO: Won't be hit, since we don't compile xsl:message.
2634 */
2635 xsltMessage(ctxt, contextNode, cur);
2636 } else {
2637 xsltTransformError(ctxt, NULL, cur,
2638 "Unexpected XSLT element '%s'.\n", cur->name);
2639 }
2640 goto skip_children;
2641
2642 } else {
2643 xsltTransformFunction func;
2644 /*
2645 * Extension intructions (elements)
2646 * --------------------------------------------------------
2647 */
2648 if (cur->psvi == xsltExtMarker) {
2649 /*
2650 * The xsltExtMarker was set during the compilation
2651 * of extension instructions if there was no registered
2652 * handler for this specific extension function at
2653 * compile-time.
2654 * Libxslt will now lookup if a handler is
2655 * registered in the context of this transformation.
2656 */
2657 func = (xsltTransformFunction)
2658 xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2659 } else
2660 func = ((xsltElemPreCompPtr) cur->psvi)->func;
2661
2662 if (func == NULL) {
2663 /*
2664 * No handler available.
2665 * Try to execute fallback behaviour via xsl:fallback.
2666 */
2667 #ifdef WITH_XSLT_DEBUG_PROCESS
2668 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2669 xsltGenericDebug(xsltGenericDebugContext,
2670 "xsltApplySequenceConstructor: unknown extension %s\ n",
2671 cur->name));
2672 #endif
2673 ctxt->insert = insert;
2674 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2675 xsltTransformError(ctxt, NULL, cur,
2676 "Unknown extension instruction '{%s}%s'.\n",
2677 cur->ns->href, cur->name);
2678 }
2679 ctxt->insert = oldInsert;
2680 } else {
2681 /*
2682 * Execute the handler-callback.
2683 */
2684 #ifdef WITH_XSLT_DEBUG_PROCESS
2685 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(x sltGenericDebugContext,
2686 "xsltApplySequenceConstructor: extension construct %s\n" ,
2687 cur->name));
2688 #endif
2689 /*
2690 * Disable the xsltCopyTextString optimization for
2691 * extension elements. Extensions could append text using
2692 * xmlAddChild which will free the buffer pointed to by
2693 * 'lasttext'. This buffer could later be reallocated with
2694 * a different size than recorded in 'lasttsize'. See bug
2695 * #777432.
2696 */
2697 if (cur->psvi == xsltExtMarker) {
2698 ctxt->lasttext = NULL;
2699 }
2700
2701 ctxt->insert = insert;
2702
2703 func(ctxt, contextNode, cur, cur->psvi);
2704
2705 /*
2706 * Cleanup temporary tree fragments.
2707 */
2708 if (oldLocalFragmentTop != ctxt->localRVT)
2709 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2710
2711 ctxt->insert = oldInsert;
2712 }
2713 goto skip_children;
2714 }
2715
2716 } else if (XSLT_IS_TEXT_NODE(cur)) {
2717 /*
2718 * Text
2719 * ------------------------------------------------------------
2720 */
2721 #ifdef WITH_XSLT_DEBUG_PROCESS
2722 if (cur->name == xmlStringTextNoenc) {
2723 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2724 xsltGenericDebug(xsltGenericDebugContext,
2725 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2726 cur->content));
2727 } else {
2728 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2729 xsltGenericDebug(xsltGenericDebugContext,
2730 "xsltApplySequenceConstructor: copy text '%s'\n",
2731 cur->content));
2732 }
2733 #endif
2734 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2735 goto error;
2736 }
2737
2738 #else /* XSLT_REFACTORED */
2739
2740 if (IS_XSLT_ELEM(cur)) {
2741 /*
2742 * This is an XSLT node
2743 */
2744 xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
2745
2746 if (info == NULL) {
2747 if (IS_XSLT_NAME(cur, "message")) {
2748 xsltMessage(ctxt, contextNode, cur);
2749 } else {
2750 /*
2751 * That's an error try to apply one of the fallback cases
2752 */
2753 ctxt->insert = insert;
2754 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2755 xsltGenericError(xsltGenericErrorContext,
2756 "xsltApplySequenceConstructor: %s was not compiled\n ",
2757 cur->name);
2758 }
2759 ctxt->insert = oldInsert;
2760 }
2761 goto skip_children;
2762 }
2763
2764 if (info->func != NULL) {
2765 oldCurInst = ctxt->inst;
2766 ctxt->inst = cur;
2767 ctxt->insert = insert;
2768
2769 info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2770
2771 /*
2772 * Cleanup temporary tree fragments.
2773 */
2774 if (oldLocalFragmentTop != ctxt->localRVT)
2775 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2776
2777 ctxt->insert = oldInsert;
2778 ctxt->inst = oldCurInst;
2779 goto skip_children;
2780 }
2781
2782 if (IS_XSLT_NAME(cur, "variable")) {
2783 xsltStackElemPtr tmpvar = ctxt->vars;
2784
2785 oldCurInst = ctxt->inst;
2786 ctxt->inst = cur;
2787
2788 xsltParseStylesheetVariable(ctxt, cur);
2789
2790 ctxt->inst = oldCurInst;
2791
2792 if (tmpvar != ctxt->vars) {
2793 /*
2794 * TODO: Using a @tmpvar is an annoying workaround, but
2795 * the current mechanisms do not provide any other way
2796 * of knowing if the var was really pushed onto the
2797 * stack.
2798 */
2799 ctxt->vars->level = level;
2800 }
2801 } else if (IS_XSLT_NAME(cur, "message")) {
2802 xsltMessage(ctxt, contextNode, cur);
2803 } else {
2804 xsltTransformError(ctxt, NULL, cur,
2805 "Unexpected XSLT element '%s'.\n", cur->name);
2806 }
2807 goto skip_children;
2808 } else if ((cur->type == XML_TEXT_NODE) ||
2809 (cur->type == XML_CDATA_SECTION_NODE)) {
2810
2811 /*
2812 * This text comes from the stylesheet
2813 * For stylesheets, the set of whitespace-preserving
2814 * element names consists of just xsl:text.
2815 */
2816 #ifdef WITH_XSLT_DEBUG_PROCESS
2817 if (cur->type == XML_CDATA_SECTION_NODE) {
2818 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltG enericDebugContext,
2819 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2820 cur->content));
2821 } else if (cur->name == xmlStringTextNoenc) {
2822 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltG enericDebugContext,
2823 "xsltApplySequenceConstructor: copy unescaped t ext %s\n",
2824 cur->content));
2825 } else {
2826 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltG enericDebugContext,
2827 "xsltApplySequenceConstructor: copy text %s\n",
2828 cur->content));
2829 }
2830 #endif
2831 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2832 goto error;
2833 } else if ((cur->type == XML_ELEMENT_NODE) &&
2834 (cur->ns != NULL) && (cur->psvi != NULL)) {
2835 xsltTransformFunction function;
2836
2837 oldCurInst = ctxt->inst;
2838 ctxt->inst = cur;
2839 /*
2840 * Flagged as an extension element
2841 */
2842 if (cur->psvi == xsltExtMarker)
2843 function = (xsltTransformFunction)
2844 xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2845 else
2846 function = ((xsltElemPreCompPtr) cur->psvi)->func;
2847
2848 if (function == NULL) {
2849 xmlNodePtr child;
2850 int found = 0;
2851
2852 #ifdef WITH_XSLT_DEBUG_PROCESS
2853 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltG enericDebugContext,
2854 "xsltApplySequenceConstructor: unknown extension %s\n",
2855 cur->name));
2856 #endif
2857 /*
2858 * Search if there are fallbacks
2859 */
2860 child = cur->children;
2861 while (child != NULL) {
2862 if ((IS_XSLT_ELEM(child)) &&
2863 (IS_XSLT_NAME(child, "fallback")))
2864 {
2865 found = 1;
2866 xsltApplySequenceConstructor(ctxt, contextNode,
2867 child->children, NULL);
2868 }
2869 child = child->next;
2870 }
2871
2872 if (!found) {
2873 xsltTransformError(ctxt, NULL, cur,
2874 "xsltApplySequenceConstructor: failed to find extension %s\n",
2875 cur->name);
2876 }
2877 } else {
2878 #ifdef WITH_XSLT_DEBUG_PROCESS
2879 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltG enericDebugContext,
2880 "xsltApplySequenceConstructor: extension construct %s\n",
2881 cur->name));
2882 #endif
2883
2884 /*
2885 * Disable the xsltCopyTextString optimization for
2886 * extension elements. Extensions could append text using
2887 * xmlAddChild which will free the buffer pointed to by
2888 * 'lasttext'. This buffer could later be reallocated with
2889 * a different size than recorded in 'lasttsize'. See bug
2890 * #777432.
2891 */
2892 if (cur->psvi == xsltExtMarker) {
2893 ctxt->lasttext = NULL;
2894 }
2895
2896 ctxt->insert = insert;
2897
2898 function(ctxt, contextNode, cur, cur->psvi);
2899 /*
2900 * Cleanup temporary tree fragments.
2901 */
2902 if (oldLocalFragmentTop != ctxt->localRVT)
2903 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2904
2905 ctxt->insert = oldInsert;
2906
2907 }
2908 ctxt->inst = oldCurInst;
2909 goto skip_children;
2910 } else if (cur->type == XML_ELEMENT_NODE) {
2911 #ifdef WITH_XSLT_DEBUG_PROCESS
2912 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGener icDebugContext,
2913 "xsltApplySequenceConstructor: copy node %s\n",
2914 cur->name));
2915 #endif
2916 oldCurInst = ctxt->inst;
2917 ctxt->inst = cur;
2918
2919 if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2920 goto error;
2921 /*
2922 * Add extra namespaces inherited from the current template
2923 * if we are in the first level children and this is a
2924 * "real" template.
2925 */
2926 if ((templ != NULL) && (oldInsert == insert) &&
2927 (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2928 int i;
2929 xmlNsPtr ns, ret;
2930
2931 for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2932 const xmlChar *URI = NULL;
2933 xsltStylesheetPtr style;
2934 ns = ctxt->templ->inheritedNs[i];
2935
2936 /* Note that the XSLT namespace was already excluded
2937 * in xsltGetInheritedNsList().
2938 */
2939 #if 0
2940 if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2941 continue;
2942 #endif
2943 style = ctxt->style;
2944 while (style != NULL) {
2945 if (style->nsAliases != NULL)
2946 URI = (const xmlChar *)
2947 xmlHashLookup(style->nsAliases, ns->href);
2948 if (URI != NULL)
2949 break;
2950
2951 style = xsltNextImport(style);
2952 }
2953 if (URI == UNDEFINED_DEFAULT_NS)
2954 continue;
2955 if (URI == NULL)
2956 URI = ns->href;
2957 /*
2958 * TODO: The following will still be buggy for the
2959 * non-refactored code.
2960 */
2961 ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2962 if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2963 {
2964 xmlNewNs(copy, URI, ns->prefix);
2965 }
2966 }
2967 if (copy->ns != NULL) {
2968 /*
2969 * Fix the node namespace if needed
2970 */
2971 copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2972 }
2973 }
2974 /*
2975 * all the attributes are directly inherited
2976 */
2977 if (cur->properties != NULL) {
2978 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2979 }
2980 ctxt->inst = oldCurInst;
2981 }
2982 #endif /* else of XSLT_REFACTORED */
2983
2984 /*
2985 * Descend into content in document order.
2986 */
2987 if (cur->children != NULL) {
2988 if (cur->children->type != XML_ENTITY_DECL) {
2989 cur = cur->children;
2990 level++;
2991 if (copy != NULL)
2992 insert = copy;
2993 continue;
2994 }
2995 }
2996
2997 skip_children:
2998 /*
2999 * If xslt:message was just processed, we might have hit a
3000 * terminate='yes'; if so, then break the loop and clean up.
3001 * TODO: Do we need to check this also before trying to descend
3002 * into the content?
3003 */
3004 if (ctxt->state == XSLT_STATE_STOPPED)
3005 break;
3006 if (cur->next != NULL) {
3007 cur = cur->next;
3008 continue;
3009 }
3010
3011 do {
3012 cur = cur->parent;
3013 level--;
3014 /*
3015 * Pop variables/params (xsl:variable and xsl:param).
3016 */
3017 if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
3018 xsltLocalVariablePop(ctxt, oldVarsNr, level);
3019 }
3020
3021 insert = insert->parent;
3022 if (cur == NULL)
3023 break;
3024 if (cur == list->parent) {
3025 cur = NULL;
3026 break;
3027 }
3028 if (cur->next != NULL) {
3029 cur = cur->next;
3030 break;
3031 }
3032 } while (cur != NULL);
3033 }
3034
3035 error:
3036 /*
3037 * In case of errors: pop remaining variables.
3038 */
3039 if (ctxt->varsNr > oldVarsNr)
3040 xsltLocalVariablePop(ctxt, oldVarsNr, -1);
3041
3042 ctxt->node = oldContextNode;
3043 ctxt->inst = oldInst;
3044 ctxt->insert = oldInsert;
3045
3046 ctxt->depth--;
3047
3048 #ifdef WITH_DEBUGGER
3049 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3050 xslDropCall();
3051 }
3052 #endif
3053 }
3054
3055 /*
3056 * xsltApplyXSLTTemplate:
3057 * @ctxt: a XSLT transformation context
3058 * @contextNode: the node in the source tree.
3059 * @list: the nodes of a sequence constructor;
3060 * (plus leading xsl:param elements)
3061 * @templ: the compiled xsl:template declaration;
3062 * NULL if a sequence constructor
3063 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
3064 *
3065 * Called by:
3066 * - xsltApplyImports()
3067 * - xsltCallTemplate()
3068 * - xsltDefaultProcessOneNode()
3069 * - xsltProcessOneNode()
3070 */
3071 static void
3072 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
3073 xmlNodePtr contextNode,
3074 xmlNodePtr list,
3075 xsltTemplatePtr templ,
3076 xsltStackElemPtr withParams)
3077 {
3078 int oldVarsBase = 0;
3079 long start = 0;
3080 xmlNodePtr cur;
3081 xsltStackElemPtr tmpParam = NULL;
3082 xmlDocPtr oldUserFragmentTop;
3083
3084 #ifdef XSLT_REFACTORED
3085 xsltStyleItemParamPtr iparam;
3086 #else
3087 xsltStylePreCompPtr iparam;
3088 #endif
3089
3090 #ifdef WITH_DEBUGGER
3091 int addCallResult = 0;
3092 #endif
3093
3094 if (ctxt == NULL)
3095 return;
3096 if (templ == NULL) {
3097 xsltTransformError(ctxt, NULL, list,
3098 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3099 return;
3100 }
3101
3102 #ifdef WITH_DEBUGGER
3103 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
3104 if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
3105 list, templ, &addCallResult) == NULL)
3106 return;
3107 }
3108 #endif
3109
3110 if (list == NULL)
3111 return;
3112 CHECK_STOPPED;
3113
3114 if (ctxt->varsNr >= ctxt->maxTemplateVars)
3115 {
3116 xsltTransformError(ctxt, NULL, list,
3117 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3118 "was detected.\n"
3119 "You can adjust maxTemplateVars (--maxvars) in order to "
3120 "raise the maximum number of variables/params (currently set to %d). \n",
3121 ctxt->maxTemplateVars);
3122 xsltDebug(ctxt, contextNode, list, NULL);
3123 ctxt->state = XSLT_STATE_STOPPED;
3124 return;
3125 }
3126
3127 oldUserFragmentTop = ctxt->tmpRVT;
3128 ctxt->tmpRVT = NULL;
3129
3130 /*
3131 * Initiate a distinct scope of local params/variables.
3132 */
3133 oldVarsBase = ctxt->varsBase;
3134 ctxt->varsBase = ctxt->varsNr;
3135
3136 ctxt->node = contextNode;
3137 if (ctxt->profile) {
3138 templ->nbCalls++;
3139 start = xsltTimestamp();
3140 profPush(ctxt, 0);
3141 profCallgraphAdd(templ, ctxt->templ);
3142 }
3143 /*
3144 * Push the xsl:template declaration onto the stack.
3145 */
3146 templPush(ctxt, templ);
3147
3148 #ifdef WITH_XSLT_DEBUG_PROCESS
3149 if (templ->name != NULL)
3150 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDe bugContext,
3151 "applying xsl:template '%s'\n", templ->name));
3152 #endif
3153 /*
3154 * Process xsl:param instructions and skip those elements for
3155 * further processing.
3156 */
3157 cur = list;
3158 do {
3159 if (cur->type == XML_TEXT_NODE) {
3160 cur = cur->next;
3161 continue;
3162 }
3163 if ((cur->type != XML_ELEMENT_NODE) ||
3164 (cur->name[0] != 'p') ||
3165 (cur->psvi == NULL) ||
3166 (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
3167 (! IS_XSLT_ELEM(cur)))
3168 {
3169 break;
3170 }
3171
3172 list = cur->next;
3173
3174 #ifdef XSLT_REFACTORED
3175 iparam = (xsltStyleItemParamPtr) cur->psvi;
3176 #else
3177 iparam = (xsltStylePreCompPtr) cur->psvi;
3178 #endif
3179
3180 /*
3181 * Substitute xsl:param for a given xsl:with-param.
3182 * Since the XPath expression will reference the params/vars
3183 * by index, we need to slot the xsl:with-params in the
3184 * order of encountered xsl:params to keep the sequence of
3185 * params/variables in the stack exactly as it was at
3186 * compile time,
3187 */
3188 tmpParam = NULL;
3189 if (withParams) {
3190 tmpParam = withParams;
3191 do {
3192 if ((tmpParam->name == (iparam->name)) &&
3193 (tmpParam->nameURI == (iparam->ns)))
3194 {
3195 /*
3196 * Push the caller-parameter.
3197 */
3198 xsltLocalVariablePush(ctxt, tmpParam, -1);
3199 break;
3200 }
3201 tmpParam = tmpParam->next;
3202 } while (tmpParam != NULL);
3203 }
3204 /*
3205 * Push the xsl:param.
3206 */
3207 if (tmpParam == NULL) {
3208 /*
3209 * Note that we must assume that the added parameter
3210 * has a @depth of 0.
3211 */
3212 xsltParseStylesheetParam(ctxt, cur);
3213 }
3214 cur = cur->next;
3215 } while (cur != NULL);
3216 /*
3217 * Process the sequence constructor.
3218 */
3219 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3220
3221 /*
3222 * Remove remaining xsl:param and xsl:with-param items from
3223 * the stack. Don't free xsl:with-param items.
3224 */
3225 if (ctxt->varsNr > ctxt->varsBase)
3226 xsltTemplateParamsCleanup(ctxt);
3227 ctxt->varsBase = oldVarsBase;
3228
3229 /*
3230 * Release user-created fragments stored in the scope
3231 * of xsl:template. Note that this mechanism is deprecated:
3232 * user code should now use xsltRegisterLocalRVT() instead
3233 * of the obsolete xsltRegisterTmpRVT().
3234 */
3235 if (ctxt->tmpRVT) {
3236 xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3237
3238 while (curdoc != NULL) {
3239 tmp = curdoc;
3240 curdoc = (xmlDocPtr) curdoc->next;
3241 xsltReleaseRVT(ctxt, tmp);
3242 }
3243 }
3244 ctxt->tmpRVT = oldUserFragmentTop;
3245
3246 /*
3247 * Pop the xsl:template declaration from the stack.
3248 */
3249 templPop(ctxt);
3250 if (ctxt->profile) {
3251 long spent, child, total, end;
3252
3253 end = xsltTimestamp();
3254 child = profPop(ctxt);
3255 total = end - start;
3256 spent = total - child;
3257 if (spent <= 0) {
3258 /*
3259 * Not possible unless the original calibration failed
3260 * we can try to correct it on the fly.
3261 */
3262 xsltCalibrateAdjust(spent);
3263 spent = 0;
3264 }
3265
3266 templ->time += spent;
3267 if (ctxt->profNr > 0)
3268 ctxt->profTab[ctxt->profNr - 1] += total;
3269 }
3270
3271 #ifdef WITH_DEBUGGER
3272 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3273 xslDropCall();
3274 }
3275 #endif
3276 }
3277
3278
3279 /**
3280 * xsltApplyOneTemplate:
3281 * @ctxt: a XSLT process context
3282 * @contextNode: the node in the source tree.
3283 * @list: the nodes of a sequence constructor
3284 * @templ: not used
3285 * @params: a set of parameters (xsl:param) or NULL
3286 *
3287 * Processes a sequence constructor on the current node in the source tree.
3288 *
3289 * @params are the already computed variable stack items; this function
3290 * pushes them on the variable stack, and pops them before exiting; it's
3291 * left to the caller to free or reuse @params afterwards. The initial
3292 * states of the variable stack will always be restored before this
3293 * function exits.
3294 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3295 * variables already on the stack are visible to the process. The caller's
3296 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3297 *
3298 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3299 * provide a @templ); a non-NULL @templ might raise an error in the future.
3300 *
3301 * BIG NOTE: This function is not intended to process the content of an
3302 * xsl:template; it does not expect xsl:param instructions in @list and
3303 * will report errors if found.
3304 *
3305 * Called by:
3306 * - xsltEvalVariable() (variables.c)
3307 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3308 */
3309 void
3310 xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
3311 xmlNodePtr contextNode,
3312 xmlNodePtr list,
3313 xsltTemplatePtr templ ATTRIBUTE_UNUSED,
3314 xsltStackElemPtr params)
3315 {
3316 if ((ctxt == NULL) || (list == NULL))
3317 return;
3318 CHECK_STOPPED;
3319
3320 if (params) {
3321 /*
3322 * This code should be obsolete - was previously used
3323 * by libexslt/functions.c, but due to bug 381319 the
3324 * logic there was changed.
3325 */
3326 int oldVarsNr = ctxt->varsNr;
3327
3328 /*
3329 * Push the given xsl:param(s) onto the variable stack.
3330 */
3331 while (params != NULL) {
3332 xsltLocalVariablePush(ctxt, params, -1);
3333 params = params->next;
3334 }
3335 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3336 /*
3337 * Pop the given xsl:param(s) from the stack but don't free them.
3338 */
3339 xsltLocalVariablePop(ctxt, oldVarsNr, -2);
3340 } else
3341 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3342 }
3343
3344 /************************************************************************
3345 * *
3346 * XSLT-1.1 extensions *
3347 * *
3348 ************************************************************************/
3349
3350 /**
3351 * xsltDocumentElem:
3352 * @ctxt: an XSLT processing context
3353 * @node: The current node
3354 * @inst: the instruction in the stylesheet
3355 * @castedComp: precomputed information
3356 *
3357 * Process an EXSLT/XSLT-1.1 document element
3358 */
3359 void
3360 xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
3361 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
3362 {
3363 #ifdef XSLT_REFACTORED
3364 xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
3365 #else
3366 xsltStylePreCompPtr comp = castedComp;
3367 #endif
3368 xsltStylesheetPtr style = NULL;
3369 int ret;
3370 xmlChar *filename = NULL, *prop, *elements;
3371 xmlChar *element, *end;
3372 xmlDocPtr res = NULL;
3373 xmlDocPtr oldOutput;
3374 xmlNodePtr oldInsert, root;
3375 const char *oldOutputFile;
3376 xsltOutputType oldType;
3377 xmlChar *URL = NULL;
3378 const xmlChar *method;
3379 const xmlChar *doctypePublic;
3380 const xmlChar *doctypeSystem;
3381 const xmlChar *version;
3382 const xmlChar *encoding;
3383 int redirect_write_append = 0;
3384
3385 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
3386 return;
3387
3388 if (comp->filename == NULL) {
3389
3390 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
3391 /*
3392 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3393 * (http://icl.com/saxon)
3394 * The @file is in no namespace.
3395 */
3396 #ifdef WITH_XSLT_DEBUG_EXTRA
3397 xsltGenericDebug(xsltGenericDebugContext,
3398 "Found saxon:output extension\n");
3399 #endif
3400 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3401 (const xmlChar *) "file",
3402 XSLT_SAXON_NAMESPACE);
3403
3404 if (URL == NULL)
3405 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3406 (const xmlChar *) "href",
3407 XSLT_SAXON_NAMESPACE);
3408 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
3409 #ifdef WITH_XSLT_DEBUG_EXTRA
3410 xsltGenericDebug(xsltGenericDebugContext,
3411 "Found xalan:write extension\n");
3412 #endif
3413 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3414 (const xmlChar *)
3415 "select",
3416 XSLT_XALAN_NAMESPACE);
3417 if (URL != NULL) {
3418 xmlXPathCompExprPtr cmp;
3419 xmlChar *val;
3420
3421 /*
3422 * Trying to handle bug #59212
3423 * The value of the "select" attribute is an
3424 * XPath expression.
3425 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirec t)
3426 */
3427 cmp = xmlXPathCompile(URL);
3428 val = xsltEvalXPathString(ctxt, cmp);
3429 xmlXPathFreeCompExpr(cmp);
3430 xmlFree(URL);
3431 URL = val;
3432 }
3433 if (URL == NULL)
3434 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3435 (const xmlChar *)
3436 "file",
3437 XSLT_XALAN_NAMESPACE);
3438 if (URL == NULL)
3439 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3440 (const xmlChar *)
3441 "href",
3442 XSLT_XALAN_NAMESPACE);
3443 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
3444 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3445 (const xmlChar *) "href",
3446 NULL);
3447 }
3448
3449 } else {
3450 URL = xmlStrdup(comp->filename);
3451 }
3452
3453 if (URL == NULL) {
3454 xsltTransformError(ctxt, NULL, inst,
3455 "xsltDocumentElem: href/URI-Reference not found\n");
3456 return;
3457 }
3458
3459 /*
3460 * If the computation failed, it's likely that the URL wasn't escaped
3461 */
3462 filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
3463 if (filename == NULL) {
3464 xmlChar *escURL;
3465
3466 escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
3467 if (escURL != NULL) {
3468 filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
3469 xmlFree(escURL);
3470 }
3471 }
3472
3473 if (filename == NULL) {
3474 xsltTransformError(ctxt, NULL, inst,
3475 "xsltDocumentElem: URL computation failed for %s\n",
3476 URL);
3477 xmlFree(URL);
3478 return;
3479 }
3480
3481 /*
3482 * Security checking: can we write to this resource
3483 */
3484 if (ctxt->sec != NULL) {
3485 ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
3486 if (ret == 0) {
3487 xsltTransformError(ctxt, NULL, inst,
3488 "xsltDocumentElem: write rights for %s denied\n",
3489 filename);
3490 xmlFree(URL);
3491 xmlFree(filename);
3492 return;
3493 }
3494 }
3495
3496 oldOutputFile = ctxt->outputFile;
3497 oldOutput = ctxt->output;
3498 oldInsert = ctxt->insert;
3499 oldType = ctxt->type;
3500 ctxt->outputFile = (const char *) filename;
3501
3502 style = xsltNewStylesheet();
3503 if (style == NULL) {
3504 xsltTransformError(ctxt, NULL, inst,
3505 "xsltDocumentElem: out of memory\n");
3506 goto error;
3507 }
3508
3509 /*
3510 * Version described in 1.1 draft allows full parameterization
3511 * of the output.
3512 */
3513 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3514 (const xmlChar *) "version",
3515 NULL);
3516 if (prop != NULL) {
3517 if (style->version != NULL)
3518 xmlFree(style->version);
3519 style->version = prop;
3520 }
3521 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3522 (const xmlChar *) "encoding",
3523 NULL);
3524 if (prop != NULL) {
3525 if (style->encoding != NULL)
3526 xmlFree(style->encoding);
3527 style->encoding = prop;
3528 }
3529 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3530 (const xmlChar *) "method",
3531 NULL);
3532 if (prop != NULL) {
3533 const xmlChar *URI;
3534
3535 if (style->method != NULL)
3536 xmlFree(style->method);
3537 style->method = NULL;
3538 if (style->methodURI != NULL)
3539 xmlFree(style->methodURI);
3540 style->methodURI = NULL;
3541
3542 URI = xsltGetQNameURI(inst, &prop);
3543 if (prop == NULL) {
3544 if (style != NULL) style->errors++;
3545 } else if (URI == NULL) {
3546 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3547 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
3548 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
3549 style->method = prop;
3550 } else {
3551 xsltTransformError(ctxt, NULL, inst,
3552 "invalid value for method: %s\n", prop);
3553 if (style != NULL) style->warnings++;
3554 }
3555 } else {
3556 style->method = prop;
3557 style->methodURI = xmlStrdup(URI);
3558 }
3559 }
3560 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3561 (const xmlChar *)
3562 "doctype-system", NULL);
3563 if (prop != NULL) {
3564 if (style->doctypeSystem != NULL)
3565 xmlFree(style->doctypeSystem);
3566 style->doctypeSystem = prop;
3567 }
3568 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3569 (const xmlChar *)
3570 "doctype-public", NULL);
3571 if (prop != NULL) {
3572 if (style->doctypePublic != NULL)
3573 xmlFree(style->doctypePublic);
3574 style->doctypePublic = prop;
3575 }
3576 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3577 (const xmlChar *) "standalone",
3578 NULL);
3579 if (prop != NULL) {
3580 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3581 style->standalone = 1;
3582 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3583 style->standalone = 0;
3584 } else {
3585 xsltTransformError(ctxt, NULL, inst,
3586 "invalid value for standalone: %s\n",
3587 prop);
3588 if (style != NULL) style->warnings++;
3589 }
3590 xmlFree(prop);
3591 }
3592
3593 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3594 (const xmlChar *) "indent",
3595 NULL);
3596 if (prop != NULL) {
3597 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3598 style->indent = 1;
3599 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3600 style->indent = 0;
3601 } else {
3602 xsltTransformError(ctxt, NULL, inst,
3603 "invalid value for indent: %s\n", prop);
3604 if (style != NULL) style->warnings++;
3605 }
3606 xmlFree(prop);
3607 }
3608
3609 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3610 (const xmlChar *)
3611 "omit-xml-declaration",
3612 NULL);
3613 if (prop != NULL) {
3614 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3615 style->omitXmlDeclaration = 1;
3616 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3617 style->omitXmlDeclaration = 0;
3618 } else {
3619 xsltTransformError(ctxt, NULL, inst,
3620 "invalid value for omit-xml-declaration: %s\n",
3621 prop);
3622 if (style != NULL) style->warnings++;
3623 }
3624 xmlFree(prop);
3625 }
3626
3627 elements = xsltEvalAttrValueTemplate(ctxt, inst,
3628 (const xmlChar *)
3629 "cdata-section-elements",
3630 NULL);
3631 if (elements != NULL) {
3632 if (style->stripSpaces == NULL)
3633 style->stripSpaces = xmlHashCreate(10);
3634 if (style->stripSpaces == NULL)
3635 return;
3636
3637 element = elements;
3638 while (*element != 0) {
3639 while (IS_BLANK_CH(*element))
3640 element++;
3641 if (*element == 0)
3642 break;
3643 end = element;
3644 while ((*end != 0) && (!IS_BLANK_CH(*end)))
3645 end++;
3646 element = xmlStrndup(element, end - element);
3647 if (element) {
3648 const xmlChar *URI;
3649
3650 #ifdef WITH_XSLT_DEBUG_PARSING
3651 xsltGenericDebug(xsltGenericDebugContext,
3652 "add cdata section output element %s\n",
3653 element);
3654 #endif
3655 URI = xsltGetQNameURI(inst, &element);
3656
3657 xmlHashAddEntry2(style->stripSpaces, element, URI,
3658 (xmlChar *) "cdata");
3659 xmlFree(element);
3660 }
3661 element = end;
3662 }
3663 xmlFree(elements);
3664 }
3665
3666 /*
3667 * Create a new document tree and process the element template
3668 */
3669 XSLT_GET_IMPORT_PTR(method, style, method)
3670 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3671 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3672 XSLT_GET_IMPORT_PTR(version, style, version)
3673 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
3674
3675 if ((method != NULL) &&
3676 (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3677 if (xmlStrEqual(method, (const xmlChar *) "html")) {
3678 ctxt->type = XSLT_OUTPUT_HTML;
3679 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3680 res = htmlNewDoc(doctypeSystem, doctypePublic);
3681 else {
3682 if (version != NULL) {
3683 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3684 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3685 #endif
3686 }
3687 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3688 }
3689 if (res == NULL)
3690 goto error;
3691 res->dict = ctxt->dict;
3692 xmlDictReference(res->dict);
3693 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3694 xsltTransformError(ctxt, NULL, inst,
3695 "xsltDocumentElem: unsupported method xhtml\n");
3696 ctxt->type = XSLT_OUTPUT_HTML;
3697 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3698 if (res == NULL)
3699 goto error;
3700 res->dict = ctxt->dict;
3701 xmlDictReference(res->dict);
3702 } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3703 ctxt->type = XSLT_OUTPUT_TEXT;
3704 res = xmlNewDoc(style->version);
3705 if (res == NULL)
3706 goto error;
3707 res->dict = ctxt->dict;
3708 xmlDictReference(res->dict);
3709 #ifdef WITH_XSLT_DEBUG
3710 xsltGenericDebug(xsltGenericDebugContext,
3711 "reusing transformation dict for output\n");
3712 #endif
3713 } else {
3714 xsltTransformError(ctxt, NULL, inst,
3715 "xsltDocumentElem: unsupported method (%s)\n",
3716 method);
3717 goto error;
3718 }
3719 } else {
3720 ctxt->type = XSLT_OUTPUT_XML;
3721 res = xmlNewDoc(style->version);
3722 if (res == NULL)
3723 goto error;
3724 res->dict = ctxt->dict;
3725 xmlDictReference(res->dict);
3726 #ifdef WITH_XSLT_DEBUG
3727 xsltGenericDebug(xsltGenericDebugContext,
3728 "reusing transformation dict for output\n");
3729 #endif
3730 }
3731 res->charset = XML_CHAR_ENCODING_UTF8;
3732 if (encoding != NULL)
3733 res->encoding = xmlStrdup(encoding);
3734 ctxt->output = res;
3735 ctxt->insert = (xmlNodePtr) res;
3736 xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
3737
3738 /*
3739 * Do some post processing work depending on the generated output
3740 */
3741 root = xmlDocGetRootElement(res);
3742 if (root != NULL) {
3743 const xmlChar *doctype = NULL;
3744
3745 if ((root->ns != NULL) && (root->ns->prefix != NULL))
3746 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3747 if (doctype == NULL)
3748 doctype = root->name;
3749
3750 /*
3751 * Apply the default selection of the method
3752 */
3753 if ((method == NULL) &&
3754 (root->ns == NULL) &&
3755 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3756 xmlNodePtr tmp;
3757
3758 tmp = res->children;
3759 while ((tmp != NULL) && (tmp != root)) {
3760 if (tmp->type == XML_ELEMENT_NODE)
3761 break;
3762 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3763 break;
3764 tmp = tmp->next;
3765 }
3766 if (tmp == root) {
3767 ctxt->type = XSLT_OUTPUT_HTML;
3768 res->type = XML_HTML_DOCUMENT_NODE;
3769 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3770 res->intSubset = xmlCreateIntSubset(res, doctype,
3771 doctypePublic,
3772 doctypeSystem);
3773 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3774 } else if (version != NULL) {
3775 xsltGetHTMLIDs(version, &doctypePublic,
3776 &doctypeSystem);
3777 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3778 res->intSubset =
3779 xmlCreateIntSubset(res, doctype,
3780 doctypePublic,
3781 doctypeSystem);
3782 #endif
3783 }
3784 }
3785
3786 }
3787 if (ctxt->type == XSLT_OUTPUT_XML) {
3788 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3789 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3790 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3791 res->intSubset = xmlCreateIntSubset(res, doctype,
3792 doctypePublic,
3793 doctypeSystem);
3794 }
3795 }
3796
3797 /*
3798 * Calls to redirect:write also take an optional attribute append.
3799 * Attribute append="true|yes" which will attempt to simply append
3800 * to an existing file instead of always opening a new file. The
3801 * default behavior of always overwriting the file still happens
3802 * if we do not specify append.
3803 * Note that append use will forbid use of remote URI target.
3804 */
3805 prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
3806 NULL);
3807 if (prop != NULL) {
3808 if (xmlStrEqual(prop, (const xmlChar *) "true") ||
3809 xmlStrEqual(prop, (const xmlChar *) "yes")) {
3810 style->omitXmlDeclaration = 1;
3811 redirect_write_append = 1;
3812 } else
3813 style->omitXmlDeclaration = 0;
3814 xmlFree(prop);
3815 }
3816
3817 if (redirect_write_append) {
3818 FILE *f;
3819
3820 f = fopen((const char *) filename, "ab");
3821 if (f == NULL) {
3822 ret = -1;
3823 } else {
3824 ret = xsltSaveResultToFile(f, res, style);
3825 fclose(f);
3826 }
3827 } else {
3828 ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
3829 }
3830 if (ret < 0) {
3831 xsltTransformError(ctxt, NULL, inst,
3832 "xsltDocumentElem: unable to save to %s\n",
3833 filename);
3834 #ifdef WITH_XSLT_DEBUG_EXTRA
3835 } else {
3836 xsltGenericDebug(xsltGenericDebugContext,
3837 "Wrote %d bytes to %s\n", ret, filename);
3838 #endif
3839 }
3840
3841 error:
3842 ctxt->output = oldOutput;
3843 ctxt->insert = oldInsert;
3844 ctxt->type = oldType;
3845 ctxt->outputFile = oldOutputFile;
3846 if (URL != NULL)
3847 xmlFree(URL);
3848 if (filename != NULL)
3849 xmlFree(filename);
3850 if (style != NULL)
3851 xsltFreeStylesheet(style);
3852 if (res != NULL)
3853 xmlFreeDoc(res);
3854 }
3855
3856 /************************************************************************
3857 * *
3858 * Most of the XSLT-1.0 transformations *
3859 * *
3860 ************************************************************************/
3861
3862 /**
3863 * xsltSort:
3864 * @ctxt: a XSLT process context
3865 * @node: the node in the source tree.
3866 * @inst: the xslt sort node
3867 * @comp: precomputed information
3868 *
3869 * function attached to xsl:sort nodes, but this should not be
3870 * called directly
3871 */
3872 void
3873 xsltSort(xsltTransformContextPtr ctxt,
3874 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
3875 xsltStylePreCompPtr comp) {
3876 if (comp == NULL) {
3877 xsltTransformError(ctxt, NULL, inst,
3878 "xsl:sort : compilation failed\n");
3879 return;
3880 }
3881 xsltTransformError(ctxt, NULL, inst,
3882 "xsl:sort : improper use this should not be reached\n");
3883 }
3884
3885 /**
3886 * xsltCopy:
3887 * @ctxt: an XSLT process context
3888 * @node: the node in the source tree
3889 * @inst: the element node of the XSLT-copy instruction
3890 * @castedComp: computed information of the XSLT-copy instruction
3891 *
3892 * Execute the XSLT-copy instruction on the source node.
3893 */
3894 void
3895 xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
3896 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
3897 {
3898 #ifdef XSLT_REFACTORED
3899 xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3900 #else
3901 xsltStylePreCompPtr comp = castedComp;
3902 #endif
3903 xmlNodePtr copy, oldInsert;
3904
3905 oldInsert = ctxt->insert;
3906 if (ctxt->insert != NULL) {
3907 switch (node->type) {
3908 case XML_TEXT_NODE:
3909 case XML_CDATA_SECTION_NODE:
3910 /*
3911 * This text comes from the stylesheet
3912 * For stylesheets, the set of whitespace-preserving
3913 * element names consists of just xsl:text.
3914 */
3915 #ifdef WITH_XSLT_DEBUG_PROCESS
3916 if (node->type == XML_CDATA_SECTION_NODE) {
3917 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGeneric DebugContext,
3918 "xsltCopy: CDATA text %s\n", node->content));
3919 } else {
3920 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGeneric DebugContext,
3921 "xsltCopy: text %s\n", node->content));
3922 }
3923 #endif
3924 xsltCopyText(ctxt, ctxt->insert, node, 0);
3925 break;
3926 case XML_DOCUMENT_NODE:
3927 case XML_HTML_DOCUMENT_NODE:
3928 break;
3929 case XML_ELEMENT_NODE:
3930 /*
3931 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3932 * REMOVED:
3933 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3934 * return;
3935 */
3936
3937 #ifdef WITH_XSLT_DEBUG_PROCESS
3938 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebu gContext,
3939 "xsltCopy: node %s\n", node->name));
3940 #endif
3941 copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3942 ctxt->insert = copy;
3943 if (comp->use != NULL) {
3944 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3945 }
3946 break;
3947 case XML_ATTRIBUTE_NODE: {
3948 #ifdef WITH_XSLT_DEBUG_PROCESS
3949 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebu gContext,
3950 "xsltCopy: attribute %s\n", node->name));
3951 #endif
3952 /*
3953 * REVISIT: We could also raise an error if the parent is not
3954 * an element node.
3955 * OPTIMIZE TODO: Can we set the value/children of the
3956 * attribute without an intermediate copy of the string value?
3957 */
3958 xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node) ;
3959 break;
3960 }
3961 case XML_PI_NODE:
3962 #ifdef WITH_XSLT_DEBUG_PROCESS
3963 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebu gContext,
3964 "xsltCopy: PI %s\n", node->name));
3965 #endif
3966 copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3967 node->content);
3968 copy = xsltAddChild(ctxt->insert, copy);
3969 break;
3970 case XML_COMMENT_NODE:
3971 #ifdef WITH_XSLT_DEBUG_PROCESS
3972 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebu gContext,
3973 "xsltCopy: comment\n"));
3974 #endif
3975 copy = xmlNewComment(node->content);
3976 copy = xsltAddChild(ctxt->insert, copy);
3977 break;
3978 case XML_NAMESPACE_DECL:
3979 #ifdef WITH_XSLT_DEBUG_PROCESS
3980 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebu gContext,
3981 "xsltCopy: namespace declaration\n"));
3982 #endif
3983 xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3984 break;
3985 default:
3986 break;
3987
3988 }
3989 }
3990
3991 switch (node->type) {
3992 case XML_DOCUMENT_NODE:
3993 case XML_HTML_DOCUMENT_NODE:
3994 case XML_ELEMENT_NODE:
3995 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
3996 NULL);
3997 break;
3998 default:
3999 break;
4000 }
4001 ctxt->insert = oldInsert;
4002 }
4003
4004 /**
4005 * xsltText:
4006 * @ctxt: a XSLT process context
4007 * @node: the node in the source tree.
4008 * @inst: the xslt text node
4009 * @comp: precomputed information
4010 *
4011 * Process the xslt text node on the source node
4012 */
4013 void
4014 xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
4015 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
4016 if ((inst->children != NULL) && (comp != NULL)) {
4017 xmlNodePtr text = inst->children;
4018 xmlNodePtr copy;
4019
4020 while (text != NULL) {
4021 if ((text->type != XML_TEXT_NODE) &&
4022 (text->type != XML_CDATA_SECTION_NODE)) {
4023 xsltTransformError(ctxt, NULL, inst,
4024 "xsl:text content problem\n");
4025 break;
4026 }
4027 copy = xmlNewDocText(ctxt->output, text->content);
4028 if (text->type != XML_CDATA_SECTION_NODE) {
4029 #ifdef WITH_XSLT_DEBUG_PARSING
4030 xsltGenericDebug(xsltGenericDebugContext,
4031 "Disable escaping: %s\n", text->content);
4032 #endif
4033 copy->name = xmlStringTextNoenc;
4034 }
4035 copy = xsltAddChild(ctxt->insert, copy);
4036 text = text->next;
4037 }
4038 }
4039 }
4040
4041 /**
4042 * xsltElement:
4043 * @ctxt: a XSLT process context
4044 * @node: the node in the source tree.
4045 * @inst: the xslt element node
4046 * @castedComp: precomputed information
4047 *
4048 * Process the xslt element node on the source node
4049 */
4050 void
4051 xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
4052 xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
4053 #ifdef XSLT_REFACTORED
4054 xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
4055 #else
4056 xsltStylePreCompPtr comp = castedComp;
4057 #endif
4058 xmlChar *prop = NULL;
4059 const xmlChar *name, *prefix = NULL, *nsName = NULL;
4060 xmlNodePtr copy;
4061 xmlNodePtr oldInsert;
4062
4063 if (ctxt->insert == NULL)
4064 return;
4065
4066 /*
4067 * A comp->has_name == 0 indicates that we need to skip this instruction,
4068 * since it was evaluated to be invalid already during compilation.
4069 */
4070 if (!comp->has_name)
4071 return;
4072
4073 /*
4074 * stack and saves
4075 */
4076 oldInsert = ctxt->insert;
4077
4078 if (comp->name == NULL) {
4079 /* TODO: fix attr acquisition wrt to the XSLT namespace */
4080 prop = xsltEvalAttrValueTemplate(ctxt, inst,
4081 (const xmlChar *) "name", XSLT_NAMESPACE);
4082 if (prop == NULL) {
4083 xsltTransformError(ctxt, NULL, inst,
4084 "xsl:element: The attribute 'name' is missing.\n");
4085 goto error;
4086 }
4087 if (xmlValidateQName(prop, 0)) {
4088 xsltTransformError(ctxt, NULL, inst,
4089 "xsl:element: The effective name '%s' is not a "
4090 "valid QName.\n", prop);
4091 /* we fall through to catch any further errors, if possible */
4092 }
4093 name = xsltSplitQName(ctxt->dict, prop, &prefix);
4094 xmlFree(prop);
4095 } else {
4096 /*
4097 * The "name" value was static.
4098 */
4099 #ifdef XSLT_REFACTORED
4100 prefix = comp->nsPrefix;
4101 name = comp->name;
4102 #else
4103 name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
4104 #endif
4105 }
4106
4107 /*
4108 * Create the new element
4109 */
4110 if (ctxt->output->dict == ctxt->dict) {
4111 copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
4112 } else {
4113 copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
4114 }
4115 if (copy == NULL) {
4116 xsltTransformError(ctxt, NULL, inst,
4117 "xsl:element : creation of %s failed\n", name);
4118 return;
4119 }
4120 copy = xsltAddChild(ctxt->insert, copy);
4121 if (copy == NULL) {
4122 xsltTransformError(ctxt, NULL, inst,
4123 "xsl:element : xsltAddChild failed\n");
4124 return;
4125 }
4126
4127 /*
4128 * Namespace
4129 * ---------
4130 */
4131 if (comp->has_ns) {
4132 if (comp->ns != NULL) {
4133 /*
4134 * No AVT; just plain text for the namespace name.
4135 */
4136 if (comp->ns[0] != 0)
4137 nsName = comp->ns;
4138 } else {
4139 xmlChar *tmpNsName;
4140 /*
4141 * Eval the AVT.
4142 */
4143 /* TODO: check attr acquisition wrt to the XSLT namespace */
4144 tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
4145 (const xmlChar *) "namespace", XSLT_NAMESPACE);
4146 /*
4147 * SPEC XSLT 1.0:
4148 * "If the string is empty, then the expanded-name of the
4149 * attribute has a null namespace URI."
4150 */
4151 if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
4152 nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
4153 xmlFree(tmpNsName);
4154 }
4155
4156 if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
4157 xsltTransformError(ctxt, NULL, inst,
4158 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4159 "forbidden.\n");
4160 goto error;
4161 }
4162 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
4163 prefix = BAD_CAST "xml";
4164 } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
4165 prefix = NULL;
4166 }
4167 } else {
4168 xmlNsPtr ns;
4169 /*
4170 * SPEC XSLT 1.0:
4171 * "If the namespace attribute is not present, then the QName is
4172 * expanded into an expanded-name using the namespace declarations
4173 * in effect for the xsl:element element, including any default
4174 * namespace declaration.
4175 */
4176 ns = xmlSearchNs(inst->doc, inst, prefix);
4177 if (ns == NULL) {
4178 /*
4179 * TODO: Check this in the compilation layer in case it's a
4180 * static value.
4181 */
4182 if (prefix != NULL) {
4183 xsltTransformError(ctxt, NULL, inst,
4184 "xsl:element: The QName '%s:%s' has no "
4185 "namespace binding in scope in the stylesheet; "
4186 "this is an error, since the namespace was not "
4187 "specified by the instruction itself.\n", prefix, name);
4188 }
4189 } else
4190 nsName = ns->href;
4191 }
4192 /*
4193 * Find/create a matching ns-decl in the result tree.
4194 */
4195 if (nsName != NULL) {
4196 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
4197 /* Don't use a prefix of "xmlns" */
4198 xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
4199
4200 copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
4201
4202 xmlFree(pref);
4203 } else {
4204 copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
4205 copy);
4206 }
4207 } else if ((copy->parent != NULL) &&
4208 (copy->parent->type == XML_ELEMENT_NODE) &&
4209 (copy->parent->ns != NULL))
4210 {
4211 /*
4212 * "Undeclare" the default namespace.
4213 */
4214 xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4215 }
4216
4217 ctxt->insert = copy;
4218
4219 if (comp->has_use) {
4220 if (comp->use != NULL) {
4221 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4222 } else {
4223 xmlChar *attrSets = NULL;
4224 /*
4225 * BUG TODO: use-attribute-sets is not a value template.
4226 * use-attribute-sets = qnames
4227 */
4228 attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4229 (const xmlChar *)"use-attribute-sets", NULL);
4230 if (attrSets != NULL) {
4231 xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4232 xmlFree(attrSets);
4233 }
4234 }
4235 }
4236 /*
4237 * Instantiate the sequence constructor.
4238 */
4239 if (inst->children != NULL)
4240 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4241 NULL);
4242
4243 error:
4244 ctxt->insert = oldInsert;
4245 return;
4246 }
4247
4248
4249 /**
4250 * xsltComment:
4251 * @ctxt: a XSLT process context
4252 * @node: the node in the source tree.
4253 * @inst: the xslt comment node
4254 * @comp: precomputed information
4255 *
4256 * Process the xslt comment node on the source node
4257 */
4258 void
4259 xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
4260 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
4261 xmlChar *value = NULL;
4262 xmlNodePtr commentNode;
4263 int len;
4264
4265 value = xsltEvalTemplateString(ctxt, node, inst);
4266 /* TODO: use or generate the compiled form */
4267 len = xmlStrlen(value);
4268 if (len > 0) {
4269 if ((value[len-1] == '-') ||
4270 (xmlStrstr(value, BAD_CAST "--"))) {
4271 xsltTransformError(ctxt, NULL, inst,
4272 "xsl:comment : '--' or ending '-' not allowed in comment\n") ;
4273 /* fall through to try to catch further errors */
4274 }
4275 }
4276 #ifdef WITH_XSLT_DEBUG_PROCESS
4277 if (value == NULL) {
4278 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugCont ext,
4279 "xsltComment: empty\n"));
4280 } else {
4281 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugCont ext,
4282 "xsltComment: content %s\n", value));
4283 }
4284 #endif
4285
4286 commentNode = xmlNewComment(value);
4287 commentNode = xsltAddChild(ctxt->insert, commentNode);
4288
4289 if (value != NULL)
4290 xmlFree(value);
4291 }
4292
4293 /**
4294 * xsltProcessingInstruction:
4295 * @ctxt: a XSLT process context
4296 * @node: the node in the source tree.
4297 * @inst: the xslt processing-instruction node
4298 * @castedComp: precomputed information
4299 *
4300 * Process the xslt processing-instruction node on the source node
4301 */
4302 void
4303 xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
4304 xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
4305 #ifdef XSLT_REFACTORED
4306 xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4307 #else
4308 xsltStylePreCompPtr comp = castedComp;
4309 #endif
4310 const xmlChar *name;
4311 xmlChar *value = NULL;
4312 xmlNodePtr pi;
4313
4314
4315 if (ctxt->insert == NULL)
4316 return;
4317 if (comp->has_name == 0)
4318 return;
4319 if (comp->name == NULL) {
4320 name = xsltEvalAttrValueTemplate(ctxt, inst,
4321 (const xmlChar *)"name", NULL);
4322 if (name == NULL) {
4323 xsltTransformError(ctxt, NULL, inst,
4324 "xsl:processing-instruction : name is missing\n");
4325 goto error;
4326 }
4327 } else {
4328 name = comp->name;
4329 }
4330 /* TODO: check that it's both an an NCName and a PITarget. */
4331
4332
4333 value = xsltEvalTemplateString(ctxt, node, inst);
4334 if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4335 xsltTransformError(ctxt, NULL, inst,
4336 "xsl:processing-instruction: '?>' not allowed within PI content\n") ;
4337 goto error;
4338 }
4339 #ifdef WITH_XSLT_DEBUG_PROCESS
4340 if (value == NULL) {
4341 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4342 "xsltProcessingInstruction: %s empty\n", name));
4343 } else {
4344 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4345 "xsltProcessingInstruction: %s content %s\n", name, value));
4346 }
4347 #endif
4348
4349 pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4350 pi = xsltAddChild(ctxt->insert, pi);
4351
4352 error:
4353 if ((name != NULL) && (name != comp->name))
4354 xmlFree((xmlChar *) name);
4355 if (value != NULL)
4356 xmlFree(value);
4357 }
4358
4359 /**
4360 * xsltCopyOf:
4361 * @ctxt: an XSLT transformation context
4362 * @node: the current node in the source tree
4363 * @inst: the element node of the XSLT copy-of instruction
4364 * @castedComp: precomputed information of the XSLT copy-of instruction
4365 *
4366 * Process the XSLT copy-of instruction.
4367 */
4368 void
4369 xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4370 xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
4371 #ifdef XSLT_REFACTORED
4372 xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4373 #else
4374 xsltStylePreCompPtr comp = castedComp;
4375 #endif
4376 xmlXPathObjectPtr res = NULL;
4377 xmlNodeSetPtr list = NULL;
4378 int i;
4379
4380 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4381 return;
4382 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4383 xsltTransformError(ctxt, NULL, inst,
4384 "xsl:copy-of : compilation failed\n");
4385 return;
4386 }
4387
4388 /*
4389 * SPEC XSLT 1.0:
4390 * "The xsl:copy-of element can be used to insert a result tree
4391 * fragment into the result tree, without first converting it to
4392 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4393 * xsl:value-of]). The required select attribute contains an
4394 * expression. When the result of evaluating the expression is a
4395 * result tree fragment, the complete fragment is copied into the
4396 * result tree. When the result is a node-set, all the nodes in the
4397 * set are copied in document order into the result tree; copying
4398 * an element node copies the attribute nodes, namespace nodes and
4399 * children of the element node as well as the element node itself;
4400 * a root node is copied by copying its children. When the result
4401 * is neither a node-set nor a result tree fragment, the result is
4402 * converted to a string and then inserted into the result tree,
4403 * as with xsl:value-of.
4404 */
4405
4406 #ifdef WITH_XSLT_DEBUG_PROCESS
4407 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4408 "xsltCopyOf: select %s\n", comp->select));
4409 #endif
4410
4411 /*
4412 * Evaluate the "select" expression.
4413 */
4414 res = xsltPreCompEval(ctxt, node, comp);
4415
4416 if (res != NULL) {
4417 if (res->type == XPATH_NODESET) {
4418 /*
4419 * Node-set
4420 * --------
4421 */
4422 #ifdef WITH_XSLT_DEBUG_PROCESS
4423 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebug Context,
4424 "xsltCopyOf: result is a node set\n"));
4425 #endif
4426 list = res->nodesetval;
4427 if (list != NULL) {
4428 xmlNodePtr cur;
4429 /*
4430 * The list is already sorted in document order by XPath.
4431 * Append everything in this order under ctxt->insert.
4432 */
4433 for (i = 0;i < list->nodeNr;i++) {
4434 cur = list->nodeTab[i];
4435 if (cur == NULL)
4436 continue;
4437 if ((cur->type == XML_DOCUMENT_NODE) ||
4438 (cur->type == XML_HTML_DOCUMENT_NODE))
4439 {
4440 xsltCopyTreeList(ctxt, inst,
4441 cur->children, ctxt->insert, 0, 0);
4442 } else if (cur->type == XML_ATTRIBUTE_NODE) {
4443 xsltShallowCopyAttr(ctxt, inst,
4444 ctxt->insert, (xmlAttrPtr) cur);
4445 } else {
4446 xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
4447 }
4448 }
4449 }
4450 } else if (res->type == XPATH_XSLT_TREE) {
4451 /*
4452 * Result tree fragment
4453 * --------------------
4454 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4455 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4456 */
4457 #ifdef WITH_XSLT_DEBUG_PROCESS
4458 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebug Context,
4459 "xsltCopyOf: result is a result tree fragment\n"));
4460 #endif
4461 list = res->nodesetval;
4462 if ((list != NULL) && (list->nodeTab != NULL) &&
4463 (list->nodeTab[0] != NULL) &&
4464 (IS_XSLT_REAL_NODE(list->nodeTab[0])))
4465 {
4466 xsltCopyTreeList(ctxt, inst,
4467 list->nodeTab[0]->children, ctxt->insert, 0, 0);
4468 }
4469 } else {
4470 xmlChar *value = NULL;
4471 /*
4472 * Convert to a string.
4473 */
4474 value = xmlXPathCastToString(res);
4475 if (value == NULL) {
4476 xsltTransformError(ctxt, NULL, inst,
4477 "Internal error in xsltCopyOf(): "
4478 "failed to cast an XPath object to string.\n");
4479 ctxt->state = XSLT_STATE_STOPPED;
4480 } else {
4481 if (value[0] != 0) {
4482 /*
4483 * Append content as text node.
4484 */
4485 xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4486 }
4487 xmlFree(value);
4488
4489 #ifdef WITH_XSLT_DEBUG_PROCESS
4490 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericD ebugContext,
4491 "xsltCopyOf: result %s\n", res->stringval));
4492 #endif
4493 }
4494 }
4495 } else {
4496 ctxt->state = XSLT_STATE_STOPPED;
4497 }
4498
4499 if (res != NULL)
4500 xmlXPathFreeObject(res);
4501 }
4502
4503 /**
4504 * xsltValueOf:
4505 * @ctxt: a XSLT process context
4506 * @node: the node in the source tree.
4507 * @inst: the xslt value-of node
4508 * @castedComp: precomputed information
4509 *
4510 * Process the xslt value-of node on the source node
4511 */
4512 void
4513 xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4514 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4515 {
4516 #ifdef XSLT_REFACTORED
4517 xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4518 #else
4519 xsltStylePreCompPtr comp = castedComp;
4520 #endif
4521 xmlXPathObjectPtr res = NULL;
4522 xmlChar *value = NULL;
4523
4524 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4525 return;
4526
4527 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4528 xsltTransformError(ctxt, NULL, inst,
4529 "Internal error in xsltValueOf(): "
4530 "The XSLT 'value-of' instruction was not compiled.\n");
4531 return;
4532 }
4533
4534 #ifdef WITH_XSLT_DEBUG_PROCESS
4535 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext ,
4536 "xsltValueOf: select %s\n", comp->select));
4537 #endif
4538
4539 res = xsltPreCompEval(ctxt, node, comp);
4540
4541 /*
4542 * Cast the XPath object to string.
4543 */
4544 if (res != NULL) {
4545 value = xmlXPathCastToString(res);
4546 if (value == NULL) {
4547 xsltTransformError(ctxt, NULL, inst,
4548 "Internal error in xsltValueOf(): "
4549 "failed to cast an XPath object to string.\n");
4550 ctxt->state = XSLT_STATE_STOPPED;
4551 goto error;
4552 }
4553 if (value[0] != 0) {
4554 xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
4555 }
4556 } else {
4557 xsltTransformError(ctxt, NULL, inst,
4558 "XPath evaluation returned no result.\n");
4559 ctxt->state = XSLT_STATE_STOPPED;
4560 goto error;
4561 }
4562
4563 #ifdef WITH_XSLT_DEBUG_PROCESS
4564 if (value) {
4565 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugCon text,
4566 "xsltValueOf: result '%s'\n", value));
4567 }
4568 #endif
4569
4570 error:
4571 if (value != NULL)
4572 xmlFree(value);
4573 if (res != NULL)
4574 xmlXPathFreeObject(res);
4575 }
4576
4577 /**
4578 * xsltNumber:
4579 * @ctxt: a XSLT process context
4580 * @node: the node in the source tree.
4581 * @inst: the xslt number node
4582 * @castedComp: precomputed information
4583 *
4584 * Process the xslt number node on the source node
4585 */
4586 void
4587 xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
4588 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4589 {
4590 #ifdef XSLT_REFACTORED
4591 xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4592 #else
4593 xsltStylePreCompPtr comp = castedComp;
4594 #endif
4595 xmlXPathContextPtr xpctxt;
4596 xmlNsPtr *oldXPNamespaces;
4597 int oldXPNsNr;
4598
4599 if (comp == NULL) {
4600 xsltTransformError(ctxt, NULL, inst,
4601 "xsl:number : compilation failed\n");
4602 return;
4603 }
4604
4605 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4606 return;
4607
4608 comp->numdata.doc = inst->doc;
4609 comp->numdata.node = inst;
4610
4611 xpctxt = ctxt->xpathCtxt;
4612 oldXPNsNr = xpctxt->nsNr;
4613 oldXPNamespaces = xpctxt->namespaces;
4614
4615 #ifdef XSLT_REFACTORED
4616 if (comp->inScopeNs != NULL) {
4617 xpctxt->namespaces = comp->inScopeNs->list;
4618 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4619 } else {
4620 xpctxt->namespaces = NULL;
4621 xpctxt->nsNr = 0;
4622 }
4623 #else
4624 xpctxt->namespaces = comp->nsList;
4625 xpctxt->nsNr = comp->nsNr;
4626 #endif
4627
4628 xsltNumberFormat(ctxt, &comp->numdata, node);
4629
4630 xpctxt->nsNr = oldXPNsNr;
4631 xpctxt->namespaces = oldXPNamespaces;
4632 }
4633
4634 /**
4635 * xsltApplyImports:
4636 * @ctxt: an XSLT transformation context
4637 * @contextNode: the current node in the source tree.
4638 * @inst: the element node of the XSLT 'apply-imports' instruction
4639 * @comp: the compiled instruction
4640 *
4641 * Process the XSLT apply-imports element.
4642 */
4643 void
4644 xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
4645 xmlNodePtr inst,
4646 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
4647 {
4648 xsltTemplatePtr templ;
4649
4650 if ((ctxt == NULL) || (inst == NULL))
4651 return;
4652
4653 if (comp == NULL) {
4654 xsltTransformError(ctxt, NULL, inst,
4655 "Internal error in xsltApplyImports(): "
4656 "The XSLT 'apply-imports' instruction was not compiled.\n");
4657 return;
4658 }
4659 /*
4660 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4661 * same; the former is the "Current Template Rule" as defined by the
4662 * XSLT spec, the latter is simply the template struct being
4663 * currently processed.
4664 */
4665 if (ctxt->currentTemplateRule == NULL) {
4666 /*
4667 * SPEC XSLT 2.0:
4668 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4669 * xsl:apply-imports or xsl:next-match is evaluated when the
4670 * current template rule is null."
4671 */
4672 xsltTransformError(ctxt, NULL, inst,
4673 "It is an error to call 'apply-imports' "
4674 "when there's no current template rule.\n");
4675 return;
4676 }
4677 /*
4678 * TODO: Check if this is correct.
4679 */
4680 templ = xsltGetTemplate(ctxt, contextNode,
4681 ctxt->currentTemplateRule->style);
4682
4683 if (templ != NULL) {
4684 xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4685 /*
4686 * Set the current template rule.
4687 */
4688 ctxt->currentTemplateRule = templ;
4689 /*
4690 * URGENT TODO: Need xsl:with-param be handled somehow here?
4691 */
4692 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4693 templ, NULL);
4694
4695 ctxt->currentTemplateRule = oldCurTemplRule;
4696 }
4697 else {
4698 /* Use built-in templates. */
4699 xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
4700 }
4701 }
4702
4703 /**
4704 * xsltCallTemplate:
4705 * @ctxt: a XSLT transformation context
4706 * @node: the "current node" in the source tree
4707 * @inst: the XSLT 'call-template' instruction
4708 * @castedComp: the compiled information of the instruction
4709 *
4710 * Processes the XSLT call-template instruction on the source node.
4711 */
4712 void
4713 xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
4714 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4715 {
4716 #ifdef XSLT_REFACTORED
4717 xsltStyleItemCallTemplatePtr comp =
4718 (xsltStyleItemCallTemplatePtr) castedComp;
4719 #else
4720 xsltStylePreCompPtr comp = castedComp;
4721 #endif
4722 xsltStackElemPtr withParams = NULL;
4723
4724 if (ctxt->insert == NULL)
4725 return;
4726 if (comp == NULL) {
4727 xsltTransformError(ctxt, NULL, inst,
4728 "The XSLT 'call-template' instruction was not compiled.\n");
4729 return;
4730 }
4731
4732 /*
4733 * The template must have been precomputed
4734 */
4735 if (comp->templ == NULL) {
4736 comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4737 if (comp->templ == NULL) {
4738 if (comp->ns != NULL) {
4739 xsltTransformError(ctxt, NULL, inst,
4740 "The called template '{%s}%s' was not found.\n",
4741 comp->ns, comp->name);
4742 } else {
4743 xsltTransformError(ctxt, NULL, inst,
4744 "The called template '%s' was not found.\n",
4745 comp->name);
4746 }
4747 return;
4748 }
4749 }
4750
4751 #ifdef WITH_XSLT_DEBUG_PROCESS
4752 if ((comp != NULL) && (comp->name != NULL))
4753 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDeb ugContext,
4754 "call-template: name %s\n", comp->name));
4755 #endif
4756
4757 if (inst->children) {
4758 xmlNodePtr cur;
4759 xsltStackElemPtr param;
4760
4761 cur = inst->children;
4762 while (cur != NULL) {
4763 #ifdef WITH_DEBUGGER
4764 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4765 xslHandleDebugger(cur, node, comp->templ, ctxt);
4766 #endif
4767 if (ctxt->state == XSLT_STATE_STOPPED) break;
4768 /*
4769 * TODO: The "with-param"s could be part of the "call-template"
4770 * structure. Avoid to "search" for params dynamically
4771 * in the XML tree every time.
4772 */
4773 if (IS_XSLT_ELEM(cur)) {
4774 if (IS_XSLT_NAME(cur, "with-param")) {
4775 param = xsltParseStylesheetCallerParam(ctxt, cur);
4776 if (param != NULL) {
4777 param->next = withParams;
4778 withParams = param;
4779 }
4780 } else {
4781 xsltGenericError(xsltGenericErrorContext,
4782 "xsl:call-template: misplaced xsl:%s\n", cur->name);
4783 }
4784 } else {
4785 xsltGenericError(xsltGenericErrorContext,
4786 "xsl:call-template: misplaced %s element\n", cur->name);
4787 }
4788 cur = cur->next;
4789 }
4790 }
4791 /*
4792 * Create a new frame using the params first
4793 */
4794 xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4795 withParams);
4796 if (withParams != NULL)
4797 xsltFreeStackElemList(withParams);
4798
4799 #ifdef WITH_XSLT_DEBUG_PROCESS
4800 if ((comp != NULL) && (comp->name != NULL))
4801 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDeb ugContext,
4802 "call-template returned: name %s\n", comp->name));
4803 #endif
4804 }
4805
4806 /**
4807 * xsltApplyTemplates:
4808 * @ctxt: a XSLT transformation context
4809 * @node: the 'current node' in the source tree
4810 * @inst: the element node of an XSLT 'apply-templates' instruction
4811 * @castedComp: the compiled instruction
4812 *
4813 * Processes the XSLT 'apply-templates' instruction on the current node.
4814 */
4815 void
4816 xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
4817 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4818 {
4819 #ifdef XSLT_REFACTORED
4820 xsltStyleItemApplyTemplatesPtr comp =
4821 (xsltStyleItemApplyTemplatesPtr) castedComp;
4822 #else
4823 xsltStylePreCompPtr comp = castedComp;
4824 #endif
4825 int i;
4826 xmlNodePtr cur, delNode = NULL, oldContextNode;
4827 xmlNodeSetPtr list = NULL, oldList;
4828 xsltStackElemPtr withParams = NULL;
4829 int oldXPProximityPosition, oldXPContextSize;
4830 const xmlChar *oldMode, *oldModeURI;
4831 xmlDocPtr oldXPDoc;
4832 xsltDocumentPtr oldDocInfo;
4833 xmlXPathContextPtr xpctxt;
4834
4835 if (comp == NULL) {
4836 xsltTransformError(ctxt, NULL, inst,
4837 "xsl:apply-templates : compilation failed\n");
4838 return;
4839 }
4840 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4841 return;
4842
4843 #ifdef WITH_XSLT_DEBUG_PROCESS
4844 if ((node != NULL) && (node->name != NULL))
4845 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericD ebugContext,
4846 "xsltApplyTemplates: node: '%s'\n", node->name));
4847 #endif
4848
4849 xpctxt = ctxt->xpathCtxt;
4850 /*
4851 * Save context states.
4852 */
4853 oldContextNode = ctxt->node;
4854 oldMode = ctxt->mode;
4855 oldModeURI = ctxt->modeURI;
4856 oldDocInfo = ctxt->document;
4857 oldList = ctxt->nodeList;
4858
4859 /*
4860 * The xpath context size and proximity position, as
4861 * well as the xpath and context documents, may be changed
4862 * so we save their initial state and will restore on exit
4863 */
4864 oldXPContextSize = xpctxt->contextSize;
4865 oldXPProximityPosition = xpctxt->proximityPosition;
4866 oldXPDoc = xpctxt->doc;
4867
4868 /*
4869 * Set up contexts.
4870 */
4871 ctxt->mode = comp->mode;
4872 ctxt->modeURI = comp->modeURI;
4873
4874 if (comp->select != NULL) {
4875 xmlXPathObjectPtr res = NULL;
4876
4877 if (comp->comp == NULL) {
4878 xsltTransformError(ctxt, NULL, inst,
4879 "xsl:apply-templates : compilation failed\n");
4880 goto error;
4881 }
4882 #ifdef WITH_XSLT_DEBUG_PROCESS
4883 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericD ebugContext,
4884 "xsltApplyTemplates: select %s\n", comp->select));
4885 #endif
4886
4887 res = xsltPreCompEval(ctxt, node, comp);
4888
4889 if (res != NULL) {
4890 if (res->type == XPATH_NODESET) {
4891 list = res->nodesetval; /* consume the node set */
4892 res->nodesetval = NULL;
4893 } else {
4894 xsltTransformError(ctxt, NULL, inst,
4895 "The 'select' expression did not evaluate to a "
4896 "node set.\n");
4897 ctxt->state = XSLT_STATE_STOPPED;
4898 xmlXPathFreeObject(res);
4899 goto error;
4900 }
4901 xmlXPathFreeObject(res);
4902 /*
4903 * Note: An xsl:apply-templates with a 'select' attribute,
4904 * can change the current source doc.
4905 */
4906 } else {
4907 xsltTransformError(ctxt, NULL, inst,
4908 "Failed to evaluate the 'select' expression.\n");
4909 ctxt->state = XSLT_STATE_STOPPED;
4910 goto error;
4911 }
4912 if (list == NULL) {
4913 #ifdef WITH_XSLT_DEBUG_PROCESS
4914 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGene ricDebugContext,
4915 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4916 #endif
4917 goto exit;
4918 }
4919 /*
4920 *
4921 * NOTE: Previously a document info (xsltDocument) was
4922 * created and attached to the Result Tree Fragment.
4923 * But such a document info is created on demand in
4924 * xsltKeyFunction() (functions.c), so we need to create
4925 * it here beforehand.
4926 * In order to take care of potential keys we need to
4927 * do some extra work for the case when a Result Tree Fragment
4928 * is converted into a nodeset (e.g. exslt:node-set()) :
4929 * We attach a "pseudo-doc" (xsltDocument) to _private.
4930 * This xsltDocument, together with the keyset, will be freed
4931 * when the Result Tree Fragment is freed.
4932 *
4933 */
4934 #if 0
4935 if ((ctxt->nbKeys > 0) &&
4936 (list->nodeNr != 0) &&
4937 (list->nodeTab[0]->doc != NULL) &&
4938 XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
4939 {
4940 /*
4941 * NOTE that it's also OK if @effectiveDocInfo will be
4942 * set to NULL.
4943 */
4944 isRTF = 1;
4945 effectiveDocInfo = list->nodeTab[0]->doc->_private;
4946 }
4947 #endif
4948 } else {
4949 /*
4950 * Build an XPath node set with the children
4951 */
4952 list = xmlXPathNodeSetCreate(NULL);
4953 if (list == NULL)
4954 goto error;
4955 if (node->type != XML_NAMESPACE_DECL)
4956 cur = node->children;
4957 else
4958 cur = NULL;
4959 while (cur != NULL) {
4960 switch (cur->type) {
4961 case XML_TEXT_NODE:
4962 if ((IS_BLANK_NODE(cur)) &&
4963 (cur->parent != NULL) &&
4964 (cur->parent->type == XML_ELEMENT_NODE) &&
4965 (ctxt->style->stripSpaces != NULL)) {
4966 const xmlChar *val;
4967
4968 if (cur->parent->ns != NULL) {
4969 val = (const xmlChar *)
4970 xmlHashLookup2(ctxt->style->stripSpaces,
4971 cur->parent->name,
4972 cur->parent->ns->href);
4973 if (val == NULL) {
4974 val = (const xmlChar *)
4975 xmlHashLookup2(ctxt->style->stripSpaces,
4976 BAD_CAST "*",
4977 cur->parent->ns->href);
4978 }
4979 } else {
4980 val = (const xmlChar *)
4981 xmlHashLookup2(ctxt->style->stripSpaces,
4982 cur->parent->name, NULL);
4983 }
4984 if ((val != NULL) &&
4985 (xmlStrEqual(val, (xmlChar *) "strip"))) {
4986 delNode = cur;
4987 break;
4988 }
4989 }
4990 /* no break on purpose */
4991 case XML_ELEMENT_NODE:
4992 case XML_DOCUMENT_NODE:
4993 case XML_HTML_DOCUMENT_NODE:
4994 case XML_CDATA_SECTION_NODE:
4995 case XML_PI_NODE:
4996 case XML_COMMENT_NODE:
4997 xmlXPathNodeSetAddUnique(list, cur);
4998 break;
4999 case XML_DTD_NODE:
5000 /* Unlink the DTD, it's still reachable
5001 * using doc->intSubset */
5002 if (cur->next != NULL)
5003 cur->next->prev = cur->prev;
5004 if (cur->prev != NULL)
5005 cur->prev->next = cur->next;
5006 break;
5007 case XML_NAMESPACE_DECL:
5008 break;
5009 default:
5010 #ifdef WITH_XSLT_DEBUG_PROCESS
5011 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug( xsltGenericDebugContext,
5012 "xsltApplyTemplates: skipping cur type %d\n",
5013 cur->type));
5014 #endif
5015 delNode = cur;
5016 }
5017 cur = cur->next;
5018 if (delNode != NULL) {
5019 #ifdef WITH_XSLT_DEBUG_PROCESS
5020 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xslt GenericDebugContext,
5021 "xsltApplyTemplates: removing ignorable blank cur\n"));
5022 #endif
5023 xmlUnlinkNode(delNode);
5024 xmlFreeNode(delNode);
5025 delNode = NULL;
5026 }
5027 }
5028 }
5029
5030 #ifdef WITH_XSLT_DEBUG_PROCESS
5031 if (list != NULL)
5032 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebug Context,
5033 "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
5034 #endif
5035
5036 if ((list == NULL) || (list->nodeNr == 0))
5037 goto exit;
5038
5039 /*
5040 * Set the context's node set and size; this is also needed for
5041 * for xsltDoSortFunction().
5042 */
5043 ctxt->nodeList = list;
5044 /*
5045 * Process xsl:with-param and xsl:sort instructions.
5046 * (The code became so verbose just to avoid the
5047 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
5048 * BUG TODO: We are not using namespaced potentially defined on the
5049 * xsl:sort or xsl:with-param elements; XPath expression might fail.
5050 */
5051 if (inst->children) {
5052 xsltStackElemPtr param;
5053
5054 cur = inst->children;
5055 while (cur) {
5056
5057 #ifdef WITH_DEBUGGER
5058 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5059 xslHandleDebugger(cur, node, NULL, ctxt);
5060 #endif
5061 if (ctxt->state == XSLT_STATE_STOPPED)
5062 break;
5063 if (cur->type == XML_TEXT_NODE) {
5064 cur = cur->next;
5065 continue;
5066 }
5067 if (! IS_XSLT_ELEM(cur))
5068 break;
5069 if (IS_XSLT_NAME(cur, "with-param")) {
5070 param = xsltParseStylesheetCallerParam(ctxt, cur);
5071 if (param != NULL) {
5072 param->next = withParams;
5073 withParams = param;
5074 }
5075 }
5076 if (IS_XSLT_NAME(cur, "sort")) {
5077 xsltTemplatePtr oldCurTempRule =
5078 ctxt->currentTemplateRule;
5079 int nbsorts = 0;
5080 xmlNodePtr sorts[XSLT_MAX_SORT];
5081
5082 sorts[nbsorts++] = cur;
5083
5084 while (cur) {
5085
5086 #ifdef WITH_DEBUGGER
5087 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5088 xslHandleDebugger(cur, node, NULL, ctxt);
5089 #endif
5090 if (ctxt->state == XSLT_STATE_STOPPED)
5091 break;
5092
5093 if (cur->type == XML_TEXT_NODE) {
5094 cur = cur->next;
5095 continue;
5096 }
5097
5098 if (! IS_XSLT_ELEM(cur))
5099 break;
5100 if (IS_XSLT_NAME(cur, "with-param")) {
5101 param = xsltParseStylesheetCallerParam(ctxt, cur);
5102 if (param != NULL) {
5103 param->next = withParams;
5104 withParams = param;
5105 }
5106 }
5107 if (IS_XSLT_NAME(cur, "sort")) {
5108 if (nbsorts >= XSLT_MAX_SORT) {
5109 xsltTransformError(ctxt, NULL, cur,
5110 "The number (%d) of xsl:sort instructions exceed s the "
5111 "maximum allowed by this processor's settings.\n ",
5112 nbsorts);
5113 ctxt->state = XSLT_STATE_STOPPED;
5114 break;
5115 } else {
5116 sorts[nbsorts++] = cur;
5117 }
5118 }
5119 cur = cur->next;
5120 }
5121 /*
5122 * The "current template rule" is cleared for xsl:sort.
5123 */
5124 ctxt->currentTemplateRule = NULL;
5125 /*
5126 * Sort.
5127 */
5128 xsltDoSortFunction(ctxt, sorts, nbsorts);
5129 ctxt->currentTemplateRule = oldCurTempRule;
5130 break;
5131 }
5132 cur = cur->next;
5133 }
5134 }
5135 xpctxt->contextSize = list->nodeNr;
5136 /*
5137 * Apply templates for all selected source nodes.
5138 */
5139 for (i = 0; i < list->nodeNr; i++) {
5140 cur = list->nodeTab[i];
5141 /*
5142 * The node becomes the "current node".
5143 */
5144 ctxt->node = cur;
5145 /*
5146 * An xsl:apply-templates can change the current context doc.
5147 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5148 */
5149 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5150 xpctxt->doc = cur->doc;
5151
5152 xpctxt->proximityPosition = i + 1;
5153 /*
5154 * Find and apply a template for this node.
5155 */
5156 xsltProcessOneNode(ctxt, cur, withParams);
5157 }
5158
5159 exit:
5160 error:
5161 /*
5162 * Free the parameter list.
5163 */
5164 if (withParams != NULL)
5165 xsltFreeStackElemList(withParams);
5166 if (list != NULL)
5167 xmlXPathFreeNodeSet(list);
5168 /*
5169 * Restore context states.
5170 */
5171 xpctxt->doc = oldXPDoc;
5172 xpctxt->contextSize = oldXPContextSize;
5173 xpctxt->proximityPosition = oldXPProximityPosition;
5174
5175 ctxt->document = oldDocInfo;
5176 ctxt->nodeList = oldList;
5177 ctxt->node = oldContextNode;
5178 ctxt->mode = oldMode;
5179 ctxt->modeURI = oldModeURI;
5180 }
5181
5182
5183 /**
5184 * xsltChoose:
5185 * @ctxt: a XSLT process context
5186 * @contextNode: the current node in the source tree
5187 * @inst: the xsl:choose instruction
5188 * @comp: compiled information of the instruction
5189 *
5190 * Processes the xsl:choose instruction on the source node.
5191 */
5192 void
5193 xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5194 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
5195 {
5196 xmlNodePtr cur;
5197
5198 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5199 return;
5200
5201 /*
5202 * TODO: Content model checks should be done only at compilation
5203 * time.
5204 */
5205 cur = inst->children;
5206 if (cur == NULL) {
5207 xsltTransformError(ctxt, NULL, inst,
5208 "xsl:choose: The instruction has no content.\n");
5209 return;
5210 }
5211
5212 #ifdef XSLT_REFACTORED
5213 /*
5214 * We don't check the content model during transformation.
5215 */
5216 #else
5217 if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
5218 xsltTransformError(ctxt, NULL, inst,
5219 "xsl:choose: xsl:when expected first\n");
5220 return;
5221 }
5222 #endif
5223
5224 {
5225 int testRes = 0, res = 0;
5226
5227 #ifdef XSLT_REFACTORED
5228 xsltStyleItemWhenPtr wcomp = NULL;
5229 #else
5230 xsltStylePreCompPtr wcomp = NULL;
5231 #endif
5232
5233 /*
5234 * Process xsl:when ---------------------------------------------------
5235 */
5236 while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
5237 wcomp = cur->psvi;
5238
5239 if ((wcomp == NULL) || (wcomp->test == NULL) ||
5240 (wcomp->comp == NULL))
5241 {
5242 xsltTransformError(ctxt, NULL, cur,
5243 "Internal error in xsltChoose(): "
5244 "The XSLT 'when' instruction was not compiled.\n");
5245 goto error;
5246 }
5247
5248
5249 #ifdef WITH_DEBUGGER
5250 if (xslDebugStatus != XSLT_DEBUG_NONE) {
5251 /*
5252 * TODO: Isn't comp->templ always NULL for xsl:choose?
5253 */
5254 xslHandleDebugger(cur, contextNode, NULL, ctxt);
5255 }
5256 #endif
5257 #ifdef WITH_XSLT_DEBUG_PROCESS
5258 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugC ontext,
5259 "xsltChoose: test %s\n", wcomp->test));
5260 #endif
5261
5262 #ifdef XSLT_FAST_IF
5263 res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp);
5264
5265 if (res == -1) {
5266 ctxt->state = XSLT_STATE_STOPPED;
5267 goto error;
5268 }
5269 testRes = (res == 1) ? 1 : 0;
5270
5271 #else /* XSLT_FAST_IF */
5272
5273 res = xsltPreCompEval(ctxt, cotextNode, wcomp);
5274
5275 if (res != NULL) {
5276 if (res->type != XPATH_BOOLEAN)
5277 res = xmlXPathConvertBoolean(res);
5278 if (res->type == XPATH_BOOLEAN)
5279 testRes = res->boolval;
5280 else {
5281 #ifdef WITH_XSLT_DEBUG_PROCESS
5282 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGener icDebugContext,
5283 "xsltChoose: test didn't evaluate to a boolean\n"));
5284 #endif
5285 goto error;
5286 }
5287 xmlXPathFreeObject(res);
5288 res = NULL;
5289 } else {
5290 ctxt->state = XSLT_STATE_STOPPED;
5291 goto error;
5292 }
5293
5294 #endif /* else of XSLT_FAST_IF */
5295
5296 #ifdef WITH_XSLT_DEBUG_PROCESS
5297 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugC ontext,
5298 "xsltChoose: test evaluate to %d\n", testRes));
5299 #endif
5300 if (testRes)
5301 goto test_is_true;
5302
5303 cur = cur->next;
5304 }
5305
5306 /*
5307 * Process xsl:otherwise ----------------------------------------------
5308 */
5309 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
5310
5311 #ifdef WITH_DEBUGGER
5312 if (xslDebugStatus != XSLT_DEBUG_NONE)
5313 xslHandleDebugger(cur, contextNode, NULL, ctxt);
5314 #endif
5315
5316 #ifdef WITH_XSLT_DEBUG_PROCESS
5317 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugC ontext,
5318 "evaluating xsl:otherwise\n"));
5319 #endif
5320 goto test_is_true;
5321 }
5322 goto exit;
5323
5324 test_is_true:
5325
5326 goto process_sequence;
5327 }
5328
5329 process_sequence:
5330
5331 /*
5332 * Instantiate the sequence constructor.
5333 */
5334 xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
5335 NULL);
5336
5337 exit:
5338 error:
5339 return;
5340 }
5341
5342 /**
5343 * xsltIf:
5344 * @ctxt: a XSLT process context
5345 * @contextNode: the current node in the source tree
5346 * @inst: the xsl:if instruction
5347 * @castedComp: compiled information of the instruction
5348 *
5349 * Processes the xsl:if instruction on the source node.
5350 */
5351 void
5352 xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5353 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
5354 {
5355 int res = 0;
5356
5357 #ifdef XSLT_REFACTORED
5358 xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
5359 #else
5360 xsltStylePreCompPtr comp = castedComp;
5361 #endif
5362
5363 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5364 return;
5365 if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
5366 xsltTransformError(ctxt, NULL, inst,
5367 "Internal error in xsltIf(): "
5368 "The XSLT 'if' instruction was not compiled.\n");
5369 return;
5370 }
5371
5372 #ifdef WITH_XSLT_DEBUG_PROCESS
5373 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5374 "xsltIf: test %s\n", comp->test));
5375 #endif
5376
5377 #ifdef XSLT_FAST_IF
5378 {
5379 xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
5380
5381 res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp);
5382
5383 /*
5384 * Cleanup fragments created during evaluation of the
5385 * "select" expression.
5386 */
5387 if (oldLocalFragmentTop != ctxt->localRVT)
5388 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
5389 }
5390
5391 #ifdef WITH_XSLT_DEBUG_PROCESS
5392 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5393 "xsltIf: test evaluate to %d\n", res));
5394 #endif
5395
5396 if (res == -1) {
5397 ctxt->state = XSLT_STATE_STOPPED;
5398 goto error;
5399 }
5400 if (res == 1) {
5401 /*
5402 * Instantiate the sequence constructor of xsl:if.
5403 */
5404 xsltApplySequenceConstructor(ctxt,
5405 contextNode, inst->children, NULL);
5406 }
5407
5408 #else /* XSLT_FAST_IF */
5409 {
5410 /*
5411 * OLD CODE:
5412 */
5413 xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp);
5414 if (xpobj != NULL) {
5415 if (xpobj->type != XPATH_BOOLEAN)
5416 xpobj = xmlXPathConvertBoolean(xpobj);
5417 if (xpobj->type == XPATH_BOOLEAN) {
5418 res = xpobj->boolval;
5419
5420 #ifdef WITH_XSLT_DEBUG_PROCESS
5421 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugC ontext,
5422 "xsltIf: test evaluate to %d\n", res));
5423 #endif
5424 if (res) {
5425 xsltApplySequenceConstructor(ctxt,
5426 contextNode, inst->children, NULL);
5427 }
5428 } else {
5429
5430 #ifdef WITH_XSLT_DEBUG_PROCESS
5431 XSLT_TRACE(ctxt, XSLT_TRACE_IF,
5432 xsltGenericDebug(xsltGenericDebugContext,
5433 "xsltIf: test didn't evaluate to a boolean\n"));
5434 #endif
5435 ctxt->state = XSLT_STATE_STOPPED;
5436 }
5437 xmlXPathFreeObject(xpobj);
5438 } else {
5439 ctxt->state = XSLT_STATE_STOPPED;
5440 }
5441 }
5442 #endif /* else of XSLT_FAST_IF */
5443
5444 error:
5445 return;
5446 }
5447
5448 /**
5449 * xsltForEach:
5450 * @ctxt: an XSLT transformation context
5451 * @contextNode: the "current node" in the source tree
5452 * @inst: the element node of the xsl:for-each instruction
5453 * @castedComp: the compiled information of the instruction
5454 *
5455 * Process the xslt for-each node on the source node
5456 */
5457 void
5458 xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5459 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
5460 {
5461 #ifdef XSLT_REFACTORED
5462 xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
5463 #else
5464 xsltStylePreCompPtr comp = castedComp;
5465 #endif
5466 int i;
5467 xmlXPathObjectPtr res = NULL;
5468 xmlNodePtr cur, curInst;
5469 xmlNodeSetPtr list = NULL;
5470 xmlNodeSetPtr oldList;
5471 int oldXPProximityPosition, oldXPContextSize;
5472 xmlNodePtr oldContextNode;
5473 xsltTemplatePtr oldCurTemplRule;
5474 xmlDocPtr oldXPDoc;
5475 xsltDocumentPtr oldDocInfo;
5476 xmlXPathContextPtr xpctxt;
5477
5478 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
5479 xsltGenericError(xsltGenericErrorContext,
5480 "xsltForEach(): Bad arguments.\n");
5481 return;
5482 }
5483
5484 if (comp == NULL) {
5485 xsltTransformError(ctxt, NULL, inst,
5486 "Internal error in xsltForEach(): "
5487 "The XSLT 'for-each' instruction was not compiled.\n");
5488 return;
5489 }
5490 if ((comp->select == NULL) || (comp->comp == NULL)) {
5491 xsltTransformError(ctxt, NULL, inst,
5492 "Internal error in xsltForEach(): "
5493 "The selecting expression of the XSLT 'for-each' "
5494 "instruction was not compiled correctly.\n");
5495 return;
5496 }
5497 xpctxt = ctxt->xpathCtxt;
5498
5499 #ifdef WITH_XSLT_DEBUG_PROCESS
5500 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext ,
5501 "xsltForEach: select %s\n", comp->select));
5502 #endif
5503
5504 /*
5505 * Save context states.
5506 */
5507 oldDocInfo = ctxt->document;
5508 oldList = ctxt->nodeList;
5509 oldContextNode = ctxt->node;
5510 /*
5511 * The "current template rule" is cleared for the instantiation of
5512 * xsl:for-each.
5513 */
5514 oldCurTemplRule = ctxt->currentTemplateRule;
5515 ctxt->currentTemplateRule = NULL;
5516
5517 oldXPDoc = xpctxt->doc;
5518 oldXPProximityPosition = xpctxt->proximityPosition;
5519 oldXPContextSize = xpctxt->contextSize;
5520
5521 /*
5522 * Evaluate the 'select' expression.
5523 */
5524 res = xsltPreCompEval(ctxt, contextNode, comp);
5525
5526 if (res != NULL) {
5527 if (res->type == XPATH_NODESET)
5528 list = res->nodesetval;
5529 else {
5530 xsltTransformError(ctxt, NULL, inst,
5531 "The 'select' expression does not evaluate to a node set.\n");
5532
5533 #ifdef WITH_XSLT_DEBUG_PROCESS
5534 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebu gContext,
5535 "xsltForEach: select didn't evaluate to a node list\n"));
5536 #endif
5537 goto error;
5538 }
5539 } else {
5540 xsltTransformError(ctxt, NULL, inst,
5541 "Failed to evaluate the 'select' expression.\n");
5542 ctxt->state = XSLT_STATE_STOPPED;
5543 goto error;
5544 }
5545
5546 if ((list == NULL) || (list->nodeNr <= 0))
5547 goto exit;
5548
5549 #ifdef WITH_XSLT_DEBUG_PROCESS
5550 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext ,
5551 "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
5552 #endif
5553
5554 /*
5555 * Set the list; this has to be done already here for xsltDoSortFunction().
5556 */
5557 ctxt->nodeList = list;
5558 /*
5559 * Handle xsl:sort instructions and skip them for further processing.
5560 * BUG TODO: We are not using namespaced potentially defined on the
5561 * xsl:sort element; XPath expression might fail.
5562 */
5563 curInst = inst->children;
5564 if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5565 int nbsorts = 0;
5566 xmlNodePtr sorts[XSLT_MAX_SORT];
5567
5568 sorts[nbsorts++] = curInst;
5569
5570 #ifdef WITH_DEBUGGER
5571 if (xslDebugStatus != XSLT_DEBUG_NONE)
5572 xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5573 #endif
5574
5575 curInst = curInst->next;
5576 while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5577 if (nbsorts >= XSLT_MAX_SORT) {
5578 xsltTransformError(ctxt, NULL, curInst,
5579 "The number of xsl:sort instructions exceeds the "
5580 "maximum (%d) allowed by this processor.\n",
5581 XSLT_MAX_SORT);
5582 goto error;
5583 } else {
5584 sorts[nbsorts++] = curInst;
5585 }
5586
5587 #ifdef WITH_DEBUGGER
5588 if (xslDebugStatus != XSLT_DEBUG_NONE)
5589 xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5590 #endif
5591 curInst = curInst->next;
5592 }
5593 xsltDoSortFunction(ctxt, sorts, nbsorts);
5594 }
5595 xpctxt->contextSize = list->nodeNr;
5596 /*
5597 * Instantiate the sequence constructor for each selected node.
5598 */
5599 for (i = 0; i < list->nodeNr; i++) {
5600 cur = list->nodeTab[i];
5601 /*
5602 * The selected node becomes the "current node".
5603 */
5604 ctxt->node = cur;
5605 /*
5606 * An xsl:for-each can change the current context doc.
5607 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5608 */
5609 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5610 xpctxt->doc = cur->doc;
5611
5612 xpctxt->proximityPosition = i + 1;
5613
5614 xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
5615 }
5616
5617 exit:
5618 error:
5619 if (res != NULL)
5620 xmlXPathFreeObject(res);
5621 /*
5622 * Restore old states.
5623 */
5624 ctxt->document = oldDocInfo;
5625 ctxt->nodeList = oldList;
5626 ctxt->node = oldContextNode;
5627 ctxt->currentTemplateRule = oldCurTemplRule;
5628
5629 xpctxt->doc = oldXPDoc;
5630 xpctxt->contextSize = oldXPContextSize;
5631 xpctxt->proximityPosition = oldXPProximityPosition;
5632 }
5633
5634 /************************************************************************
5635 * *
5636 * Generic interface *
5637 * *
5638 ************************************************************************/
5639
5640 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5641 typedef struct xsltHTMLVersion {
5642 const char *version;
5643 const char *public;
5644 const char *system;
5645 } xsltHTMLVersion;
5646
5647 static xsltHTMLVersion xsltHTMLVersions[] = {
5648 { "5", NULL, "about:legacy-compat" },
5649 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5650 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5651 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5652 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5653 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5654 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5655 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5656 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5657 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5658 "http://www.w3.org/TR/html4/strict.dtd"},
5659 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5660 "http://www.w3.org/TR/html4/loose.dtd"},
5661 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5662 "http://www.w3.org/TR/html4/frameset.dtd"},
5663 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5664 "http://www.w3.org/TR/html4/loose.dtd"},
5665 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
5666 };
5667
5668 /**
5669 * xsltGetHTMLIDs:
5670 * @version: the version string
5671 * @publicID: used to return the public ID
5672 * @systemID: used to return the system ID
5673 *
5674 * Returns -1 if not found, 0 otherwise and the system and public
5675 * Identifier for this given verion of HTML
5676 */
5677 static int
5678 xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
5679 const xmlChar **systemID) {
5680 unsigned int i;
5681 if (version == NULL)
5682 return(-1);
5683 for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
5684 i++) {
5685 if (!xmlStrcasecmp(version,
5686 (const xmlChar *) xsltHTMLVersions[i].version)) {
5687 if (publicID != NULL)
5688 *publicID = (const xmlChar *) xsltHTMLVersions[i].public;
5689 if (systemID != NULL)
5690 *systemID = (const xmlChar *) xsltHTMLVersions[i].system;
5691 return(0);
5692 }
5693 }
5694 return(-1);
5695 }
5696 #endif
5697
5698 /**
5699 * xsltApplyStripSpaces:
5700 * @ctxt: a XSLT process context
5701 * @node: the root of the XML tree
5702 *
5703 * Strip the unwanted ignorable spaces from the input tree
5704 */
5705 void
5706 xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
5707 xmlNodePtr current;
5708 #ifdef WITH_XSLT_DEBUG_PROCESS
5709 int nb = 0;
5710 #endif
5711
5712
5713 current = node;
5714 while (current != NULL) {
5715 /*
5716 * Cleanup children empty nodes if asked for
5717 */
5718 if ((IS_XSLT_REAL_NODE(current)) &&
5719 (current->children != NULL) &&
5720 (xsltFindElemSpaceHandling(ctxt, current))) {
5721 xmlNodePtr delete = NULL, cur = current->children;
5722
5723 while (cur != NULL) {
5724 if (IS_BLANK_NODE(cur))
5725 delete = cur;
5726
5727 cur = cur->next;
5728 if (delete != NULL) {
5729 xmlUnlinkNode(delete);
5730 xmlFreeNode(delete);
5731 delete = NULL;
5732 #ifdef WITH_XSLT_DEBUG_PROCESS
5733 nb++;
5734 #endif
5735 }
5736 }
5737 }
5738
5739 /*
5740 * Skip to next node in document order.
5741 */
5742 if (node->type == XML_ENTITY_REF_NODE) {
5743 /* process deep in entities */
5744 xsltApplyStripSpaces(ctxt, node->children);
5745 }
5746 if ((current->children != NULL) &&
5747 (current->type != XML_ENTITY_REF_NODE)) {
5748 current = current->children;
5749 } else if (current->next != NULL) {
5750 current = current->next;
5751 } else {
5752 do {
5753 current = current->parent;
5754 if (current == NULL)
5755 break;
5756 if (current == node)
5757 goto done;
5758 if (current->next != NULL) {
5759 current = current->next;
5760 break;
5761 }
5762 } while (current != NULL);
5763 }
5764 }
5765
5766 done:
5767 #ifdef WITH_XSLT_DEBUG_PROCESS
5768 XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugCon text,
5769 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
5770 #endif
5771 return;
5772 }
5773
5774 static int
5775 xsltCountKeys(xsltTransformContextPtr ctxt)
5776 {
5777 xsltStylesheetPtr style;
5778 xsltKeyDefPtr keyd;
5779
5780 if (ctxt == NULL)
5781 return(-1);
5782
5783 /*
5784 * Do we have those nastly templates with a key() in the match pattern?
5785 */
5786 ctxt->hasTemplKeyPatterns = 0;
5787 style = ctxt->style;
5788 while (style != NULL) {
5789 if (style->keyMatch != NULL) {
5790 ctxt->hasTemplKeyPatterns = 1;
5791 break;
5792 }
5793 style = xsltNextImport(style);
5794 }
5795 /*
5796 * Count number of key declarations.
5797 */
5798 ctxt->nbKeys = 0;
5799 style = ctxt->style;
5800 while (style != NULL) {
5801 keyd = style->keys;
5802 while (keyd) {
5803 ctxt->nbKeys++;
5804 keyd = keyd->next;
5805 }
5806 style = xsltNextImport(style);
5807 }
5808 return(ctxt->nbKeys);
5809 }
5810
5811 /**
5812 * xsltApplyStylesheetInternal:
5813 * @style: a parsed XSLT stylesheet
5814 * @doc: a parsed XML document
5815 * @params: a NULL terminated array of parameters names/values tuples
5816 * @output: the targetted output
5817 * @profile: profile FILE * output or NULL
5818 * @user: user provided parameter
5819 *
5820 * Apply the stylesheet to the document
5821 * NOTE: This may lead to a non-wellformed output XML wise !
5822 *
5823 * Returns the result document or NULL in case of error
5824 */
5825 static xmlDocPtr
5826 xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
5827 const char **params, const char *output,
5828 FILE * profile, xsltTransformContextPtr userCtxt)
5829 {
5830 xmlDocPtr res = NULL;
5831 xsltTransformContextPtr ctxt = NULL;
5832 xmlNodePtr root, node;
5833 const xmlChar *method;
5834 const xmlChar *doctypePublic;
5835 const xmlChar *doctypeSystem;
5836 const xmlChar *version;
5837 const xmlChar *encoding;
5838 xsltStackElemPtr variables;
5839 xsltStackElemPtr vptr;
5840
5841 xsltInitGlobals();
5842
5843 if ((style == NULL) || (doc == NULL))
5844 return (NULL);
5845
5846 if (style->internalized == 0) {
5847 #ifdef WITH_XSLT_DEBUG
5848 xsltGenericDebug(xsltGenericDebugContext,
5849 "Stylesheet was not fully internalized !\n");
5850 #endif
5851 }
5852 if (doc->intSubset != NULL) {
5853 /*
5854 * Avoid hitting the DTD when scanning nodes
5855 * but keep it linked as doc->intSubset
5856 */
5857 xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
5858 if (cur->next != NULL)
5859 cur->next->prev = cur->prev;
5860 if (cur->prev != NULL)
5861 cur->prev->next = cur->next;
5862 if (doc->children == cur)
5863 doc->children = cur->next;
5864 if (doc->last == cur)
5865 doc->last = cur->prev;
5866 cur->prev = cur->next = NULL;
5867 }
5868
5869 /*
5870 * Check for XPath document order availability
5871 */
5872 root = xmlDocGetRootElement(doc);
5873 if (root != NULL) {
5874 if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE))
5875 xmlXPathOrderDocElems(doc);
5876 }
5877
5878 if (userCtxt != NULL)
5879 ctxt = userCtxt;
5880 else
5881 ctxt = xsltNewTransformContext(style, doc);
5882
5883 if (ctxt == NULL)
5884 return (NULL);
5885
5886 ctxt->initialContextDoc = doc;
5887 ctxt->initialContextNode = (xmlNodePtr) doc;
5888
5889 if (profile != NULL)
5890 ctxt->profile = 1;
5891
5892 if (output != NULL)
5893 ctxt->outputFile = output;
5894 else
5895 ctxt->outputFile = NULL;
5896
5897 /*
5898 * internalize the modes if needed
5899 */
5900 if (ctxt->dict != NULL) {
5901 if (ctxt->mode != NULL)
5902 ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
5903 if (ctxt->modeURI != NULL)
5904 ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
5905 }
5906
5907 XSLT_GET_IMPORT_PTR(method, style, method)
5908 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
5909 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
5910 XSLT_GET_IMPORT_PTR(version, style, version)
5911 XSLT_GET_IMPORT_PTR(encoding, style, encoding)
5912
5913 if ((method != NULL) &&
5914 (!xmlStrEqual(method, (const xmlChar *) "xml")))
5915 {
5916 if (xmlStrEqual(method, (const xmlChar *) "html")) {
5917 ctxt->type = XSLT_OUTPUT_HTML;
5918 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
5919 res = htmlNewDoc(doctypeSystem, doctypePublic);
5920 } else {
5921 if (version == NULL) {
5922 xmlDtdPtr dtd;
5923
5924 res = htmlNewDoc(NULL, NULL);
5925 /*
5926 * Make sure no DTD node is generated in this case
5927 */
5928 if (res != NULL) {
5929 dtd = xmlGetIntSubset(res);
5930 if (dtd != NULL) {
5931 xmlUnlinkNode((xmlNodePtr) dtd);
5932 xmlFreeDtd(dtd);
5933 }
5934 res->intSubset = NULL;
5935 res->extSubset = NULL;
5936 }
5937 } else {
5938
5939 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5940 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
5941 #endif
5942 res = htmlNewDoc(doctypeSystem, doctypePublic);
5943 }
5944 }
5945 if (res == NULL)
5946 goto error;
5947 res->dict = ctxt->dict;
5948 xmlDictReference(res->dict);
5949
5950 #ifdef WITH_XSLT_DEBUG
5951 xsltGenericDebug(xsltGenericDebugContext,
5952 "reusing transformation dict for output\n");
5953 #endif
5954 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
5955 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5956 "xsltApplyStylesheetInternal: unsupported method xhtml, using ht ml\n");
5957 ctxt->type = XSLT_OUTPUT_HTML;
5958 res = htmlNewDoc(doctypeSystem, doctypePublic);
5959 if (res == NULL)
5960 goto error;
5961 res->dict = ctxt->dict;
5962 xmlDictReference(res->dict);
5963
5964 #ifdef WITH_XSLT_DEBUG
5965 xsltGenericDebug(xsltGenericDebugContext,
5966 "reusing transformation dict for output\n");
5967 #endif
5968 } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
5969 ctxt->type = XSLT_OUTPUT_TEXT;
5970 res = xmlNewDoc(style->version);
5971 if (res == NULL)
5972 goto error;
5973 res->dict = ctxt->dict;
5974 xmlDictReference(res->dict);
5975
5976 #ifdef WITH_XSLT_DEBUG
5977 xsltGenericDebug(xsltGenericDebugContext,
5978 "reusing transformation dict for output\n");
5979 #endif
5980 } else {
5981 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5982 "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5983 method);
5984 goto error;
5985 }
5986 } else {
5987 ctxt->type = XSLT_OUTPUT_XML;
5988 res = xmlNewDoc(style->version);
5989 if (res == NULL)
5990 goto error;
5991 res->dict = ctxt->dict;
5992 xmlDictReference(ctxt->dict);
5993 #ifdef WITH_XSLT_DEBUG
5994 xsltGenericDebug(xsltGenericDebugContext,
5995 "reusing transformation dict for output\n");
5996 #endif
5997 }
5998 res->charset = XML_CHAR_ENCODING_UTF8;
5999 if (encoding != NULL)
6000 res->encoding = xmlStrdup(encoding);
6001 variables = style->variables;
6002
6003 /*
6004 * Start the evaluation, evaluate the params, the stylesheets globals
6005 * and start by processing the top node.
6006 */
6007 if (xsltNeedElemSpaceHandling(ctxt))
6008 xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
6009 /*
6010 * Evaluate global params and user-provided params.
6011 */
6012 ctxt->node = (xmlNodePtr) doc;
6013 if (ctxt->globalVars == NULL)
6014 ctxt->globalVars = xmlHashCreate(20);
6015 if (params != NULL) {
6016 xsltEvalUserParams(ctxt, params);
6017 }
6018
6019 /* need to be called before evaluating global variables */
6020 xsltCountKeys(ctxt);
6021
6022 xsltEvalGlobalVariables(ctxt);
6023
6024 /* Clean up any unused RVTs. */
6025 xsltReleaseLocalRVTs(ctxt, NULL);
6026
6027 ctxt->node = (xmlNodePtr) doc;
6028 ctxt->output = res;
6029 ctxt->insert = (xmlNodePtr) res;
6030 ctxt->varsBase = ctxt->varsNr - 1;
6031
6032 ctxt->xpathCtxt->contextSize = 1;
6033 ctxt->xpathCtxt->proximityPosition = 1;
6034 ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
6035 /*
6036 * Start processing the source tree -----------------------------------
6037 */
6038 xsltProcessOneNode(ctxt, ctxt->node, NULL);
6039 /*
6040 * Remove all remaining vars from the stack.
6041 */
6042 xsltLocalVariablePop(ctxt, 0, -2);
6043 xsltShutdownCtxtExts(ctxt);
6044
6045 xsltCleanupTemplates(style); /* TODO: <- style should be read only */
6046
6047 /*
6048 * Now cleanup our variables so stylesheet can be re-used
6049 *
6050 * TODO: this is not needed anymore global variables are copied
6051 * and not evaluated directly anymore, keep this as a check
6052 */
6053 if (style->variables != variables) {
6054 vptr = style->variables;
6055 while (vptr->next != variables)
6056 vptr = vptr->next;
6057 vptr->next = NULL;
6058 xsltFreeStackElemList(style->variables);
6059 style->variables = variables;
6060 }
6061 vptr = style->variables;
6062 while (vptr != NULL) {
6063 if (vptr->computed) {
6064 if (vptr->value != NULL) {
6065 xmlXPathFreeObject(vptr->value);
6066 vptr->value = NULL;
6067 vptr->computed = 0;
6068 }
6069 }
6070 vptr = vptr->next;
6071 }
6072 #if 0
6073 /*
6074 * code disabled by wmb; awaiting kb's review
6075 * problem is that global variable(s) may contain xpath objects
6076 * from doc associated with RVT, so can't be freed at this point.
6077 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6078 * I assume this shouldn't be required at this point.
6079 */
6080 /*
6081 * Free all remaining tree fragments.
6082 */
6083 xsltFreeRVTs(ctxt);
6084 #endif
6085 /*
6086 * Do some post processing work depending on the generated output
6087 */
6088 root = xmlDocGetRootElement(res);
6089 if (root != NULL) {
6090 const xmlChar *doctype = NULL;
6091
6092 if ((root->ns != NULL) && (root->ns->prefix != NULL))
6093 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
6094 if (doctype == NULL)
6095 doctype = root->name;
6096
6097 /*
6098 * Apply the default selection of the method
6099 */
6100 if ((method == NULL) &&
6101 (root->ns == NULL) &&
6102 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
6103 xmlNodePtr tmp;
6104
6105 tmp = res->children;
6106 while ((tmp != NULL) && (tmp != root)) {
6107 if (tmp->type == XML_ELEMENT_NODE)
6108 break;
6109 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
6110 break;
6111 tmp = tmp->next;
6112 }
6113 if (tmp == root) {
6114 ctxt->type = XSLT_OUTPUT_HTML;
6115 /*
6116 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6117 * transformation on the doc, but functions like
6118 */
6119 res->type = XML_HTML_DOCUMENT_NODE;
6120 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6121 res->intSubset = xmlCreateIntSubset(res, doctype,
6122 doctypePublic,
6123 doctypeSystem);
6124 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6125 } else if (version != NULL) {
6126 xsltGetHTMLIDs(version, &doctypePublic,
6127 &doctypeSystem);
6128 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
6129 res->intSubset =
6130 xmlCreateIntSubset(res, doctype,
6131 doctypePublic,
6132 doctypeSystem);
6133 #endif
6134 }
6135 }
6136
6137 }
6138 if (ctxt->type == XSLT_OUTPUT_XML) {
6139 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
6140 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
6141 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6142 xmlNodePtr last;
6143 /* Need a small "hack" here to assure DTD comes before
6144 possible comment nodes */
6145 node = res->children;
6146 last = res->last;
6147 res->children = NULL;
6148 res->last = NULL;
6149 res->intSubset = xmlCreateIntSubset(res, doctype,
6150 doctypePublic,
6151 doctypeSystem);
6152 if (res->children != NULL) {
6153 res->children->next = node;
6154 node->prev = res->children;
6155 res->last = last;
6156 } else {
6157 res->children = node;
6158 res->last = last;
6159 }
6160 }
6161 }
6162 }
6163 xmlXPathFreeNodeSet(ctxt->nodeList);
6164 if (profile != NULL) {
6165 xsltSaveProfiling(ctxt, profile);
6166 }
6167
6168 /*
6169 * Be pedantic.
6170 */
6171 if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) {
6172 xmlFreeDoc(res);
6173 res = NULL;
6174 }
6175 if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
6176 int ret;
6177
6178 ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
6179 if (ret == 0) {
6180 xsltTransformError(ctxt, NULL, NULL,
6181 "xsltApplyStylesheet: forbidden to save to %s\n",
6182 output);
6183 } else if (ret < 0) {
6184 xsltTransformError(ctxt, NULL, NULL,
6185 "xsltApplyStylesheet: saving to %s may not be possible\n",
6186 output);
6187 }
6188 }
6189
6190 #ifdef XSLT_DEBUG_PROFILE_CACHE
6191 printf("# Cache:\n");
6192 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6193 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);
6194 #endif
6195
6196 if ((ctxt != NULL) && (userCtxt == NULL))
6197 xsltFreeTransformContext(ctxt);
6198
6199 return (res);
6200
6201 error:
6202 if (res != NULL)
6203 xmlFreeDoc(res);
6204
6205 #ifdef XSLT_DEBUG_PROFILE_CACHE
6206 printf("# Cache:\n");
6207 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6208 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);
6209 #endif
6210
6211 if ((ctxt != NULL) && (userCtxt == NULL))
6212 xsltFreeTransformContext(ctxt);
6213 return (NULL);
6214 }
6215
6216 /**
6217 * xsltApplyStylesheet:
6218 * @style: a parsed XSLT stylesheet
6219 * @doc: a parsed XML document
6220 * @params: a NULL terminated arry of parameters names/values tuples
6221 *
6222 * Apply the stylesheet to the document
6223 * NOTE: This may lead to a non-wellformed output XML wise !
6224 *
6225 * Returns the result document or NULL in case of error
6226 */
6227 xmlDocPtr
6228 xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6229 const char **params)
6230 {
6231 return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
6232 }
6233
6234 /**
6235 * xsltProfileStylesheet:
6236 * @style: a parsed XSLT stylesheet
6237 * @doc: a parsed XML document
6238 * @params: a NULL terminated arry of parameters names/values tuples
6239 * @output: a FILE * for the profiling output
6240 *
6241 * Apply the stylesheet to the document and dump the profiling to
6242 * the given output.
6243 *
6244 * Returns the result document or NULL in case of error
6245 */
6246 xmlDocPtr
6247 xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6248 const char **params, FILE * output)
6249 {
6250 xmlDocPtr res;
6251
6252 res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
6253 return (res);
6254 }
6255
6256 /**
6257 * xsltApplyStylesheetUser:
6258 * @style: a parsed XSLT stylesheet
6259 * @doc: a parsed XML document
6260 * @params: a NULL terminated array of parameters names/values tuples
6261 * @output: the targetted output
6262 * @profile: profile FILE * output or NULL
6263 * @userCtxt: user provided transform context
6264 *
6265 * Apply the stylesheet to the document and allow the user to provide
6266 * its own transformation context.
6267 *
6268 * Returns the result document or NULL in case of error
6269 */
6270 xmlDocPtr
6271 xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6272 const char **params, const char *output,
6273 FILE * profile, xsltTransformContextPtr userCtxt)
6274 {
6275 xmlDocPtr res;
6276
6277 res = xsltApplyStylesheetInternal(style, doc, params, output,
6278 profile, userCtxt);
6279 return (res);
6280 }
6281
6282 /**
6283 * xsltRunStylesheetUser:
6284 * @style: a parsed XSLT stylesheet
6285 * @doc: a parsed XML document
6286 * @params: a NULL terminated array of parameters names/values tuples
6287 * @output: the URL/filename ot the generated resource if available
6288 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6289 * @IObuf: an output buffer for progressive output (not implemented yet)
6290 * @profile: profile FILE * output or NULL
6291 * @userCtxt: user provided transform context
6292 *
6293 * Apply the stylesheet to the document and generate the output according
6294 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6295 *
6296 * NOTE: This may lead to a non-wellformed output XML wise !
6297 * NOTE: This may also result in multiple files being generated
6298 * NOTE: using IObuf, the result encoding used will be the one used for
6299 * creating the output buffer, use the following macro to read it
6300 * from the stylesheet
6301 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6302 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6303 * since the interface uses only UTF8
6304 *
6305 * Returns the number of by written to the main resource or -1 in case of
6306 * error.
6307 */
6308 int
6309 xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6310 const char **params, const char *output,
6311 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
6312 FILE * profile, xsltTransformContextPtr userCtxt)
6313 {
6314 xmlDocPtr tmp;
6315 int ret;
6316
6317 if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
6318 return (-1);
6319 if ((SAX != NULL) && (IObuf != NULL))
6320 return (-1);
6321
6322 /* unsupported yet */
6323 if (SAX != NULL) {
6324 XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6325 return (-1);
6326 }
6327
6328 tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
6329 userCtxt);
6330 if (tmp == NULL) {
6331 xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
6332 "xsltRunStylesheet : run failed\n");
6333 return (-1);
6334 }
6335 if (IObuf != NULL) {
6336 /* TODO: incomplete, IObuf output not progressive */
6337 ret = xsltSaveResultTo(IObuf, tmp, style);
6338 } else {
6339 ret = xsltSaveResultToFilename(output, tmp, style, 0);
6340 }
6341 xmlFreeDoc(tmp);
6342 return (ret);
6343 }
6344
6345 /**
6346 * xsltRunStylesheet:
6347 * @style: a parsed XSLT stylesheet
6348 * @doc: a parsed XML document
6349 * @params: a NULL terminated array of parameters names/values tuples
6350 * @output: the URL/filename ot the generated resource if available
6351 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6352 * @IObuf: an output buffer for progressive output (not implemented yet)
6353 *
6354 * Apply the stylesheet to the document and generate the output according
6355 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6356 *
6357 * NOTE: This may lead to a non-wellformed output XML wise !
6358 * NOTE: This may also result in multiple files being generated
6359 * NOTE: using IObuf, the result encoding used will be the one used for
6360 * creating the output buffer, use the following macro to read it
6361 * from the stylesheet
6362 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6363 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6364 * since the interface uses only UTF8
6365 *
6366 * Returns the number of bytes written to the main resource or -1 in case of
6367 * error.
6368 */
6369 int
6370 xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6371 const char **params, const char *output,
6372 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
6373 {
6374 return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
6375 NULL, NULL));
6376 }
6377
6378 /**
6379 * xsltRegisterAllElement:
6380 * @ctxt: the XPath context
6381 *
6382 * Registers all default XSLT elements in this context
6383 */
6384 void
6385 xsltRegisterAllElement(xsltTransformContextPtr ctxt)
6386 {
6387 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
6388 XSLT_NAMESPACE,
6389 (xsltTransformFunction) xsltApplyTemplates);
6390 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
6391 XSLT_NAMESPACE,
6392 (xsltTransformFunction) xsltApplyImports);
6393 xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
6394 XSLT_NAMESPACE,
6395 (xsltTransformFunction) xsltCallTemplate);
6396 xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
6397 XSLT_NAMESPACE,
6398 (xsltTransformFunction) xsltElement);
6399 xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
6400 XSLT_NAMESPACE,
6401 (xsltTransformFunction) xsltAttribute);
6402 xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
6403 XSLT_NAMESPACE,
6404 (xsltTransformFunction) xsltText);
6405 xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
6406 XSLT_NAMESPACE,
6407 (xsltTransformFunction) xsltProcessingInstruction);
6408 xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
6409 XSLT_NAMESPACE,
6410 (xsltTransformFunction) xsltComment);
6411 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
6412 XSLT_NAMESPACE,
6413 (xsltTransformFunction) xsltCopy);
6414 xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
6415 XSLT_NAMESPACE,
6416 (xsltTransformFunction) xsltValueOf);
6417 xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
6418 XSLT_NAMESPACE,
6419 (xsltTransformFunction) xsltNumber);
6420 xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
6421 XSLT_NAMESPACE,
6422 (xsltTransformFunction) xsltForEach);
6423 xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
6424 XSLT_NAMESPACE,
6425 (xsltTransformFunction) xsltIf);
6426 xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
6427 XSLT_NAMESPACE,
6428 (xsltTransformFunction) xsltChoose);
6429 xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
6430 XSLT_NAMESPACE,
6431 (xsltTransformFunction) xsltSort);
6432 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
6433 XSLT_NAMESPACE,
6434 (xsltTransformFunction) xsltCopyOf);
6435 xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
6436 XSLT_NAMESPACE,
6437 (xsltTransformFunction) xsltMessage);
6438
6439 /*
6440 * Those don't have callable entry points but are registered anyway
6441 */
6442 xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
6443 XSLT_NAMESPACE,
6444 (xsltTransformFunction) xsltDebug);
6445 xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
6446 XSLT_NAMESPACE,
6447 (xsltTransformFunction) xsltDebug);
6448 xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
6449 XSLT_NAMESPACE,
6450 (xsltTransformFunction) xsltDebug);
6451 xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
6452 XSLT_NAMESPACE,
6453 (xsltTransformFunction) xsltDebug);
6454 xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
6455 XSLT_NAMESPACE,
6456 (xsltTransformFunction) xsltDebug);
6457 xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
6458 XSLT_NAMESPACE,
6459 (xsltTransformFunction) xsltDebug);
6460 xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
6461 XSLT_NAMESPACE,
6462 (xsltTransformFunction) xsltDebug);
6463
6464 }
OLDNEW
« no previous file with comments | « third_party/libxslt/libxslt/transform.h ('k') | third_party/libxslt/libxslt/trio.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698