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