[LIBXSLT] Update to version 1.1.32. CORE-14291
[reactos.git] / dll / 3rdparty / libxslt / transform.c
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 #include "precomp.h"
20
21 #include <libxml/debugXML.h>
22
23 #ifdef WITH_XSLT_DEBUG
24 #define WITH_XSLT_DEBUG_EXTRA
25 #define WITH_XSLT_DEBUG_PROCESS
26 #define WITH_XSLT_DEBUG_VARIABLE
27 #endif
28
29 #define XSLT_GENERATE_HTML_DOCTYPE
30 #ifdef XSLT_GENERATE_HTML_DOCTYPE
31 static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
32 const xmlChar **systemID);
33 #endif
34
35 int xsltMaxDepth = 3000;
36 int xsltMaxVars = 15000;
37
38 /*
39 * Useful macros
40 */
41
42 #ifndef FALSE
43 # define FALSE (0 == 1)
44 # define TRUE (!FALSE)
45 #endif
46
47 #define IS_BLANK_NODE(n) \
48 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
49
50
51 /*
52 * Forward declarations
53 */
54
55 static xmlNsPtr
56 xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
57
58 static xmlNodePtr
59 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
60 xmlNodePtr node, xmlNodePtr insert, int isLRE,
61 int topElemVisited);
62
63 static void
64 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
65 xmlNodePtr contextNode, xmlNodePtr list,
66 xsltTemplatePtr templ);
67
68 static void
69 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
70 xmlNodePtr contextNode,
71 xmlNodePtr list,
72 xsltTemplatePtr templ,
73 xsltStackElemPtr withParams);
74
75 /**
76 * templPush:
77 * @ctxt: the transformation context
78 * @value: the template to push on the stack
79 *
80 * Push a template on the stack
81 *
82 * Returns the new index in the stack or 0 in case of error
83 */
84 static int
85 templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
86 {
87 if (ctxt->templMax == 0) {
88 ctxt->templMax = 4;
89 ctxt->templTab =
90 (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *
91 sizeof(ctxt->templTab[0]));
92 if (ctxt->templTab == NULL) {
93 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
94 return (0);
95 }
96 }
97 else if (ctxt->templNr >= ctxt->templMax) {
98 ctxt->templMax *= 2;
99 ctxt->templTab =
100 (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
101 ctxt->templMax *
102 sizeof(ctxt->templTab[0]));
103 if (ctxt->templTab == NULL) {
104 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
105 return (0);
106 }
107 }
108 ctxt->templTab[ctxt->templNr] = value;
109 ctxt->templ = value;
110 return (ctxt->templNr++);
111 }
112 /**
113 * templPop:
114 * @ctxt: the transformation context
115 *
116 * Pop a template value from the stack
117 *
118 * Returns the stored template value
119 */
120 static xsltTemplatePtr
121 templPop(xsltTransformContextPtr ctxt)
122 {
123 xsltTemplatePtr ret;
124
125 if (ctxt->templNr <= 0)
126 return (0);
127 ctxt->templNr--;
128 if (ctxt->templNr > 0)
129 ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
130 else
131 ctxt->templ = (xsltTemplatePtr) 0;
132 ret = ctxt->templTab[ctxt->templNr];
133 ctxt->templTab[ctxt->templNr] = 0;
134 return (ret);
135 }
136
137 /**
138 * xsltLocalVariablePop:
139 * @ctxt: the transformation context
140 * @limitNr: number of variables which should remain
141 * @level: the depth in the xsl:template's tree
142 *
143 * Pops all variable values at the given @depth from the stack.
144 *
145 * Returns the stored variable value
146 * **NOTE:**
147 * This is an internal routine and should not be called by users!
148 */
149 void
150 xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
151 {
152 xsltStackElemPtr variable;
153
154 if (ctxt->varsNr <= 0)
155 return;
156
157 do {
158 if (ctxt->varsNr <= limitNr)
159 break;
160 variable = ctxt->varsTab[ctxt->varsNr - 1];
161 if (variable->level <= level)
162 break;
163 if (variable->level >= 0)
164 xsltFreeStackElemList(variable);
165 ctxt->varsNr--;
166 } while (ctxt->varsNr != 0);
167 if (ctxt->varsNr > 0)
168 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
169 else
170 ctxt->vars = NULL;
171 }
172
173 /**
174 * xsltTemplateParamsCleanup:
175 *
176 * Removes xsl:param and xsl:with-param items from the
177 * variable-stack. Only xsl:with-param items are not freed.
178 */
179 static void
180 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
181 {
182 xsltStackElemPtr param;
183
184 for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
185 param = ctxt->varsTab[ctxt->varsNr -1];
186 /*
187 * Free xsl:param items.
188 * xsl:with-param items will have a level of -1 or -2.
189 */
190 if (param->level >= 0) {
191 xsltFreeStackElemList(param);
192 }
193 }
194 if (ctxt->varsNr > 0)
195 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
196 else
197 ctxt->vars = NULL;
198 }
199
200 /**
201 * profPush:
202 * @ctxt: the transformation context
203 * @value: the profiling value to push on the stack
204 *
205 * Push a profiling value on the stack
206 *
207 * Returns the new index in the stack or 0 in case of error
208 */
209 static int
210 profPush(xsltTransformContextPtr ctxt, long value)
211 {
212 if (ctxt->profMax == 0) {
213 ctxt->profMax = 4;
214 ctxt->profTab =
215 (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
216 if (ctxt->profTab == NULL) {
217 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
218 return (0);
219 }
220 }
221 else if (ctxt->profNr >= ctxt->profMax) {
222 ctxt->profMax *= 2;
223 ctxt->profTab =
224 (long *) xmlRealloc(ctxt->profTab,
225 ctxt->profMax * sizeof(ctxt->profTab[0]));
226 if (ctxt->profTab == NULL) {
227 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
228 return (0);
229 }
230 }
231 ctxt->profTab[ctxt->profNr] = value;
232 ctxt->prof = value;
233 return (ctxt->profNr++);
234 }
235 /**
236 * profPop:
237 * @ctxt: the transformation context
238 *
239 * Pop a profiling value from the stack
240 *
241 * Returns the stored profiling value
242 */
243 static long
244 profPop(xsltTransformContextPtr ctxt)
245 {
246 long ret;
247
248 if (ctxt->profNr <= 0)
249 return (0);
250 ctxt->profNr--;
251 if (ctxt->profNr > 0)
252 ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
253 else
254 ctxt->prof = (long) 0;
255 ret = ctxt->profTab[ctxt->profNr];
256 ctxt->profTab[ctxt->profNr] = 0;
257 return (ret);
258 }
259
260 static void
261 profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
262 {
263 int i;
264
265 if (templ->templMax == 0) {
266 templ->templMax = 4;
267 templ->templCalledTab =
268 (xsltTemplatePtr *) xmlMalloc(templ->templMax *
269 sizeof(templ->templCalledTab[0]));
270 templ->templCountTab =
271 (int *) xmlMalloc(templ->templMax *
272 sizeof(templ->templCountTab[0]));
273 if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
274 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
275 return;
276 }
277 }
278 else if (templ->templNr >= templ->templMax) {
279 templ->templMax *= 2;
280 templ->templCalledTab =
281 (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab,
282 templ->templMax *
283 sizeof(templ->templCalledTab[0]));
284 templ->templCountTab =
285 (int *) xmlRealloc(templ->templCountTab,
286 templ->templMax *
287 sizeof(templ->templCountTab[0]));
288 if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
289 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
290 return;
291 }
292 }
293
294 for (i = 0; i < templ->templNr; i++) {
295 if (templ->templCalledTab[i] == parent) {
296 templ->templCountTab[i]++;
297 break;
298 }
299 }
300 if (i == templ->templNr) {
301 /* not found, add new one */
302 templ->templCalledTab[templ->templNr] = parent;
303 templ->templCountTab[templ->templNr] = 1;
304 templ->templNr++;
305 }
306 }
307
308 /**
309 * xsltPreCompEval:
310 * @ctxt: transform context
311 * @node: context node
312 * @comp: precompiled expression
313 *
314 * Evaluate a precompiled XPath expression.
315 */
316 static xmlXPathObjectPtr
317 xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node,
318 xsltStylePreCompPtr comp) {
319 xmlXPathObjectPtr res;
320 xmlXPathContextPtr xpctxt;
321 xmlNodePtr oldXPContextNode;
322 xmlNsPtr *oldXPNamespaces;
323 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
324
325 xpctxt = ctxt->xpathCtxt;
326 oldXPContextNode = xpctxt->node;
327 oldXPProximityPosition = xpctxt->proximityPosition;
328 oldXPContextSize = xpctxt->contextSize;
329 oldXPNsNr = xpctxt->nsNr;
330 oldXPNamespaces = xpctxt->namespaces;
331
332 xpctxt->node = node;
333 #ifdef XSLT_REFACTORED
334 if (comp->inScopeNs != NULL) {
335 xpctxt->namespaces = comp->inScopeNs->list;
336 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
337 } else {
338 xpctxt->namespaces = NULL;
339 xpctxt->nsNr = 0;
340 }
341 #else
342 xpctxt->namespaces = comp->nsList;
343 xpctxt->nsNr = comp->nsNr;
344 #endif
345
346 res = xmlXPathCompiledEval(comp->comp, xpctxt);
347
348 xpctxt->node = oldXPContextNode;
349 xpctxt->proximityPosition = oldXPProximityPosition;
350 xpctxt->contextSize = oldXPContextSize;
351 xpctxt->nsNr = oldXPNsNr;
352 xpctxt->namespaces = oldXPNamespaces;
353
354 return(res);
355 }
356
357 /**
358 * xsltPreCompEvalToBoolean:
359 * @ctxt: transform context
360 * @node: context node
361 * @comp: precompiled expression
362 *
363 * Evaluate a precompiled XPath expression as boolean.
364 */
365 static int
366 xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node,
367 xsltStylePreCompPtr comp) {
368 int res;
369 xmlXPathContextPtr xpctxt;
370 xmlNodePtr oldXPContextNode;
371 xmlNsPtr *oldXPNamespaces;
372 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
373
374 xpctxt = ctxt->xpathCtxt;
375 oldXPContextNode = xpctxt->node;
376 oldXPProximityPosition = xpctxt->proximityPosition;
377 oldXPContextSize = xpctxt->contextSize;
378 oldXPNsNr = xpctxt->nsNr;
379 oldXPNamespaces = xpctxt->namespaces;
380
381 xpctxt->node = node;
382 #ifdef XSLT_REFACTORED
383 if (comp->inScopeNs != NULL) {
384 xpctxt->namespaces = comp->inScopeNs->list;
385 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
386 } else {
387 xpctxt->namespaces = NULL;
388 xpctxt->nsNr = 0;
389 }
390 #else
391 xpctxt->namespaces = comp->nsList;
392 xpctxt->nsNr = comp->nsNr;
393 #endif
394
395 res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
396
397 xpctxt->node = oldXPContextNode;
398 xpctxt->proximityPosition = oldXPProximityPosition;
399 xpctxt->contextSize = oldXPContextSize;
400 xpctxt->nsNr = oldXPNsNr;
401 xpctxt->namespaces = oldXPNamespaces;
402
403 return(res);
404 }
405
406 /************************************************************************
407 * *
408 * XInclude default settings *
409 * *
410 ************************************************************************/
411
412 static int xsltDoXIncludeDefault = 0;
413
414 /**
415 * xsltSetXIncludeDefault:
416 * @xinclude: whether to do XInclude processing
417 *
418 * Set whether XInclude should be processed on document being loaded by default
419 */
420 void
421 xsltSetXIncludeDefault(int xinclude) {
422 xsltDoXIncludeDefault = (xinclude != 0);
423 }
424
425 /**
426 * xsltGetXIncludeDefault:
427 *
428 * Provides the default state for XInclude processing
429 *
430 * Returns 0 if there is no processing 1 otherwise
431 */
432 int
433 xsltGetXIncludeDefault(void) {
434 return(xsltDoXIncludeDefault);
435 }
436
437 static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
438
439 /**
440 * xsltDebugSetDefaultTrace:
441 * @val: tracing level mask
442 *
443 * Set the default debug tracing level mask
444 */
445 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
446 xsltDefaultTrace = val;
447 }
448
449 /**
450 * xsltDebugGetDefaultTrace:
451 *
452 * Get the current default debug tracing level mask
453 *
454 * Returns the current default debug tracing level mask
455 */
456 xsltDebugTraceCodes xsltDebugGetDefaultTrace() {
457 return xsltDefaultTrace;
458 }
459
460 /************************************************************************
461 * *
462 * Handling of Transformation Contexts *
463 * *
464 ************************************************************************/
465
466 static xsltTransformCachePtr
467 xsltTransformCacheCreate(void)
468 {
469 xsltTransformCachePtr ret;
470
471 ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
472 if (ret == NULL) {
473 xsltTransformError(NULL, NULL, NULL,
474 "xsltTransformCacheCreate : malloc failed\n");
475 return(NULL);
476 }
477 memset(ret, 0, sizeof(xsltTransformCache));
478 return(ret);
479 }
480
481 static void
482 xsltTransformCacheFree(xsltTransformCachePtr cache)
483 {
484 if (cache == NULL)
485 return;
486 /*
487 * Free tree fragments.
488 */
489 if (cache->RVT) {
490 xmlDocPtr tmp, cur = cache->RVT;
491 while (cur) {
492 tmp = cur;
493 cur = (xmlDocPtr) cur->next;
494 if (tmp->_private != NULL) {
495 /*
496 * Tree the document info.
497 */
498 xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
499 xmlFree(tmp->_private);
500 }
501 xmlFreeDoc(tmp);
502 }
503 }
504 /*
505 * Free vars/params.
506 */
507 if (cache->stackItems) {
508 xsltStackElemPtr tmp, cur = cache->stackItems;
509 while (cur) {
510 tmp = cur;
511 cur = cur->next;
512 /*
513 * REVISIT TODO: Should be call a destruction-function
514 * instead?
515 */
516 xmlFree(tmp);
517 }
518 }
519 xmlFree(cache);
520 }
521
522 /**
523 * xsltNewTransformContext:
524 * @style: a parsed XSLT stylesheet
525 * @doc: the input document
526 *
527 * Create a new XSLT TransformContext
528 *
529 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
530 */
531 xsltTransformContextPtr
532 xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
533 xsltTransformContextPtr cur;
534 xsltDocumentPtr docu;
535 int i;
536
537 xsltInitGlobals();
538
539 cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
540 if (cur == NULL) {
541 xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
542 "xsltNewTransformContext : malloc failed\n");
543 return(NULL);
544 }
545 memset(cur, 0, sizeof(xsltTransformContext));
546
547 cur->cache = xsltTransformCacheCreate();
548 if (cur->cache == NULL)
549 goto internal_err;
550 /*
551 * setup of the dictionary must be done early as some of the
552 * processing later like key handling may need it.
553 */
554 cur->dict = xmlDictCreateSub(style->dict);
555 cur->internalized = ((style->internalized) && (cur->dict != NULL));
556 #ifdef WITH_XSLT_DEBUG
557 xsltGenericDebug(xsltGenericDebugContext,
558 "Creating sub-dictionary from stylesheet for transformation\n");
559 #endif
560
561 /*
562 * initialize the template stack
563 */
564 cur->templTab = (xsltTemplatePtr *)
565 xmlMalloc(10 * sizeof(xsltTemplatePtr));
566 if (cur->templTab == NULL) {
567 xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
568 "xsltNewTransformContext: out of memory\n");
569 goto internal_err;
570 }
571 cur->templNr = 0;
572 cur->templMax = 5;
573 cur->templ = NULL;
574 cur->maxTemplateDepth = xsltMaxDepth;
575
576 /*
577 * initialize the variables stack
578 */
579 cur->varsTab = (xsltStackElemPtr *)
580 xmlMalloc(10 * sizeof(xsltStackElemPtr));
581 if (cur->varsTab == NULL) {
582 xmlGenericError(xmlGenericErrorContext,
583 "xsltNewTransformContext: out of memory\n");
584 goto internal_err;
585 }
586 cur->varsNr = 0;
587 cur->varsMax = 10;
588 cur->vars = NULL;
589 cur->varsBase = 0;
590 cur->maxTemplateVars = xsltMaxVars;
591
592 /*
593 * the profiling stack is not initialized by default
594 */
595 cur->profTab = NULL;
596 cur->profNr = 0;
597 cur->profMax = 0;
598 cur->prof = 0;
599
600 cur->style = style;
601 xmlXPathInit();
602 cur->xpathCtxt = xmlXPathNewContext(doc);
603 if (cur->xpathCtxt == NULL) {
604 xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
605 "xsltNewTransformContext : xmlXPathNewContext failed\n");
606 goto internal_err;
607 }
608 /*
609 * Create an XPath cache.
610 */
611 if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
612 goto internal_err;
613 /*
614 * Initialize the extras array
615 */
616 if (style->extrasNr != 0) {
617 cur->extrasMax = style->extrasNr + 20;
618 cur->extras = (xsltRuntimeExtraPtr)
619 xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
620 if (cur->extras == NULL) {
621 xmlGenericError(xmlGenericErrorContext,
622 "xsltNewTransformContext: out of memory\n");
623 goto internal_err;
624 }
625 cur->extrasNr = style->extrasNr;
626 for (i = 0;i < cur->extrasMax;i++) {
627 cur->extras[i].info = NULL;
628 cur->extras[i].deallocate = NULL;
629 cur->extras[i].val.ptr = NULL;
630 }
631 } else {
632 cur->extras = NULL;
633 cur->extrasNr = 0;
634 cur->extrasMax = 0;
635 }
636
637 XSLT_REGISTER_VARIABLE_LOOKUP(cur);
638 XSLT_REGISTER_FUNCTION_LOOKUP(cur);
639 cur->xpathCtxt->nsHash = style->nsHash;
640 /*
641 * Initialize the registered external modules
642 */
643 xsltInitCtxtExts(cur);
644 /*
645 * Setup document element ordering for later efficiencies
646 * (bug 133289)
647 */
648 if (xslDebugStatus == XSLT_DEBUG_NONE)
649 xmlXPathOrderDocElems(doc);
650 /*
651 * Must set parserOptions before calling xsltNewDocument
652 * (bug 164530)
653 */
654 cur->parserOptions = XSLT_PARSE_OPTIONS;
655 docu = xsltNewDocument(cur, doc);
656 if (docu == NULL) {
657 xsltTransformError(cur, NULL, (xmlNodePtr)doc,
658 "xsltNewTransformContext : xsltNewDocument failed\n");
659 goto internal_err;
660 }
661 docu->main = 1;
662 cur->document = docu;
663 cur->inst = NULL;
664 cur->outputFile = NULL;
665 cur->sec = xsltGetDefaultSecurityPrefs();
666 cur->debugStatus = xslDebugStatus;
667 cur->traceCode = (unsigned long*) &xsltDefaultTrace;
668 cur->xinclude = xsltGetXIncludeDefault();
669 cur->keyInitLevel = 0;
670
671 return(cur);
672
673 internal_err:
674 if (cur != NULL)
675 xsltFreeTransformContext(cur);
676 return(NULL);
677 }
678
679 /**
680 * xsltFreeTransformContext:
681 * @ctxt: an XSLT parser context
682 *
683 * Free up the memory allocated by @ctxt
684 */
685 void
686 xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
687 if (ctxt == NULL)
688 return;
689
690 /*
691 * Shutdown the extension modules associated to the stylesheet
692 * used if needed.
693 */
694 xsltShutdownCtxtExts(ctxt);
695
696 if (ctxt->xpathCtxt != NULL) {
697 ctxt->xpathCtxt->nsHash = NULL;
698 xmlXPathFreeContext(ctxt->xpathCtxt);
699 }
700 if (ctxt->templTab != NULL)
701 xmlFree(ctxt->templTab);
702 if (ctxt->varsTab != NULL)
703 xmlFree(ctxt->varsTab);
704 if (ctxt->profTab != NULL)
705 xmlFree(ctxt->profTab);
706 if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
707 int i;
708
709 for (i = 0;i < ctxt->extrasNr;i++) {
710 if ((ctxt->extras[i].deallocate != NULL) &&
711 (ctxt->extras[i].info != NULL))
712 ctxt->extras[i].deallocate(ctxt->extras[i].info);
713 }
714 xmlFree(ctxt->extras);
715 }
716 xsltFreeGlobalVariables(ctxt);
717 xsltFreeDocuments(ctxt);
718 xsltFreeCtxtExts(ctxt);
719 xsltFreeRVTs(ctxt);
720 xsltTransformCacheFree(ctxt->cache);
721 xmlDictFree(ctxt->dict);
722 #ifdef WITH_XSLT_DEBUG
723 xsltGenericDebug(xsltGenericDebugContext,
724 "freeing transformation dictionary\n");
725 #endif
726 memset(ctxt, -1, sizeof(xsltTransformContext));
727 xmlFree(ctxt);
728 }
729
730 /************************************************************************
731 * *
732 * Copy of Nodes in an XSLT fashion *
733 * *
734 ************************************************************************/
735
736 /**
737 * xsltAddChild:
738 * @parent: the parent node
739 * @cur: the child node
740 *
741 * Wrapper version of xmlAddChild with a more consistent behaviour on
742 * error. One expect the use to be child = xsltAddChild(parent, child);
743 * and the routine will take care of not leaking on errors or node merge
744 *
745 * Returns the child is successfully attached or NULL if merged or freed
746 */
747 static xmlNodePtr
748 xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
749 xmlNodePtr ret;
750
751 if (cur == NULL)
752 return(NULL);
753 if (parent == NULL) {
754 xmlFreeNode(cur);
755 return(NULL);
756 }
757 ret = xmlAddChild(parent, cur);
758
759 return(ret);
760 }
761
762 /**
763 * xsltAddTextString:
764 * @ctxt: a XSLT process context
765 * @target: the text node where the text will be attached
766 * @string: the text string
767 * @len: the string length in byte
768 *
769 * Extend the current text node with the new string, it handles coalescing
770 *
771 * Returns: the text node
772 */
773 static xmlNodePtr
774 xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
775 const xmlChar *string, int len) {
776 /*
777 * optimization
778 */
779 if ((len <= 0) || (string == NULL) || (target == NULL))
780 return(target);
781
782 if (ctxt->lasttext == target->content) {
783 int minSize;
784
785 /* Check for integer overflow accounting for NUL terminator. */
786 if (len >= INT_MAX - ctxt->lasttuse) {
787 xsltTransformError(ctxt, NULL, target,
788 "xsltCopyText: text allocation failed\n");
789 return(NULL);
790 }
791 minSize = ctxt->lasttuse + len + 1;
792
793 if (ctxt->lasttsize < minSize) {
794 xmlChar *newbuf;
795 int size;
796 int extra;
797
798 /* Double buffer size but increase by at least 100 bytes. */
799 extra = minSize < 100 ? 100 : minSize;
800
801 /* Check for integer overflow. */
802 if (extra > INT_MAX - ctxt->lasttsize) {
803 size = INT_MAX;
804 }
805 else {
806 size = ctxt->lasttsize + extra;
807 }
808
809 newbuf = (xmlChar *) xmlRealloc(target->content,size);
810 if (newbuf == NULL) {
811 xsltTransformError(ctxt, NULL, target,
812 "xsltCopyText: text allocation failed\n");
813 return(NULL);
814 }
815 ctxt->lasttsize = size;
816 ctxt->lasttext = newbuf;
817 target->content = newbuf;
818 }
819 memcpy(&(target->content[ctxt->lasttuse]), string, len);
820 ctxt->lasttuse += len;
821 target->content[ctxt->lasttuse] = 0;
822 } else {
823 xmlNodeAddContent(target, string);
824 ctxt->lasttext = target->content;
825 len = xmlStrlen(target->content);
826 ctxt->lasttsize = len;
827 ctxt->lasttuse = len;
828 }
829 return(target);
830 }
831
832 /**
833 * xsltCopyTextString:
834 * @ctxt: a XSLT process context
835 * @target: the element where the text will be attached
836 * @string: the text string
837 * @noescape: should disable-escaping be activated for this text node.
838 *
839 * Adds @string to a newly created or an existent text node child of
840 * @target.
841 *
842 * Returns: the text node, where the text content of @cur is copied to.
843 * NULL in case of API or internal errors.
844 */
845 xmlNodePtr
846 xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
847 const xmlChar *string, int noescape)
848 {
849 xmlNodePtr copy;
850 int len;
851
852 if (string == NULL)
853 return(NULL);
854
855 #ifdef WITH_XSLT_DEBUG_PROCESS
856 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
857 "xsltCopyTextString: copy text %s\n",
858 string));
859 #endif
860
861 /*
862 * Play safe and reset the merging mechanism for every new
863 * target node.
864 */
865 if ((target == NULL) || (target->children == NULL)) {
866 ctxt->lasttext = NULL;
867 }
868
869 /* handle coalescing of text nodes here */
870 len = xmlStrlen(string);
871 if ((ctxt->type == XSLT_OUTPUT_XML) &&
872 (ctxt->style->cdataSection != NULL) &&
873 (target != NULL) &&
874 (target->type == XML_ELEMENT_NODE) &&
875 (((target->ns == NULL) &&
876 (xmlHashLookup2(ctxt->style->cdataSection,
877 target->name, NULL) != NULL)) ||
878 ((target->ns != NULL) &&
879 (xmlHashLookup2(ctxt->style->cdataSection,
880 target->name, target->ns->href) != NULL))))
881 {
882 /*
883 * Process "cdata-section-elements".
884 */
885 if ((target->last != NULL) &&
886 (target->last->type == XML_CDATA_SECTION_NODE))
887 {
888 return(xsltAddTextString(ctxt, target->last, string, len));
889 }
890 copy = xmlNewCDataBlock(ctxt->output, string, len);
891 } else if (noescape) {
892 /*
893 * Process "disable-output-escaping".
894 */
895 if ((target != NULL) && (target->last != NULL) &&
896 (target->last->type == XML_TEXT_NODE) &&
897 (target->last->name == xmlStringTextNoenc))
898 {
899 return(xsltAddTextString(ctxt, target->last, string, len));
900 }
901 copy = xmlNewTextLen(string, len);
902 if (copy != NULL)
903 copy->name = xmlStringTextNoenc;
904 } else {
905 /*
906 * Default processing.
907 */
908 if ((target != NULL) && (target->last != NULL) &&
909 (target->last->type == XML_TEXT_NODE) &&
910 (target->last->name == xmlStringText)) {
911 return(xsltAddTextString(ctxt, target->last, string, len));
912 }
913 copy = xmlNewTextLen(string, len);
914 }
915 if (copy != NULL && target != NULL)
916 copy = xsltAddChild(target, copy);
917 if (copy != NULL) {
918 ctxt->lasttext = copy->content;
919 ctxt->lasttsize = len;
920 ctxt->lasttuse = len;
921 } else {
922 xsltTransformError(ctxt, NULL, target,
923 "xsltCopyTextString: text copy failed\n");
924 ctxt->lasttext = NULL;
925 }
926 return(copy);
927 }
928
929 /**
930 * xsltCopyText:
931 * @ctxt: a XSLT process context
932 * @target: the element where the text will be attached
933 * @cur: the text or CDATA node
934 * @interned: the string is in the target doc dictionary
935 *
936 * Copy the text content of @cur and append it to @target's children.
937 *
938 * Returns: the text node, where the text content of @cur is copied to.
939 * NULL in case of API or internal errors.
940 */
941 static xmlNodePtr
942 xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
943 xmlNodePtr cur, int interned)
944 {
945 xmlNodePtr copy;
946
947 if ((cur->type != XML_TEXT_NODE) &&
948 (cur->type != XML_CDATA_SECTION_NODE))
949 return(NULL);
950 if (cur->content == NULL)
951 return(NULL);
952
953 #ifdef WITH_XSLT_DEBUG_PROCESS
954 if (cur->type == XML_CDATA_SECTION_NODE) {
955 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
956 "xsltCopyText: copy CDATA text %s\n",
957 cur->content));
958 } else if (cur->name == xmlStringTextNoenc) {
959 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
960 "xsltCopyText: copy unescaped text %s\n",
961 cur->content));
962 } else {
963 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
964 "xsltCopyText: copy text %s\n",
965 cur->content));
966 }
967 #endif
968
969 /*
970 * Play save and reset the merging mechanism for every new
971 * target node.
972 */
973 if ((target == NULL) || (target->children == NULL)) {
974 ctxt->lasttext = NULL;
975 }
976
977 if ((ctxt->style->cdataSection != NULL) &&
978 (ctxt->type == XSLT_OUTPUT_XML) &&
979 (target != NULL) &&
980 (target->type == XML_ELEMENT_NODE) &&
981 (((target->ns == NULL) &&
982 (xmlHashLookup2(ctxt->style->cdataSection,
983 target->name, NULL) != NULL)) ||
984 ((target->ns != NULL) &&
985 (xmlHashLookup2(ctxt->style->cdataSection,
986 target->name, target->ns->href) != NULL))))
987 {
988 /*
989 * Process "cdata-section-elements".
990 */
991 /*
992 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
993 */
994 /*
995 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
996 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
997 * TODO: Reported in #321505.
998 */
999 if ((target->last != NULL) &&
1000 (target->last->type == XML_CDATA_SECTION_NODE))
1001 {
1002 /*
1003 * Append to existing CDATA-section node.
1004 */
1005 copy = xsltAddTextString(ctxt, target->last, cur->content,
1006 xmlStrlen(cur->content));
1007 goto exit;
1008 } else {
1009 unsigned int len;
1010
1011 len = xmlStrlen(cur->content);
1012 copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
1013 if (copy == NULL)
1014 goto exit;
1015 ctxt->lasttext = copy->content;
1016 ctxt->lasttsize = len;
1017 ctxt->lasttuse = len;
1018 }
1019 } else if ((target != NULL) &&
1020 (target->last != NULL) &&
1021 /* both escaped or both non-escaped text-nodes */
1022 (((target->last->type == XML_TEXT_NODE) &&
1023 (target->last->name == cur->name)) ||
1024 /* non-escaped text nodes and CDATA-section nodes */
1025 (((target->last->type == XML_CDATA_SECTION_NODE) &&
1026 (cur->name == xmlStringTextNoenc)))))
1027 {
1028 /*
1029 * we are appending to an existing text node
1030 */
1031 copy = xsltAddTextString(ctxt, target->last, cur->content,
1032 xmlStrlen(cur->content));
1033 goto exit;
1034 } else if ((interned) && (target != NULL) &&
1035 (target->doc != NULL) &&
1036 (target->doc->dict == ctxt->dict))
1037 {
1038 /*
1039 * TODO: DO we want to use this also for "text" output?
1040 */
1041 copy = xmlNewTextLen(NULL, 0);
1042 if (copy == NULL)
1043 goto exit;
1044 if (cur->name == xmlStringTextNoenc)
1045 copy->name = xmlStringTextNoenc;
1046
1047 /*
1048 * Must confirm that content is in dict (bug 302821)
1049 * TODO: This check should be not needed for text coming
1050 * from the stylesheets
1051 */
1052 if (xmlDictOwns(ctxt->dict, cur->content))
1053 copy->content = cur->content;
1054 else {
1055 if ((copy->content = xmlStrdup(cur->content)) == NULL)
1056 return NULL;
1057 }
1058 } else {
1059 /*
1060 * normal processing. keep counters to extend the text node
1061 * in xsltAddTextString if needed.
1062 */
1063 unsigned int len;
1064
1065 len = xmlStrlen(cur->content);
1066 copy = xmlNewTextLen(cur->content, len);
1067 if (copy == NULL)
1068 goto exit;
1069 if (cur->name == xmlStringTextNoenc)
1070 copy->name = xmlStringTextNoenc;
1071 ctxt->lasttext = copy->content;
1072 ctxt->lasttsize = len;
1073 ctxt->lasttuse = len;
1074 }
1075 if (copy != NULL) {
1076 if (target != NULL) {
1077 copy->doc = target->doc;
1078 /*
1079 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1080 * to ensure that the optimized text-merging mechanism
1081 * won't interfere with normal node-merging in any case.
1082 */
1083 copy = xsltAddChild(target, copy);
1084 }
1085 } else {
1086 xsltTransformError(ctxt, NULL, target,
1087 "xsltCopyText: text copy failed\n");
1088 }
1089
1090 exit:
1091 if ((copy == NULL) || (copy->content == NULL)) {
1092 xsltTransformError(ctxt, NULL, target,
1093 "Internal error in xsltCopyText(): "
1094 "Failed to copy the string.\n");
1095 ctxt->state = XSLT_STATE_STOPPED;
1096 }
1097 return(copy);
1098 }
1099
1100 /**
1101 * xsltShallowCopyAttr:
1102 * @ctxt: a XSLT process context
1103 * @invocNode: responsible node in the stylesheet; used for error reports
1104 * @target: the element where the attribute will be grafted
1105 * @attr: the attribute to be copied
1106 *
1107 * Do a copy of an attribute.
1108 * Called by:
1109 * - xsltCopyTree()
1110 * - xsltCopyOf()
1111 * - xsltCopy()
1112 *
1113 * Returns: a new xmlAttrPtr, or NULL in case of error.
1114 */
1115 static xmlAttrPtr
1116 xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1117 xmlNodePtr target, xmlAttrPtr attr)
1118 {
1119 xmlAttrPtr copy;
1120 xmlChar *value;
1121
1122 if (attr == NULL)
1123 return(NULL);
1124
1125 if (target->type != XML_ELEMENT_NODE) {
1126 xsltTransformError(ctxt, NULL, invocNode,
1127 "Cannot add an attribute node to a non-element node.\n");
1128 return(NULL);
1129 }
1130
1131 if (target->children != NULL) {
1132 xsltTransformError(ctxt, NULL, invocNode,
1133 "Attribute nodes must be added before "
1134 "any child nodes to an element.\n");
1135 return(NULL);
1136 }
1137
1138 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1139 if (attr->ns != NULL) {
1140 xmlNsPtr ns;
1141
1142 ns = xsltGetSpecialNamespace(ctxt, invocNode,
1143 attr->ns->href, attr->ns->prefix, target);
1144 if (ns == NULL) {
1145 xsltTransformError(ctxt, NULL, invocNode,
1146 "Namespace fixup error: Failed to acquire an in-scope "
1147 "namespace binding of the copied attribute '{%s}%s'.\n",
1148 attr->ns->href, attr->name);
1149 /*
1150 * TODO: Should we just stop here?
1151 */
1152 }
1153 /*
1154 * Note that xmlSetNsProp() will take care of duplicates
1155 * and assigns the new namespace even to a duplicate.
1156 */
1157 copy = xmlSetNsProp(target, ns, attr->name, value);
1158 } else {
1159 copy = xmlSetNsProp(target, NULL, attr->name, value);
1160 }
1161 if (value != NULL)
1162 xmlFree(value);
1163
1164 if (copy == NULL)
1165 return(NULL);
1166
1167 #if 0
1168 /*
1169 * NOTE: This was optimized according to bug #342695.
1170 * TODO: Can this further be optimized, if source and target
1171 * share the same dict and attr->children is just 1 text node
1172 * which is in the dict? How probable is such a case?
1173 */
1174 /*
1175 * TODO: Do we need to create an empty text node if the value
1176 * is the empty string?
1177 */
1178 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1179 if (value != NULL) {
1180 txtNode = xmlNewDocText(target->doc, NULL);
1181 if (txtNode == NULL)
1182 return(NULL);
1183 if ((target->doc != NULL) &&
1184 (target->doc->dict != NULL))
1185 {
1186 txtNode->content =
1187 (xmlChar *) xmlDictLookup(target->doc->dict,
1188 BAD_CAST value, -1);
1189 xmlFree(value);
1190 } else
1191 txtNode->content = value;
1192 copy->children = txtNode;
1193 }
1194 #endif
1195
1196 return(copy);
1197 }
1198
1199 /**
1200 * xsltCopyAttrListNoOverwrite:
1201 * @ctxt: a XSLT process context
1202 * @invocNode: responsible node in the stylesheet; used for error reports
1203 * @target: the element where the new attributes will be grafted
1204 * @attr: the first attribute in the list to be copied
1205 *
1206 * Copies a list of attribute nodes, starting with @attr, over to the
1207 * @target element node.
1208 *
1209 * Called by:
1210 * - xsltCopyTree()
1211 *
1212 * Returns 0 on success and -1 on errors and internal errors.
1213 */
1214 static int
1215 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
1216 xmlNodePtr invocNode,
1217 xmlNodePtr target, xmlAttrPtr attr)
1218 {
1219 xmlAttrPtr copy;
1220 xmlNsPtr origNs = NULL, copyNs = NULL;
1221 xmlChar *value;
1222
1223 /*
1224 * Don't use xmlCopyProp() here, since it will try to
1225 * reconciliate namespaces.
1226 */
1227 while (attr != NULL) {
1228 /*
1229 * Find a namespace node in the tree of @target.
1230 * Avoid searching for the same ns.
1231 */
1232 if (attr->ns != origNs) {
1233 origNs = attr->ns;
1234 if (attr->ns != NULL) {
1235 copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
1236 attr->ns->href, attr->ns->prefix, target);
1237 if (copyNs == NULL)
1238 return(-1);
1239 } else
1240 copyNs = NULL;
1241 }
1242 /*
1243 * If attribute has a value, we need to copy it (watching out
1244 * for possible entities)
1245 */
1246 if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
1247 (attr->children->next == NULL)) {
1248 copy = xmlNewNsProp(target, copyNs, attr->name,
1249 attr->children->content);
1250 } else if (attr->children != NULL) {
1251 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1252 copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
1253 xmlFree(value);
1254 } else {
1255 copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
1256 }
1257
1258 if (copy == NULL)
1259 return(-1);
1260
1261 attr = attr->next;
1262 }
1263 return(0);
1264 }
1265
1266 /**
1267 * xsltShallowCopyElem:
1268 * @ctxt: the XSLT process context
1269 * @node: the element node in the source tree
1270 * or the Literal Result Element
1271 * @insert: the parent in the result tree
1272 * @isLRE: if @node is a Literal Result Element
1273 *
1274 * Make a copy of the element node @node
1275 * and insert it as last child of @insert.
1276 *
1277 * URGENT TODO: The problem with this one (for the non-refactored code)
1278 * is that it is used for both, Literal Result Elements *and*
1279 * copying input nodes.
1280 *
1281 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1282 *
1283 * Called from:
1284 * xsltApplySequenceConstructor()
1285 * (for Literal Result Elements - which is a problem)
1286 * xsltCopy() (for shallow-copying elements via xsl:copy)
1287 *
1288 * Returns a pointer to the new node, or NULL in case of error
1289 */
1290 static xmlNodePtr
1291 xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
1292 xmlNodePtr insert, int isLRE)
1293 {
1294 xmlNodePtr copy;
1295
1296 if ((node->type == XML_DTD_NODE) || (insert == NULL))
1297 return(NULL);
1298 if ((node->type == XML_TEXT_NODE) ||
1299 (node->type == XML_CDATA_SECTION_NODE))
1300 return(xsltCopyText(ctxt, insert, node, 0));
1301
1302 copy = xmlDocCopyNode(node, insert->doc, 0);
1303 if (copy != NULL) {
1304 copy->doc = ctxt->output;
1305 copy = xsltAddChild(insert, copy);
1306 if (copy == NULL) {
1307 xsltTransformError(ctxt, NULL, node,
1308 "xsltShallowCopyElem: copy failed\n");
1309 return (copy);
1310 }
1311
1312 if (node->type == XML_ELEMENT_NODE) {
1313 /*
1314 * Add namespaces as they are needed
1315 */
1316 if (node->nsDef != NULL) {
1317 /*
1318 * TODO: Remove the LRE case in the refactored code
1319 * gets enabled.
1320 */
1321 if (isLRE)
1322 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1323 else
1324 xsltCopyNamespaceListInternal(copy, node->nsDef);
1325 }
1326
1327 /*
1328 * URGENT TODO: The problem with this is that it does not
1329 * copy over all namespace nodes in scope.
1330 * The damn thing about this is, that we would need to
1331 * use the xmlGetNsList(), for every single node; this is
1332 * also done in xsltCopyTree(), but only for the top node.
1333 */
1334 if (node->ns != NULL) {
1335 if (isLRE) {
1336 /*
1337 * REVISIT TODO: Since the non-refactored code still does
1338 * ns-aliasing, we need to call xsltGetNamespace() here.
1339 * Remove this when ready.
1340 */
1341 copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
1342 } else {
1343 copy->ns = xsltGetSpecialNamespace(ctxt,
1344 node, node->ns->href, node->ns->prefix, copy);
1345
1346 }
1347 } else if ((insert->type == XML_ELEMENT_NODE) &&
1348 (insert->ns != NULL))
1349 {
1350 /*
1351 * "Undeclare" the default namespace.
1352 */
1353 xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
1354 }
1355 }
1356 } else {
1357 xsltTransformError(ctxt, NULL, node,
1358 "xsltShallowCopyElem: copy %s failed\n", node->name);
1359 }
1360 return(copy);
1361 }
1362
1363 /**
1364 * xsltCopyTreeList:
1365 * @ctxt: a XSLT process context
1366 * @invocNode: responsible node in the stylesheet; used for error reports
1367 * @list: the list of element nodes in the source tree.
1368 * @insert: the parent in the result tree.
1369 * @isLRE: is this a literal result element list
1370 * @topElemVisited: indicates if a top-most element was already processed
1371 *
1372 * Make a copy of the full list of tree @list
1373 * and insert it as last children of @insert
1374 *
1375 * NOTE: Not to be used for Literal Result Elements.
1376 *
1377 * Used by:
1378 * - xsltCopyOf()
1379 *
1380 * Returns a pointer to the new list, or NULL in case of error
1381 */
1382 static xmlNodePtr
1383 xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1384 xmlNodePtr list,
1385 xmlNodePtr insert, int isLRE, int topElemVisited)
1386 {
1387 xmlNodePtr copy, ret = NULL;
1388
1389 while (list != NULL) {
1390 copy = xsltCopyTree(ctxt, invocNode,
1391 list, insert, isLRE, topElemVisited);
1392 if (copy != NULL) {
1393 if (ret == NULL) {
1394 ret = copy;
1395 }
1396 }
1397 list = list->next;
1398 }
1399 return(ret);
1400 }
1401
1402 /**
1403 * xsltCopyNamespaceListInternal:
1404 * @node: the target node
1405 * @cur: the first namespace
1406 *
1407 * Do a copy of a namespace list. If @node is non-NULL the
1408 * new namespaces are added automatically.
1409 * Called by:
1410 * xsltCopyTree()
1411 *
1412 * QUESTION: What is the exact difference between this function
1413 * and xsltCopyNamespaceList() in "namespaces.c"?
1414 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1415 *
1416 * Returns: a new xmlNsPtr, or NULL in case of error.
1417 */
1418 static xmlNsPtr
1419 xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
1420 xmlNsPtr ret = NULL;
1421 xmlNsPtr p = NULL, q, luNs;
1422
1423 if (ns == NULL)
1424 return(NULL);
1425 /*
1426 * One can add namespaces only on element nodes
1427 */
1428 if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
1429 elem = NULL;
1430
1431 do {
1432 if (ns->type != XML_NAMESPACE_DECL)
1433 break;
1434 /*
1435 * Avoid duplicating namespace declarations on the tree.
1436 */
1437 if (elem != NULL) {
1438 if ((elem->ns != NULL) &&
1439 xmlStrEqual(elem->ns->prefix, ns->prefix) &&
1440 xmlStrEqual(elem->ns->href, ns->href))
1441 {
1442 ns = ns->next;
1443 continue;
1444 }
1445 luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
1446 if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
1447 {
1448 ns = ns->next;
1449 continue;
1450 }
1451 }
1452 q = xmlNewNs(elem, ns->href, ns->prefix);
1453 if (p == NULL) {
1454 ret = p = q;
1455 } else if (q != NULL) {
1456 p->next = q;
1457 p = q;
1458 }
1459 ns = ns->next;
1460 } while (ns != NULL);
1461 return(ret);
1462 }
1463
1464 /**
1465 * xsltShallowCopyNsNode:
1466 * @ctxt: the XSLT transformation context
1467 * @invocNode: responsible node in the stylesheet; used for error reports
1468 * @insert: the target element node in the result tree
1469 * @ns: the namespace node
1470 *
1471 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1472 *
1473 * Returns a new/existing ns-node, or NULL.
1474 */
1475 static xmlNsPtr
1476 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
1477 xmlNodePtr invocNode,
1478 xmlNodePtr insert,
1479 xmlNsPtr ns)
1480 {
1481 /*
1482 * TODO: Contrary to header comments, this is declared as int.
1483 * be modified to return a node pointer, or NULL if any error
1484 */
1485 xmlNsPtr tmpns;
1486
1487 if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
1488 return(NULL);
1489
1490 if (insert->children != NULL) {
1491 xsltTransformError(ctxt, NULL, invocNode,
1492 "Namespace nodes must be added before "
1493 "any child nodes are added to an element.\n");
1494 return(NULL);
1495 }
1496 /*
1497 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1498 * an equal prefix. We definitively won't do that.
1499 *
1500 * MSXML 4.0 and the .NET ignores ns-decls for which an
1501 * equal prefix is already in use.
1502 *
1503 * Saxon raises an error like:
1504 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1505 * nodes with the same name".
1506 *
1507 * NOTE: We'll currently follow MSXML here.
1508 * REVISIT TODO: Check if it's better to follow Saxon here.
1509 */
1510 if (ns->prefix == NULL) {
1511 /*
1512 * If we are adding ns-nodes to an element using e.g.
1513 * <xsl:copy-of select="/foo/namespace::*">, then we need
1514 * to ensure that we don't incorrectly declare a default
1515 * namespace on an element in no namespace, which otherwise
1516 * would move the element incorrectly into a namespace, if
1517 * the node tree is serialized.
1518 */
1519 if (insert->ns == NULL)
1520 goto occupied;
1521 } else if ((ns->prefix[0] == 'x') &&
1522 xmlStrEqual(ns->prefix, BAD_CAST "xml"))
1523 {
1524 /*
1525 * The XML namespace is built in.
1526 */
1527 return(NULL);
1528 }
1529
1530 if (insert->nsDef != NULL) {
1531 tmpns = insert->nsDef;
1532 do {
1533 if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
1534 if ((tmpns->prefix == ns->prefix) ||
1535 xmlStrEqual(tmpns->prefix, ns->prefix))
1536 {
1537 /*
1538 * Same prefix.
1539 */
1540 if (xmlStrEqual(tmpns->href, ns->href))
1541 return(NULL);
1542 goto occupied;
1543 }
1544 }
1545 tmpns = tmpns->next;
1546 } while (tmpns != NULL);
1547 }
1548 tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
1549 if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
1550 return(NULL);
1551 /*
1552 * Declare a new namespace.
1553 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1554 * that it will again search the already declared namespaces
1555 * for a duplicate :-/
1556 */
1557 return(xmlNewNs(insert, ns->href, ns->prefix));
1558
1559 occupied:
1560 /*
1561 * TODO: We could as well raise an error here (like Saxon does),
1562 * or at least generate a warning.
1563 */
1564 return(NULL);
1565 }
1566
1567 /**
1568 * xsltCopyTree:
1569 * @ctxt: the XSLT transformation context
1570 * @invocNode: responsible node in the stylesheet; used for error reports
1571 * @node: the element node in the source tree
1572 * @insert: the parent in the result tree
1573 * @isLRE: indicates if @node is a Literal Result Element
1574 * @topElemVisited: indicates if a top-most element was already processed
1575 *
1576 * Make a copy of the full tree under the element node @node
1577 * and insert it as last child of @insert
1578 *
1579 * NOTE: Not to be used for Literal Result Elements.
1580 *
1581 * Used by:
1582 * - xsltCopyOf()
1583 *
1584 * Returns a pointer to the new tree, or NULL in case of error
1585 */
1586 static xmlNodePtr
1587 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1588 xmlNodePtr node, xmlNodePtr insert, int isLRE,
1589 int topElemVisited)
1590 {
1591 xmlNodePtr copy;
1592
1593 if (node == NULL)
1594 return(NULL);
1595 switch (node->type) {
1596 case XML_ELEMENT_NODE:
1597 case XML_ENTITY_REF_NODE:
1598 case XML_ENTITY_NODE:
1599 case XML_PI_NODE:
1600 case XML_COMMENT_NODE:
1601 case XML_DOCUMENT_NODE:
1602 case XML_HTML_DOCUMENT_NODE:
1603 #ifdef LIBXML_DOCB_ENABLED
1604 case XML_DOCB_DOCUMENT_NODE:
1605 #endif
1606 break;
1607 case XML_TEXT_NODE: {
1608 int noenc = (node->name == xmlStringTextNoenc);
1609 return(xsltCopyTextString(ctxt, insert, node->content, noenc));
1610 }
1611 case XML_CDATA_SECTION_NODE:
1612 return(xsltCopyTextString(ctxt, insert, node->content, 0));
1613 case XML_ATTRIBUTE_NODE:
1614 return((xmlNodePtr)
1615 xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
1616 case XML_NAMESPACE_DECL:
1617 return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
1618 insert, (xmlNsPtr) node));
1619
1620 case XML_DOCUMENT_TYPE_NODE:
1621 case XML_DOCUMENT_FRAG_NODE:
1622 case XML_NOTATION_NODE:
1623 case XML_DTD_NODE:
1624 case XML_ELEMENT_DECL:
1625 case XML_ATTRIBUTE_DECL:
1626 case XML_ENTITY_DECL:
1627 case XML_XINCLUDE_START:
1628 case XML_XINCLUDE_END:
1629 return(NULL);
1630 }
1631 if (XSLT_IS_RES_TREE_FRAG(node)) {
1632 if (node->children != NULL)
1633 copy = xsltCopyTreeList(ctxt, invocNode,
1634 node->children, insert, 0, 0);
1635 else
1636 copy = NULL;
1637 return(copy);
1638 }
1639 copy = xmlDocCopyNode(node, insert->doc, 0);
1640 if (copy != NULL) {
1641 copy->doc = ctxt->output;
1642 copy = xsltAddChild(insert, copy);
1643 if (copy == NULL) {
1644 xsltTransformError(ctxt, NULL, invocNode,
1645 "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1646 return (copy);
1647 }
1648 /*
1649 * The node may have been coalesced into another text node.
1650 */
1651 if (insert->last != copy)
1652 return(insert->last);
1653 copy->next = NULL;
1654
1655 if (node->type == XML_ELEMENT_NODE) {
1656 /*
1657 * Copy in-scope namespace nodes.
1658 *
1659 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1660 * using xmlSearchNsByHref(), this will eventually change
1661 * the prefix of an original ns-binding; thus it might
1662 * break QNames in element/attribute content.
1663 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1664 * context, plus a ns-lookup function, which writes directly
1665 * to a given list, then we wouldn't need to create/free the
1666 * nsList every time.
1667 */
1668 if ((topElemVisited == 0) &&
1669 (node->parent != NULL) &&
1670 (node->parent->type != XML_DOCUMENT_NODE) &&
1671 (node->parent->type != XML_HTML_DOCUMENT_NODE))
1672 {
1673 xmlNsPtr *nsList, *curns, ns;
1674
1675 /*
1676 * If this is a top-most element in a tree to be
1677 * copied, then we need to ensure that all in-scope
1678 * namespaces are copied over. For nodes deeper in the
1679 * tree, it is sufficient to reconcile only the ns-decls
1680 * (node->nsDef entries).
1681 */
1682
1683 nsList = xmlGetNsList(node->doc, node);
1684 if (nsList != NULL) {
1685 curns = nsList;
1686 do {
1687 /*
1688 * Search by prefix first in order to break as less
1689 * QNames in element/attribute content as possible.
1690 */
1691 ns = xmlSearchNs(insert->doc, insert,
1692 (*curns)->prefix);
1693
1694 if ((ns == NULL) ||
1695 (! xmlStrEqual(ns->href, (*curns)->href)))
1696 {
1697 ns = NULL;
1698 /*
1699 * Search by namespace name.
1700 * REVISIT TODO: Currently disabled.
1701 */
1702 #if 0
1703 ns = xmlSearchNsByHref(insert->doc,
1704 insert, (*curns)->href);
1705 #endif
1706 }
1707 if (ns == NULL) {
1708 /*
1709 * Declare a new namespace on the copied element.
1710 */
1711 ns = xmlNewNs(copy, (*curns)->href,
1712 (*curns)->prefix);
1713 /* TODO: Handle errors */
1714 }
1715 if (node->ns == *curns) {
1716 /*
1717 * If this was the original's namespace then set
1718 * the generated counterpart on the copy.
1719 */
1720 copy->ns = ns;
1721 }
1722 curns++;
1723 } while (*curns != NULL);
1724 xmlFree(nsList);
1725 }
1726 } else if (node->nsDef != NULL) {
1727 /*
1728 * Copy over all namespace declaration attributes.
1729 */
1730 if (node->nsDef != NULL) {
1731 if (isLRE)
1732 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1733 else
1734 xsltCopyNamespaceListInternal(copy, node->nsDef);
1735 }
1736 }
1737 /*
1738 * Set the namespace.
1739 */
1740 if (node->ns != NULL) {
1741 if (copy->ns == NULL) {
1742 /*
1743 * This will map copy->ns to one of the newly created
1744 * in-scope ns-decls, OR create a new ns-decl on @copy.
1745 */
1746 copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
1747 node->ns->href, node->ns->prefix, copy);
1748 }
1749 } else if ((insert->type == XML_ELEMENT_NODE) &&
1750 (insert->ns != NULL))
1751 {
1752 /*
1753 * "Undeclare" the default namespace on @copy with xmlns="".
1754 */
1755 xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
1756 }
1757 /*
1758 * Copy attribute nodes.
1759 */
1760 if (node->properties != NULL) {
1761 xsltCopyAttrListNoOverwrite(ctxt, invocNode,
1762 copy, node->properties);
1763 }
1764 if (topElemVisited == 0)
1765 topElemVisited = 1;
1766 }
1767 /*
1768 * Copy the subtree.
1769 */
1770 if (node->children != NULL) {
1771 xsltCopyTreeList(ctxt, invocNode,
1772 node->children, copy, isLRE, topElemVisited);
1773 }
1774 } else {
1775 xsltTransformError(ctxt, NULL, invocNode,
1776 "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1777 }
1778 return(copy);
1779 }
1780
1781 /************************************************************************
1782 * *
1783 * Error/fallback processing *
1784 * *
1785 ************************************************************************/
1786
1787 /**
1788 * xsltApplyFallbacks:
1789 * @ctxt: a XSLT process context
1790 * @node: the node in the source tree.
1791 * @inst: the node generating the error
1792 *
1793 * Process possible xsl:fallback nodes present under @inst
1794 *
1795 * Returns the number of xsl:fallback element found and processed
1796 */
1797 static int
1798 xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
1799 xmlNodePtr inst) {
1800
1801 xmlNodePtr child;
1802 int ret = 0;
1803
1804 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
1805 (inst->children == NULL))
1806 return(0);
1807
1808 child = inst->children;
1809 while (child != NULL) {
1810 if ((IS_XSLT_ELEM(child)) &&
1811 (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
1812 #ifdef WITH_XSLT_DEBUG_PARSING
1813 xsltGenericDebug(xsltGenericDebugContext,
1814 "applying xsl:fallback\n");
1815 #endif
1816 ret++;
1817 xsltApplySequenceConstructor(ctxt, node, child->children,
1818 NULL);
1819 }
1820 child = child->next;
1821 }
1822 return(ret);
1823 }
1824
1825 /************************************************************************
1826 * *
1827 * Default processing *
1828 * *
1829 ************************************************************************/
1830
1831 /**
1832 * xsltDefaultProcessOneNode:
1833 * @ctxt: a XSLT process context
1834 * @node: the node in the source tree.
1835 * @params: extra parameters passed to the template if any
1836 *
1837 * Process the source node with the default built-in template rule:
1838 * <xsl:template match="*|/">
1839 * <xsl:apply-templates/>
1840 * </xsl:template>
1841 *
1842 * and
1843 *
1844 * <xsl:template match="text()|@*">
1845 * <xsl:value-of select="."/>
1846 * </xsl:template>
1847 *
1848 * Note also that namespace declarations are copied directly:
1849 *
1850 * the built-in template rule is the only template rule that is applied
1851 * for namespace nodes.
1852 */
1853 static void
1854 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
1855 xsltStackElemPtr params) {
1856 xmlNodePtr copy;
1857 xmlNodePtr delete = NULL, cur;
1858 int nbchild = 0, oldSize;
1859 int childno = 0, oldPos;
1860 xsltTemplatePtr template;
1861
1862 CHECK_STOPPED;
1863 /*
1864 * Handling of leaves
1865 */
1866 switch (node->type) {
1867 case XML_DOCUMENT_NODE:
1868 case XML_HTML_DOCUMENT_NODE:
1869 case XML_ELEMENT_NODE:
1870 break;
1871 case XML_CDATA_SECTION_NODE:
1872 #ifdef WITH_XSLT_DEBUG_PROCESS
1873 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1874 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1875 node->content));
1876 #endif
1877 copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1878 if (copy == NULL) {
1879 xsltTransformError(ctxt, NULL, node,
1880 "xsltDefaultProcessOneNode: cdata copy failed\n");
1881 }
1882 return;
1883 case XML_TEXT_NODE:
1884 #ifdef WITH_XSLT_DEBUG_PROCESS
1885 if (node->content == NULL) {
1886 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1887 "xsltDefaultProcessOneNode: copy empty text\n"));
1888 return;
1889 } else {
1890 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1891 "xsltDefaultProcessOneNode: copy text %s\n",
1892 node->content));
1893 }
1894 #endif
1895 copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1896 if (copy == NULL) {
1897 xsltTransformError(ctxt, NULL, node,
1898 "xsltDefaultProcessOneNode: text copy failed\n");
1899 }
1900 return;
1901 case XML_ATTRIBUTE_NODE:
1902 cur = node->children;
1903 while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
1904 cur = cur->next;
1905 if (cur == NULL) {
1906 xsltTransformError(ctxt, NULL, node,
1907 "xsltDefaultProcessOneNode: no text for attribute\n");
1908 } else {
1909 #ifdef WITH_XSLT_DEBUG_PROCESS
1910 if (cur->content == NULL) {
1911 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1912 "xsltDefaultProcessOneNode: copy empty text\n"));
1913 } else {
1914 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1915 "xsltDefaultProcessOneNode: copy text %s\n",
1916 cur->content));
1917 }
1918 #endif
1919 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1920 if (copy == NULL) {
1921 xsltTransformError(ctxt, NULL, node,
1922 "xsltDefaultProcessOneNode: text copy failed\n");
1923 }
1924 }
1925 return;
1926 default:
1927 return;
1928 }
1929 /*
1930 * Handling of Elements: first pass, cleanup and counting
1931 */
1932 cur = node->children;
1933 while (cur != NULL) {
1934 switch (cur->type) {
1935 case XML_TEXT_NODE:
1936 case XML_CDATA_SECTION_NODE:
1937 case XML_DOCUMENT_NODE:
1938 case XML_HTML_DOCUMENT_NODE:
1939 case XML_ELEMENT_NODE:
1940 case XML_PI_NODE:
1941 case XML_COMMENT_NODE:
1942 nbchild++;
1943 break;
1944 case XML_DTD_NODE:
1945 /* Unlink the DTD, it's still reachable using doc->intSubset */
1946 if (cur->next != NULL)
1947 cur->next->prev = cur->prev;
1948 if (cur->prev != NULL)
1949 cur->prev->next = cur->next;
1950 break;
1951 default:
1952 #ifdef WITH_XSLT_DEBUG_PROCESS
1953 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1954 "xsltDefaultProcessOneNode: skipping node type %d\n",
1955 cur->type));
1956 #endif
1957 delete = cur;
1958 }
1959 cur = cur->next;
1960 if (delete != NULL) {
1961 #ifdef WITH_XSLT_DEBUG_PROCESS
1962 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1963 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1964 #endif
1965 xmlUnlinkNode(delete);
1966 xmlFreeNode(delete);
1967 delete = NULL;
1968 }
1969 }
1970 if (delete != NULL) {
1971 #ifdef WITH_XSLT_DEBUG_PROCESS
1972 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1973 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1974 #endif
1975 xmlUnlinkNode(delete);
1976 xmlFreeNode(delete);
1977 delete = NULL;
1978 }
1979
1980 /*
1981 * Handling of Elements: second pass, actual processing
1982 *
1983 * Note that params are passed to the next template. This matches
1984 * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1985 */
1986 oldSize = ctxt->xpathCtxt->contextSize;
1987 oldPos = ctxt->xpathCtxt->proximityPosition;
1988 cur = node->children;
1989 while (cur != NULL) {
1990 childno++;
1991 switch (cur->type) {
1992 case XML_DOCUMENT_NODE:
1993 case XML_HTML_DOCUMENT_NODE:
1994 case XML_ELEMENT_NODE:
1995 ctxt->xpathCtxt->contextSize = nbchild;
1996 ctxt->xpathCtxt->proximityPosition = childno;
1997 xsltProcessOneNode(ctxt, cur, params);
1998 break;
1999 case XML_CDATA_SECTION_NODE:
2000 template = xsltGetTemplate(ctxt, cur, NULL);
2001 if (template) {
2002 #ifdef WITH_XSLT_DEBUG_PROCESS
2003 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2004 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2005 cur->content));
2006 #endif
2007 /*
2008 * Instantiate the xsl:template.
2009 */
2010 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2011 template, params);
2012 } else /* if (ctxt->mode == NULL) */ {
2013 #ifdef WITH_XSLT_DEBUG_PROCESS
2014 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2015 "xsltDefaultProcessOneNode: copy CDATA %s\n",
2016 cur->content));
2017 #endif
2018 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2019 if (copy == NULL) {
2020 xsltTransformError(ctxt, NULL, cur,
2021 "xsltDefaultProcessOneNode: cdata copy failed\n");
2022 }
2023 }
2024 break;
2025 case XML_TEXT_NODE:
2026 template = xsltGetTemplate(ctxt, cur, NULL);
2027 if (template) {
2028 #ifdef WITH_XSLT_DEBUG_PROCESS
2029 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2030 "xsltDefaultProcessOneNode: applying template for text %s\n",
2031 cur->content));
2032 #endif
2033 ctxt->xpathCtxt->contextSize = nbchild;
2034 ctxt->xpathCtxt->proximityPosition = childno;
2035 /*
2036 * Instantiate the xsl:template.
2037 */
2038 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2039 template, params);
2040 } else /* if (ctxt->mode == NULL) */ {
2041 #ifdef WITH_XSLT_DEBUG_PROCESS
2042 if (cur->content == NULL) {
2043 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2044 "xsltDefaultProcessOneNode: copy empty text\n"));
2045 } else {
2046 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2047 "xsltDefaultProcessOneNode: copy text %s\n",
2048 cur->content));
2049 }
2050 #endif
2051 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2052 if (copy == NULL) {
2053 xsltTransformError(ctxt, NULL, cur,
2054 "xsltDefaultProcessOneNode: text copy failed\n");
2055 }
2056 }
2057 break;
2058 case XML_PI_NODE:
2059 case XML_COMMENT_NODE:
2060 template = xsltGetTemplate(ctxt, cur, NULL);
2061 if (template) {
2062 #ifdef WITH_XSLT_DEBUG_PROCESS
2063 if (cur->type == XML_PI_NODE) {
2064 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2065 "xsltDefaultProcessOneNode: template found for PI %s\n",
2066 cur->name));
2067 } else if (cur->type == XML_COMMENT_NODE) {
2068 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2069 "xsltDefaultProcessOneNode: template found for comment\n"));
2070 }
2071 #endif
2072 ctxt->xpathCtxt->contextSize = nbchild;
2073 ctxt->xpathCtxt->proximityPosition = childno;
2074 /*
2075 * Instantiate the xsl:template.
2076 */
2077 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2078 template, params);
2079 }
2080 break;
2081 default:
2082 break;
2083 }
2084 cur = cur->next;
2085 }
2086 ctxt->xpathCtxt->contextSize = oldSize;
2087 ctxt->xpathCtxt->proximityPosition = oldPos;
2088 }
2089
2090 /**
2091 * xsltProcessOneNode:
2092 * @ctxt: a XSLT process context
2093 * @contextNode: the "current node" in the source tree
2094 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
2095 * template if any
2096 *
2097 * Process the source node.
2098 */
2099 void
2100 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
2101 xsltStackElemPtr withParams)
2102 {
2103 xsltTemplatePtr templ;
2104 xmlNodePtr oldNode;
2105
2106 templ = xsltGetTemplate(ctxt, contextNode, NULL);
2107 /*
2108 * If no template is found, apply the default rule.
2109 */
2110 if (templ == NULL) {
2111 #ifdef WITH_XSLT_DEBUG_PROCESS
2112 if (contextNode->type == XML_DOCUMENT_NODE) {
2113 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2114 "xsltProcessOneNode: no template found for /\n"));
2115 } else if (contextNode->type == XML_CDATA_SECTION_NODE) {
2116 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2117 "xsltProcessOneNode: no template found for CDATA\n"));
2118 } else if (contextNode->type == XML_ATTRIBUTE_NODE) {
2119 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2120 "xsltProcessOneNode: no template found for attribute %s\n",
2121 ((xmlAttrPtr) contextNode)->name));
2122 } else {
2123 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2124 "xsltProcessOneNode: no template found for %s\n", contextNode->name));
2125 }
2126 #endif
2127 oldNode = ctxt->node;
2128 ctxt->node = contextNode;
2129 xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
2130 ctxt->node = oldNode;
2131 return;
2132 }
2133
2134 if (contextNode->type == XML_ATTRIBUTE_NODE) {
2135 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2136 /*
2137 * Set the "current template rule".
2138 */
2139 ctxt->currentTemplateRule = templ;
2140
2141 #ifdef WITH_XSLT_DEBUG_PROCESS
2142 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2143 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2144 templ->match, contextNode->name));
2145 #endif
2146 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2147
2148 ctxt->currentTemplateRule = oldCurTempRule;
2149 } else {
2150 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2151 /*
2152 * Set the "current template rule".
2153 */
2154 ctxt->currentTemplateRule = templ;
2155
2156 #ifdef WITH_XSLT_DEBUG_PROCESS
2157 if (contextNode->type == XML_DOCUMENT_NODE) {
2158 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2159 "xsltProcessOneNode: applying template '%s' for /\n",
2160 templ->match));
2161 } else {
2162 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2163 "xsltProcessOneNode: applying template '%s' for %s\n",
2164 templ->match, contextNode->name));
2165 }
2166 #endif
2167 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2168
2169 ctxt->currentTemplateRule = oldCurTempRule;
2170 }
2171 }
2172
2173 static xmlNodePtr
2174 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2175 xmlNodePtr contextNode,
2176 xmlNodePtr list,
2177 xsltTemplatePtr templ,
2178 int *addCallResult)
2179 {
2180 xmlNodePtr debugedNode = NULL;
2181
2182 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2183 if (templ) {
2184 *addCallResult = xslAddCall(templ, templ->elem);
2185 } else {
2186 *addCallResult = xslAddCall(NULL, list);
2187 }
2188 switch (ctxt->debugStatus) {
2189 case XSLT_DEBUG_RUN_RESTART:
2190 case XSLT_DEBUG_QUIT:
2191 if (*addCallResult)
2192 xslDropCall();
2193 return(NULL);
2194 }
2195 if (templ) {
2196 xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2197 debugedNode = templ->elem;
2198 } else if (list) {
2199 xslHandleDebugger(list, contextNode, templ, ctxt);
2200 debugedNode = list;
2201 } else if (ctxt->inst) {
2202 xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2203 debugedNode = ctxt->inst;
2204 }
2205 }
2206 return(debugedNode);
2207 }
2208
2209 /**
2210 * xsltLocalVariablePush:
2211 * @ctxt: the transformation context
2212 * @variable: variable to be pushed to the variable stack
2213 * @level: new value for variable's level
2214 *
2215 * Places the variable onto the local variable stack
2216 *
2217 * Returns: 0 for success, -1 for any error
2218 * **NOTE:**
2219 * This is an internal routine and should not be called by users!
2220 */
2221 int
2222 xsltLocalVariablePush(xsltTransformContextPtr ctxt,
2223 xsltStackElemPtr variable,
2224 int level)
2225 {
2226 if (ctxt->varsMax == 0) {
2227 ctxt->varsMax = 10;
2228 ctxt->varsTab =
2229 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
2230 sizeof(ctxt->varsTab[0]));
2231 if (ctxt->varsTab == NULL) {
2232 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
2233 return (-1);
2234 }
2235 }
2236 if (ctxt->varsNr >= ctxt->varsMax) {
2237 ctxt->varsMax *= 2;
2238 ctxt->varsTab =
2239 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
2240 ctxt->varsMax *
2241 sizeof(ctxt->varsTab[0]));
2242 if (ctxt->varsTab == NULL) {
2243 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2244 return (-1);
2245 }
2246 }
2247 ctxt->varsTab[ctxt->varsNr++] = variable;
2248 ctxt->vars = variable;
2249 variable->level = level;
2250 return(0);
2251 }
2252
2253 /**
2254 * xsltReleaseLocalRVTs:
2255 *
2256 * Fragments which are results of extension instructions
2257 * are preserved; all other fragments are freed/cached.
2258 */
2259 static void
2260 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
2261 {
2262 xmlDocPtr cur = ctxt->localRVT, tmp;
2263
2264 if (cur == base)
2265 return;
2266 if (cur->prev != NULL)
2267 xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
2268
2269 do {
2270 tmp = cur;
2271 cur = (xmlDocPtr) cur->next;
2272 if (tmp->psvi == XSLT_RVT_LOCAL) {
2273 xsltReleaseRVT(ctxt, tmp);
2274 } else if (tmp->psvi == XSLT_RVT_GLOBAL) {
2275 xsltRegisterPersistRVT(ctxt, tmp);
2276 } else if (tmp->psvi != XSLT_RVT_FUNC_RESULT) {
2277 xmlGenericError(xmlGenericErrorContext,
2278 "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2279 tmp->psvi);
2280 }
2281 } while (cur != base);
2282
2283 if (base != NULL)
2284 base->prev = NULL;
2285 ctxt->localRVT = base;
2286 }
2287
2288 /**
2289 * xsltApplySequenceConstructor:
2290 * @ctxt: a XSLT process context
2291 * @contextNode: the "current node" in the source tree
2292 * @list: the nodes of a sequence constructor;
2293 * (plus leading xsl:param elements)
2294 * @templ: the compiled xsl:template (optional)
2295 *
2296 * Processes a sequence constructor.
2297 *
2298 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2299 * semantics of "current template rule". I.e. the field ctxt->templ
2300 * is not intended to reflect this, thus always pushed onto the
2301 * template stack.
2302 */
2303 static void
2304 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
2305 xmlNodePtr contextNode, xmlNodePtr list,
2306 xsltTemplatePtr templ)
2307 {
2308 xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2309 xmlNodePtr cur, insert, copy = NULL;
2310 int level = 0, oldVarsNr;
2311 xmlDocPtr oldLocalFragmentTop;
2312
2313 #ifdef XSLT_REFACTORED
2314 xsltStylePreCompPtr info;
2315 #endif
2316
2317 #ifdef WITH_DEBUGGER
2318 int addCallResult = 0;
2319 xmlNodePtr debuggedNode = NULL;
2320 #endif
2321
2322 if (ctxt == NULL)
2323 return;
2324
2325 #ifdef WITH_DEBUGGER
2326 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2327 debuggedNode =
2328 xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2329 list, templ, &addCallResult);
2330 if (debuggedNode == NULL)
2331 return;
2332 }
2333 #endif
2334
2335 if (list == NULL)
2336 return;
2337 CHECK_STOPPED;
2338
2339 /*
2340 * Check for infinite recursion: stop if the maximum of nested templates
2341 * is excceeded. Adjust xsltMaxDepth if you need more.
2342 */
2343 if (ctxt->depth >= ctxt->maxTemplateDepth) {
2344 xsltTransformError(ctxt, NULL, list,
2345 "xsltApplySequenceConstructor: A potential infinite template "
2346 "recursion was detected.\n"
2347 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2348 "raise the maximum number of nested template calls and "
2349 "variables/params (currently set to %d).\n",
2350 ctxt->maxTemplateDepth);
2351 xsltDebug(ctxt, contextNode, list, NULL);
2352 ctxt->state = XSLT_STATE_STOPPED;
2353 return;
2354 }
2355 ctxt->depth++;
2356
2357 oldLocalFragmentTop = ctxt->localRVT;
2358 oldInsert = insert = ctxt->insert;
2359 oldInst = oldCurInst = ctxt->inst;
2360 oldContextNode = ctxt->node;
2361 /*
2362 * Save current number of variables on the stack; new vars are popped when
2363 * exiting.
2364 */
2365 oldVarsNr = ctxt->varsNr;
2366 /*
2367 * Process the sequence constructor.
2368 */
2369 cur = list;
2370 while (cur != NULL) {
2371 ctxt->inst = cur;
2372
2373 #ifdef WITH_DEBUGGER
2374 switch (ctxt->debugStatus) {
2375 case XSLT_DEBUG_RUN_RESTART:
2376 case XSLT_DEBUG_QUIT:
2377 break;
2378
2379 }
2380 #endif
2381 /*
2382 * Test; we must have a valid insertion point.
2383 */
2384 if (insert == NULL) {
2385
2386 #ifdef WITH_XSLT_DEBUG_PROCESS
2387 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2388 "xsltApplySequenceConstructor: insert == NULL !\n"));
2389 #endif
2390 goto error;
2391 }
2392
2393 #ifdef WITH_DEBUGGER
2394 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2395 xslHandleDebugger(cur, contextNode, templ, ctxt);
2396 #endif
2397
2398 #ifdef XSLT_REFACTORED
2399 if (cur->type == XML_ELEMENT_NODE) {
2400 info = (xsltStylePreCompPtr) cur->psvi;
2401 /*
2402 * We expect a compiled representation on:
2403 * 1) XSLT instructions of this XSLT version (1.0)
2404 * (with a few exceptions)
2405 * 2) Literal result elements
2406 * 3) Extension instructions
2407 * 4) XSLT instructions of future XSLT versions
2408 * (forwards-compatible mode).
2409 */
2410 if (info == NULL) {
2411 /*
2412 * Handle the rare cases where we don't expect a compiled
2413 * representation on an XSLT element.
2414 */
2415 if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2416 xsltMessage(ctxt, contextNode, cur);
2417 goto skip_children;
2418 }
2419 /*
2420 * Something really went wrong:
2421 */
2422 xsltTransformError(ctxt, NULL, cur,
2423 "Internal error in xsltApplySequenceConstructor(): "
2424 "The element '%s' in the stylesheet has no compiled "
2425 "representation.\n",
2426 cur->name);
2427 goto skip_children;
2428 }
2429
2430 if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2431 xsltStyleItemLRElementInfoPtr lrInfo =
2432 (xsltStyleItemLRElementInfoPtr) info;
2433 /*
2434 * Literal result elements
2435 * --------------------------------------------------------
2436 */
2437 #ifdef WITH_XSLT_DEBUG_PROCESS
2438 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2439 xsltGenericDebug(xsltGenericDebugContext,
2440 "xsltApplySequenceConstructor: copy literal result "
2441 "element '%s'\n", cur->name));
2442 #endif
2443 /*
2444 * Copy the raw element-node.
2445 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2446 * == NULL)
2447 * goto error;
2448 */
2449 copy = xmlDocCopyNode(cur, insert->doc, 0);
2450 if (copy == NULL) {
2451 xsltTransformError(ctxt, NULL, cur,
2452 "Internal error in xsltApplySequenceConstructor(): "
2453 "Failed to copy literal result element '%s'.\n",
2454 cur->name);
2455 goto error;
2456 } else {
2457 /*
2458 * Add the element-node to the result tree.
2459 */
2460 copy->doc = ctxt->output;
2461 copy = xsltAddChild(insert, copy);
2462 /*
2463 * Create effective namespaces declarations.
2464 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2465 */
2466 if (lrInfo->effectiveNs != NULL) {
2467 xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2468 xmlNsPtr ns, lastns = NULL;
2469
2470 while (effNs != NULL) {
2471 /*
2472 * Avoid generating redundant namespace
2473 * declarations; thus lookup if there is already
2474 * such a ns-decl in the result.
2475 */
2476 ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2477 if ((ns != NULL) &&
2478 (xmlStrEqual(ns->href, effNs->nsName)))
2479 {
2480 effNs = effNs->next;
2481 continue;
2482 }
2483 ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2484 if (ns == NULL) {
2485 xsltTransformError(ctxt, NULL, cur,
2486 "Internal error in "
2487 "xsltApplySequenceConstructor(): "
2488 "Failed to copy a namespace "
2489 "declaration.\n");
2490 goto error;
2491 }
2492
2493 if (lastns == NULL)
2494 copy->nsDef = ns;
2495 else
2496 lastns->next =ns;
2497 lastns = ns;
2498
2499 effNs = effNs->next;
2500 }
2501
2502 }
2503 /*
2504 * NOTE that we don't need to apply ns-alising: this was
2505 * already done at compile-time.
2506 */
2507 if (cur->ns != NULL) {
2508 /*
2509 * If there's no such ns-decl in the result tree,
2510 * then xsltGetSpecialNamespace() will
2511 * create a ns-decl on the copied node.
2512 */
2513 copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2514 cur->ns->href, cur->ns->prefix, copy);
2515 } else {
2516 /*
2517 * Undeclare the default namespace if needed.
2518 * This can be skipped, if the result element has
2519 * no ns-decls, in which case the result element
2520 * obviously does not declare a default namespace;
2521 * AND there's either no parent, or the parent
2522 * element is in no namespace; this means there's no
2523 * default namespace is scope to care about.
2524 *
2525 * REVISIT: This might result in massive
2526 * generation of ns-decls if nodes in a default
2527 * namespaces are mixed with nodes in no namespace.
2528 *
2529 */
2530 if (copy->nsDef ||
2531 ((insert != NULL) &&
2532 (insert->type == XML_ELEMENT_NODE) &&
2533 (insert->ns != NULL)))
2534 {
2535 xsltGetSpecialNamespace(ctxt, cur,
2536 NULL, NULL, copy);
2537 }
2538 }
2539 }
2540 /*
2541 * SPEC XSLT 2.0 "Each attribute of the literal result
2542 * element, other than an attribute in the XSLT namespace,
2543 * is processed to produce an attribute for the element in
2544 * the result tree."
2545 * NOTE: See bug #341325.
2546 */
2547 if (cur->properties != NULL) {
2548 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2549 }
2550 } else if (IS_XSLT_ELEM_FAST(cur)) {
2551 /*
2552 * XSLT instructions
2553 * --------------------------------------------------------
2554 */
2555 if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2556 /*
2557 * We hit an unknown XSLT element.
2558 * Try to apply one of the fallback cases.
2559 */
2560 ctxt->insert = insert;
2561 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2562 xsltTransformError(ctxt, NULL, cur,
2563 "The is no fallback behaviour defined for "
2564 "the unknown XSLT element '%s'.\n",
2565 cur->name);
2566 }
2567 ctxt->insert = oldInsert;
2568 } else if (info->func != NULL) {
2569 /*
2570 * Execute the XSLT instruction.
2571 */
2572 ctxt->insert = insert;
2573
2574 info->func(ctxt, contextNode, cur,
2575 (xsltElemPreCompPtr) info);
2576
2577 /*
2578 * Cleanup temporary tree fragments.
2579 */
2580 if (oldLocalFragmentTop != ctxt->localRVT)
2581 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2582
2583 ctxt->insert = oldInsert;
2584 } else if (info->type == XSLT_FUNC_VARIABLE) {
2585 xsltStackElemPtr tmpvar = ctxt->vars;
2586
2587 xsltParseStylesheetVariable(ctxt, cur);
2588
2589 if (tmpvar != ctxt->vars) {
2590 /*
2591 * TODO: Using a @tmpvar is an annoying workaround, but
2592 * the current mechanisms do not provide any other way
2593 * of knowing if the var was really pushed onto the
2594 * stack.
2595 */
2596 ctxt->vars->level = level;
2597 }
2598 } else if (info->type == XSLT_FUNC_MESSAGE) {
2599 /*
2600 * TODO: Won't be hit, since we don't compile xsl:message.
2601 */
2602 xsltMessage(ctxt, contextNode, cur);
2603 } else {
2604 xsltTransformError(ctxt, NULL, cur,
2605 "Unexpected XSLT element '%s'.\n", cur->name);
2606 }
2607 goto skip_children;
2608
2609 } else {
2610 xsltTransformFunction func;
2611 /*
2612 * Extension intructions (elements)
2613 * --------------------------------------------------------
2614 */
2615 if (cur->psvi == xsltExtMarker) {
2616 /*
2617 * The xsltExtMarker was set during the compilation
2618 * of extension instructions if there was no registered
2619 * handler for this specific extension function at
2620 * compile-time.
2621 * Libxslt will now lookup if a handler is
2622 * registered in the context of this transformation.
2623 */
2624 func = (xsltTransformFunction)
2625 xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2626 } else
2627 func = ((xsltElemPreCompPtr) cur->psvi)->func;
2628
2629 if (func == NULL) {
2630 /*
2631 * No handler available.
2632 * Try to execute fallback behaviour via xsl:fallback.
2633 */
2634 #ifdef WITH_XSLT_DEBUG_PROCESS
2635 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2636 xsltGenericDebug(xsltGenericDebugContext,
2637 "xsltApplySequenceConstructor: unknown extension %s\n",
2638 cur->name));
2639 #endif
2640 ctxt->insert = insert;
2641 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2642 xsltTransformError(ctxt, NULL, cur,
2643 "Unknown extension instruction '{%s}%s'.\n",
2644 cur->ns->href, cur->name);
2645 }
2646 ctxt->insert = oldInsert;
2647 } else {
2648 /*
2649 * Execute the handler-callback.
2650 */
2651 #ifdef WITH_XSLT_DEBUG_PROCESS
2652 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2653 "xsltApplySequenceConstructor: extension construct %s\n",
2654 cur->name));
2655 #endif
2656 /*
2657 * Disable the xsltCopyTextString optimization for
2658 * extension elements. Extensions could append text using
2659 * xmlAddChild which will free the buffer pointed to by
2660 * 'lasttext'. This buffer could later be reallocated with
2661 * a different size than recorded in 'lasttsize'. See bug
2662 * #777432.
2663 */
2664 if (cur->psvi == xsltExtMarker) {
2665 ctxt->lasttext = NULL;
2666 }
2667
2668 ctxt->insert = insert;
2669
2670 func(ctxt, contextNode, cur, cur->psvi);
2671
2672 /*
2673 * Cleanup temporary tree fragments.
2674 */
2675 if (oldLocalFragmentTop != ctxt->localRVT)
2676 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2677
2678 ctxt->insert = oldInsert;
2679 }
2680 goto skip_children;
2681 }
2682
2683 } else if (XSLT_IS_TEXT_NODE(cur)) {
2684 /*
2685 * Text
2686 * ------------------------------------------------------------
2687 */
2688 #ifdef WITH_XSLT_DEBUG_PROCESS
2689 if (cur->name == xmlStringTextNoenc) {
2690 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2691 xsltGenericDebug(xsltGenericDebugContext,
2692 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2693 cur->content));
2694 } else {
2695 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2696 xsltGenericDebug(xsltGenericDebugContext,
2697 "xsltApplySequenceConstructor: copy text '%s'\n",
2698 cur->content));
2699 }
2700 #endif
2701 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2702 goto error;
2703 }
2704
2705 #else /* XSLT_REFACTORED */
2706
2707 if (IS_XSLT_ELEM(cur)) {
2708 /*
2709 * This is an XSLT node
2710 */
2711 xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
2712
2713 if (info == NULL) {
2714 if (IS_XSLT_NAME(cur, "message")) {
2715 xsltMessage(ctxt, contextNode, cur);
2716 } else {
2717 /*
2718 * That's an error try to apply one of the fallback cases
2719 */
2720 ctxt->insert = insert;
2721 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2722 xsltGenericError(xsltGenericErrorContext,
2723 "xsltApplySequenceConstructor: %s was not compiled\n",
2724 cur->name);
2725 }
2726 ctxt->insert = oldInsert;
2727 }
2728 goto skip_children;
2729 }
2730
2731 if (info->func != NULL) {
2732 oldCurInst = ctxt->inst;
2733 ctxt->inst = cur;
2734 ctxt->insert = insert;
2735
2736 info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2737
2738 /*
2739 * Cleanup temporary tree fragments.
2740 */
2741 if (oldLocalFragmentTop != ctxt->localRVT)
2742 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2743
2744 ctxt->insert = oldInsert;
2745 ctxt->inst = oldCurInst;
2746 goto skip_children;
2747 }
2748
2749 if (IS_XSLT_NAME(cur, "variable")) {
2750 xsltStackElemPtr tmpvar = ctxt->vars;
2751
2752 oldCurInst = ctxt->inst;
2753 ctxt->inst = cur;
2754
2755 xsltParseStylesheetVariable(ctxt, cur);
2756
2757 ctxt->inst = oldCurInst;
2758
2759 if (tmpvar != ctxt->vars) {
2760 /*
2761 * TODO: Using a @tmpvar is an annoying workaround, but
2762 * the current mechanisms do not provide any other way
2763 * of knowing if the var was really pushed onto the
2764 * stack.
2765 */
2766 ctxt->vars->level = level;
2767 }
2768 } else if (IS_XSLT_NAME(cur, "message")) {
2769 xsltMessage(ctxt, contextNode, cur);
2770 } else {
2771 xsltTransformError(ctxt, NULL, cur,
2772 "Unexpected XSLT element '%s'.\n", cur->name);
2773 }
2774 goto skip_children;
2775 } else if ((cur->type == XML_TEXT_NODE) ||
2776 (cur->type == XML_CDATA_SECTION_NODE)) {
2777
2778 /*
2779 * This text comes from the stylesheet
2780 * For stylesheets, the set of whitespace-preserving
2781 * element names consists of just xsl:text.
2782 */
2783 #ifdef WITH_XSLT_DEBUG_PROCESS
2784 if (cur->type == XML_CDATA_SECTION_NODE) {
2785 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2786 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2787 cur->content));
2788 } else if (cur->name == xmlStringTextNoenc) {
2789 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2790 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2791 cur->content));
2792 } else {
2793 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2794 "xsltApplySequenceConstructor: copy text %s\n",
2795 cur->content));
2796 }
2797 #endif
2798 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2799 goto error;
2800 } else if ((cur->type == XML_ELEMENT_NODE) &&
2801 (cur->ns != NULL) && (cur->psvi != NULL)) {
2802 xsltTransformFunction function;
2803
2804 oldCurInst = ctxt->inst;
2805 ctxt->inst = cur;
2806 /*
2807 * Flagged as an extension element
2808 */
2809 if (cur->psvi == xsltExtMarker)
2810 function = (xsltTransformFunction)
2811 xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2812 else
2813 function = ((xsltElemPreCompPtr) cur->psvi)->func;
2814
2815 if (function == NULL) {
2816 xmlNodePtr child;
2817 int found = 0;
2818
2819 #ifdef WITH_XSLT_DEBUG_PROCESS
2820 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2821 "xsltApplySequenceConstructor: unknown extension %s\n",
2822 cur->name));
2823 #endif
2824 /*
2825 * Search if there are fallbacks
2826 */
2827 child = cur->children;
2828 while (child != NULL) {
2829 if ((IS_XSLT_ELEM(child)) &&
2830 (IS_XSLT_NAME(child, "fallback")))
2831 {
2832 found = 1;
2833 xsltApplySequenceConstructor(ctxt, contextNode,
2834 child->children, NULL);
2835 }
2836 child = child->next;
2837 }
2838
2839 if (!found) {
2840 xsltTransformError(ctxt, NULL, cur,
2841 "xsltApplySequenceConstructor: failed to find extension %s\n",
2842 cur->name);
2843 }
2844 } else {
2845 #ifdef WITH_XSLT_DEBUG_PROCESS
2846 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2847 "xsltApplySequenceConstructor: extension construct %s\n",
2848 cur->name));
2849 #endif
2850
2851 /*
2852 * Disable the xsltCopyTextString optimization for
2853 * extension elements. Extensions could append text using
2854 * xmlAddChild which will free the buffer pointed to by
2855 * 'lasttext'. This buffer could later be reallocated with
2856 * a different size than recorded in 'lasttsize'. See bug
2857 * #777432.
2858 */
2859 if (cur->psvi == xsltExtMarker) {
2860 ctxt->lasttext = NULL;
2861 }
2862
2863 ctxt->insert = insert;
2864
2865 function(ctxt, contextNode, cur, cur->psvi);
2866 /*
2867 * Cleanup temporary tree fragments.
2868 */
2869 if (oldLocalFragmentTop != ctxt->localRVT)
2870 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2871
2872 ctxt->insert = oldInsert;
2873
2874 }
2875 ctxt->inst = oldCurInst;
2876 goto skip_children;
2877 } else if (cur->type == XML_ELEMENT_NODE) {
2878 #ifdef WITH_XSLT_DEBUG_PROCESS
2879 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2880 "xsltApplySequenceConstructor: copy node %s\n",
2881 cur->name));
2882 #endif
2883 oldCurInst = ctxt->inst;
2884 ctxt->inst = cur;
2885
2886 if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2887 goto error;
2888 /*
2889 * Add extra namespaces inherited from the current template
2890 * if we are in the first level children and this is a
2891 * "real" template.
2892 */
2893 if ((templ != NULL) && (oldInsert == insert) &&
2894 (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2895 int i;
2896 xmlNsPtr ns, ret;
2897
2898 for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2899 const xmlChar *URI = NULL;
2900 xsltStylesheetPtr style;
2901 ns = ctxt->templ->inheritedNs[i];
2902
2903 /* Note that the XSLT namespace was already excluded
2904 * in xsltGetInheritedNsList().
2905 */
2906 #if 0
2907 if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2908 continue;
2909 #endif
2910 style = ctxt->style;
2911 while (style != NULL) {
2912 if (style->nsAliases != NULL)
2913 URI = (const xmlChar *)
2914 xmlHashLookup(style->nsAliases, ns->href);
2915 if (URI != NULL)
2916 break;
2917
2918 style = xsltNextImport(style);
2919 }
2920 if (URI == UNDEFINED_DEFAULT_NS)
2921 continue;
2922 if (URI == NULL)
2923 URI = ns->href;
2924 /*
2925 * TODO: The following will still be buggy for the
2926 * non-refactored code.
2927 */
2928 ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2929 if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2930 {
2931 xmlNewNs(copy, URI, ns->prefix);
2932 }
2933 }
2934 if (copy->ns != NULL) {
2935 /*
2936 * Fix the node namespace if needed
2937 */
2938 copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2939 }
2940 }
2941 /*
2942 * all the attributes are directly inherited
2943 */
2944 if (cur->properties != NULL) {
2945 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2946 }
2947 ctxt->inst = oldCurInst;
2948 }
2949 #endif /* else of XSLT_REFACTORED */
2950
2951 /*
2952 * Descend into content in document order.
2953 */
2954 if (cur->children != NULL) {
2955 if (cur->children->type != XML_ENTITY_DECL) {
2956 cur = cur->children;
2957 level++;
2958 if (copy != NULL)
2959 insert = copy;
2960 continue;
2961 }
2962 }
2963
2964 skip_children:
2965 /*
2966 * If xslt:message was just processed, we might have hit a
2967 * terminate='yes'; if so, then break the loop and clean up.
2968 * TODO: Do we need to check this also before trying to descend
2969 * into the content?
2970 */
2971 if (ctxt->state == XSLT_STATE_STOPPED)
2972 break;
2973 if (cur->next != NULL) {
2974 cur = cur->next;
2975 continue;
2976 }
2977
2978 do {
2979 cur = cur->parent;
2980 level--;
2981 /*
2982 * Pop variables/params (xsl:variable and xsl:param).
2983 */
2984 if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
2985 xsltLocalVariablePop(ctxt, oldVarsNr, level);
2986 }
2987
2988 insert = insert->parent;
2989 if (cur == NULL)
2990 break;
2991 if (cur == list->parent) {
2992 cur = NULL;
2993 break;
2994 }
2995 if (cur->next != NULL) {
2996 cur = cur->next;
2997 break;
2998 }
2999 } while (cur != NULL);
3000 }
3001
3002 error:
3003 /*
3004 * In case of errors: pop remaining variables.
3005 */
3006 if (ctxt->varsNr > oldVarsNr)
3007 xsltLocalVariablePop(ctxt, oldVarsNr, -1);
3008
3009 ctxt->node = oldContextNode;
3010 ctxt->inst = oldInst;
3011 ctxt->insert = oldInsert;
3012
3013 ctxt->depth--;
3014
3015 #ifdef WITH_DEBUGGER
3016 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3017 xslDropCall();
3018 }
3019 #endif
3020 }
3021
3022 /*
3023 * xsltApplyXSLTTemplate:
3024 * @ctxt: a XSLT transformation context
3025 * @contextNode: the node in the source tree.
3026 * @list: the nodes of a sequence constructor;
3027 * (plus leading xsl:param elements)
3028 * @templ: the compiled xsl:template declaration;
3029 * NULL if a sequence constructor
3030 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
3031 *
3032 * Called by:
3033 * - xsltApplyImports()
3034 * - xsltCallTemplate()
3035 * - xsltDefaultProcessOneNode()
3036 * - xsltProcessOneNode()
3037 */
3038 static void
3039 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
3040 xmlNodePtr contextNode,
3041 xmlNodePtr list,
3042 xsltTemplatePtr templ,
3043 xsltStackElemPtr withParams)
3044 {
3045 int oldVarsBase = 0;
3046 long start = 0;
3047 xmlNodePtr cur;
3048 xsltStackElemPtr tmpParam = NULL;
3049 xmlDocPtr oldUserFragmentTop;
3050
3051 #ifdef XSLT_REFACTORED
3052 xsltStyleItemParamPtr iparam;
3053 #else
3054 xsltStylePreCompPtr iparam;
3055 #endif
3056
3057 #ifdef WITH_DEBUGGER
3058 int addCallResult = 0;
3059 #endif
3060
3061 if (ctxt == NULL)
3062 return;
3063 if (templ == NULL) {
3064 xsltTransformError(ctxt, NULL, list,
3065 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3066 return;
3067 }
3068
3069 #ifdef WITH_DEBUGGER
3070 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
3071 if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
3072 list, templ, &addCallResult) == NULL)
3073 return;
3074 }
3075 #endif
3076
3077 if (list == NULL)
3078 return;
3079 CHECK_STOPPED;
3080
3081 if (ctxt->varsNr >= ctxt->maxTemplateVars)
3082 {
3083 xsltTransformError(ctxt, NULL, list,
3084 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3085 "was detected.\n"
3086 "You can adjust maxTemplateVars (--maxvars) in order to "
3087 "raise the maximum number of variables/params (currently set to %d).\n",
3088 ctxt->maxTemplateVars);
3089 xsltDebug(ctxt, contextNode, list, NULL);
3090 ctxt->state = XSLT_STATE_STOPPED;
3091 return;
3092 }
3093
3094 oldUserFragmentTop = ctxt->tmpRVT;
3095 ctxt->tmpRVT = NULL;
3096
3097 /*
3098 * Initiate a distinct scope of local params/variables.
3099 */
3100 oldVarsBase = ctxt->varsBase;
3101 ctxt->varsBase = ctxt->varsNr;
3102
3103 ctxt->node = contextNode;
3104 if (ctxt->profile) {
3105 templ->nbCalls++;
3106 start = xsltTimestamp();
3107 profPush(ctxt, 0);
3108 profCallgraphAdd(templ, ctxt->templ);
3109 }
3110 /*
3111 * Push the xsl:template declaration onto the stack.
3112 */
3113 templPush(ctxt, templ);
3114
3115 #ifdef WITH_XSLT_DEBUG_PROCESS
3116 if (templ->name != NULL)
3117 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
3118 "applying xsl:template '%s'\n", templ->name));
3119 #endif
3120 /*
3121 * Process xsl:param instructions and skip those elements for
3122 * further processing.
3123 */
3124 cur = list;
3125 do {
3126 if (cur->type == XML_TEXT_NODE) {
3127 cur = cur->next;
3128 continue;
3129 }
3130 if ((cur->type != XML_ELEMENT_NODE) ||
3131 (cur->name[0] != 'p') ||
3132 (cur->psvi == NULL) ||
3133 (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
3134 (! IS_XSLT_ELEM(cur)))
3135 {
3136 break;
3137 }
3138
3139 list = cur->next;
3140
3141 #ifdef XSLT_REFACTORED
3142 iparam = (xsltStyleItemParamPtr) cur->psvi;
3143 #else
3144 iparam = (xsltStylePreCompPtr) cur->psvi;
3145 #endif
3146
3147 /*
3148 * Substitute xsl:param for a given xsl:with-param.
3149 * Since the XPath expression will reference the params/vars
3150 * by index, we need to slot the xsl:with-params in the
3151 * order of encountered xsl:params to keep the sequence of
3152 * params/variables in the stack exactly as it was at
3153 * compile time,
3154 */
3155 tmpParam = NULL;
3156 if (withParams) {
3157 tmpParam = withParams;
3158 do {
3159 if ((tmpParam->name == (iparam->name)) &&
3160 (tmpParam->nameURI == (iparam->ns)))
3161 {
3162 /*
3163 * Push the caller-parameter.
3164 */
3165 xsltLocalVariablePush(ctxt, tmpParam, -1);
3166 break;
3167 }
3168 tmpParam = tmpParam->next;
3169 } while (tmpParam != NULL);
3170 }
3171 /*
3172 * Push the xsl:param.
3173 */
3174 if (tmpParam == NULL) {
3175 /*
3176 * Note that we must assume that the added parameter
3177 * has a @depth of 0.
3178 */
3179 xsltParseStylesheetParam(ctxt, cur);
3180 }
3181 cur = cur->next;
3182 } while (cur != NULL);
3183 /*
3184 * Process the sequence constructor.
3185 */
3186 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3187
3188 /*
3189 * Remove remaining xsl:param and xsl:with-param items from
3190 * the stack. Don't free xsl:with-param items.
3191 */
3192 if (ctxt->varsNr > ctxt->varsBase)
3193 xsltTemplateParamsCleanup(ctxt);
3194 ctxt->varsBase = oldVarsBase;
3195
3196 /*
3197 * Release user-created fragments stored in the scope
3198 * of xsl:template. Note that this mechanism is deprecated:
3199 * user code should now use xsltRegisterLocalRVT() instead
3200 * of the obsolete xsltRegisterTmpRVT().
3201 */
3202 if (ctxt->tmpRVT) {
3203 xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3204
3205 while (curdoc != NULL) {
3206 tmp = curdoc;
3207 curdoc = (xmlDocPtr) curdoc->next;
3208 xsltReleaseRVT(ctxt, tmp);
3209 }
3210 }
3211 ctxt->tmpRVT = oldUserFragmentTop;
3212
3213 /*
3214 * Pop the xsl:template declaration from the stack.
3215 */
3216 templPop(ctxt);
3217 if (ctxt->profile) {
3218 long spent, child, total, end;
3219
3220 end = xsltTimestamp();
3221 child = profPop(ctxt);
3222 total = end - start;
3223 spent = total - child;
3224 if (spent <= 0) {
3225 /*
3226 * Not possible unless the original calibration failed
3227 * we can try to correct it on the fly.
3228 */
3229 xsltCalibrateAdjust(spent);
3230 spent = 0;
3231 }
3232
3233 templ->time += spent;
3234 if (ctxt->profNr > 0)
3235 ctxt->profTab[ctxt->profNr - 1] += total;
3236 }
3237
3238 #ifdef WITH_DEBUGGER
3239 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3240 xslDropCall();
3241 }
3242 #endif
3243 }
3244
3245
3246 /**
3247 * xsltApplyOneTemplate:
3248 * @ctxt: a XSLT process context
3249 * @contextNode: the node in the source tree.
3250 * @list: the nodes of a sequence constructor
3251