VirtualBox

source: vbox/trunk/src/libs/libxslt-1.1.22/libxslt/transform.c@ 7296

最後變更 在這個檔案從7296是 7296,由 vboxsync 提交於 17 年 前

Added libxslt-1.1.22 sources.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette