VirtualBox

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

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

libxslt: Fixed warning.

  • 屬性 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
2038#ifdef WITH_DEBUGGER
2039static xmlNodePtr
2040xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2041 xmlNodePtr contextNode,
2042 xmlNodePtr list,
2043 xsltTemplatePtr templ,
2044 int *addCallResult)
2045{
2046 xmlNodePtr debugedNode = NULL;
2047
2048 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2049 if (templ) {
2050 *addCallResult = xslAddCall(templ, templ->elem);
2051 } else {
2052 *addCallResult = xslAddCall(NULL, list);
2053 }
2054 switch (ctxt->debugStatus) {
2055 case XSLT_DEBUG_RUN_RESTART:
2056 case XSLT_DEBUG_QUIT:
2057 if (*addCallResult)
2058 xslDropCall();
2059 return(NULL);
2060 }
2061 if (templ) {
2062 xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2063 debugedNode = templ->elem;
2064 } else if (list) {
2065 xslHandleDebugger(list, contextNode, templ, ctxt);
2066 debugedNode = list;
2067 } else if (ctxt->inst) {
2068 xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2069 debugedNode = ctxt->inst;
2070 }
2071 }
2072 return(debugedNode);
2073}
2074#endif
2075
2076/**
2077 * xsltLocalVariablePush:
2078 * @ctxt: the transformation context
2079 * @variable: variable to be pushed to the variable stack
2080 * @level: new value for variable's level
2081 *
2082 * Places the variable onto the local variable stack
2083 *
2084 * Returns: 0 for success, -1 for any error
2085 * **NOTE:**
2086 * This is an internal routine and should not be called by users!
2087 */
2088int
2089xsltLocalVariablePush(xsltTransformContextPtr ctxt,
2090 xsltStackElemPtr variable,
2091 int level)
2092{
2093 if (ctxt->varsMax == 0) {
2094 ctxt->varsMax = 10;
2095 ctxt->varsTab =
2096 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
2097 sizeof(ctxt->varsTab[0]));
2098 if (ctxt->varsTab == NULL) {
2099 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
2100 return (-1);
2101 }
2102 }
2103 if (ctxt->varsNr >= ctxt->varsMax) {
2104 ctxt->varsMax *= 2;
2105 ctxt->varsTab =
2106 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
2107 ctxt->varsMax *
2108 sizeof(ctxt->varsTab[0]));
2109 if (ctxt->varsTab == NULL) {
2110 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2111 return (-1);
2112 }
2113 }
2114 ctxt->varsTab[ctxt->varsNr++] = variable;
2115 ctxt->vars = variable;
2116 variable->level = level;
2117 return(0);
2118}
2119
2120/**
2121 * xsltReleaseLocalRVTs:
2122 *
2123 * Fragments which are results of extension instructions
2124 * are preserved; all other fragments are freed/cached.
2125 */
2126static void
2127xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
2128{
2129 xmlDocPtr cur = ctxt->localRVT, tmp;
2130
2131 while ((cur != NULL) && (cur != base)) {
2132 if (cur->psvi == (void *) ((long) 1)) {
2133 cur = (xmlDocPtr) cur->next;
2134 } else {
2135 tmp = cur;
2136 cur = (xmlDocPtr) cur->next;
2137
2138 if (tmp == ctxt->localRVT)
2139 ctxt->localRVT = cur;
2140
2141 /*
2142 * We need ctxt->localRVTBase for extension instructions
2143 * which return values (like EXSLT's function).
2144 */
2145 if (tmp == ctxt->localRVTBase)
2146 ctxt->localRVTBase = cur;
2147
2148 if (tmp->prev)
2149 tmp->prev->next = (xmlNodePtr) cur;
2150 if (cur)
2151 cur->prev = tmp->prev;
2152 xsltReleaseRVT(ctxt, tmp);
2153 }
2154 }
2155}
2156
2157/**
2158 * xsltApplySequenceConstructor:
2159 * @ctxt: a XSLT process context
2160 * @contextNode: the "current node" in the source tree
2161 * @list: the nodes of a sequence constructor;
2162 * (plus leading xsl:param elements)
2163 * @templ: the compiled xsl:template (optional)
2164 *
2165 * Processes a sequence constructor.
2166 *
2167 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2168 * semantics of "current template rule". I.e. the field ctxt->templ
2169 * is not intended to reflect this, thus always pushed onto the
2170 * template stack.
2171 */
2172static void
2173xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
2174 xmlNodePtr contextNode, xmlNodePtr list,
2175 xsltTemplatePtr templ)
2176{
2177 xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2178 xmlNodePtr cur, insert, copy = NULL;
2179 int level = 0, oldVarsNr;
2180 xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase;
2181
2182#ifdef XSLT_REFACTORED
2183 xsltStylePreCompPtr info;
2184#endif
2185
2186#ifdef WITH_DEBUGGER
2187 int addCallResult = 0;
2188 xmlNodePtr debuggedNode = NULL;
2189#endif
2190
2191 if (ctxt == NULL)
2192 return;
2193
2194#ifdef WITH_DEBUGGER
2195 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2196 debuggedNode =
2197 xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2198 list, templ, &addCallResult);
2199 if (debuggedNode == NULL)
2200 return;
2201 }
2202#endif
2203
2204 if (list == NULL)
2205 return;
2206 CHECK_STOPPED;
2207
2208 oldLocalFragmentTop = ctxt->localRVT;
2209 oldInsert = insert = ctxt->insert;
2210 oldInst = oldCurInst = ctxt->inst;
2211 oldContextNode = ctxt->node;
2212 /*
2213 * Save current number of variables on the stack; new vars are popped when
2214 * exiting.
2215 */
2216 oldVarsNr = ctxt->varsNr;
2217 /*
2218 * Process the sequence constructor.
2219 */
2220 cur = list;
2221 while (cur != NULL) {
2222 ctxt->inst = cur;
2223
2224#ifdef WITH_DEBUGGER
2225 switch (ctxt->debugStatus) {
2226 case XSLT_DEBUG_RUN_RESTART:
2227 case XSLT_DEBUG_QUIT:
2228 break;
2229
2230 }
2231#endif
2232 /*
2233 * Test; we must have a valid insertion point.
2234 */
2235 if (insert == NULL) {
2236
2237#ifdef WITH_XSLT_DEBUG_PROCESS
2238 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2239 "xsltApplySequenceConstructor: insert == NULL !\n"));
2240#endif
2241 goto error;
2242 }
2243
2244#ifdef WITH_DEBUGGER
2245 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2246 xslHandleDebugger(cur, contextNode, templ, ctxt);
2247#endif
2248
2249#ifdef XSLT_REFACTORED
2250 if (cur->type == XML_ELEMENT_NODE) {
2251 info = (xsltStylePreCompPtr) cur->psvi;
2252 /*
2253 * We expect a compiled representation on:
2254 * 1) XSLT instructions of this XSLT version (1.0)
2255 * (with a few exceptions)
2256 * 2) Literal result elements
2257 * 3) Extension instructions
2258 * 4) XSLT instructions of future XSLT versions
2259 * (forwards-compatible mode).
2260 */
2261 if (info == NULL) {
2262 /*
2263 * Handle the rare cases where we don't expect a compiled
2264 * representation on an XSLT element.
2265 */
2266 if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2267 xsltMessage(ctxt, contextNode, cur);
2268 goto skip_children;
2269 }
2270 /*
2271 * Something really went wrong:
2272 */
2273 xsltTransformError(ctxt, NULL, cur,
2274 "Internal error in xsltApplySequenceConstructor(): "
2275 "The element '%s' in the stylesheet has no compiled "
2276 "representation.\n",
2277 cur->name);
2278 goto skip_children;
2279 }
2280
2281 if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2282 xsltStyleItemLRElementInfoPtr lrInfo =
2283 (xsltStyleItemLRElementInfoPtr) info;
2284 /*
2285 * Literal result elements
2286 * --------------------------------------------------------
2287 */
2288#ifdef WITH_XSLT_DEBUG_PROCESS
2289 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2290 xsltGenericDebug(xsltGenericDebugContext,
2291 "xsltApplySequenceConstructor: copy literal result "
2292 "element '%s'\n", cur->name));
2293#endif
2294 /*
2295 * Copy the raw element-node.
2296 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2297 * == NULL)
2298 * goto error;
2299 */
2300 copy = xmlDocCopyNode(cur, insert->doc, 0);
2301 if (copy == NULL) {
2302 xsltTransformError(ctxt, NULL, cur,
2303 "Internal error in xsltApplySequenceConstructor(): "
2304 "Failed to copy literal result element '%s'.\n",
2305 cur->name);
2306 goto error;
2307 } else {
2308 /*
2309 * Add the element-node to the result tree.
2310 */
2311 copy->doc = ctxt->output;
2312 xmlAddChild(insert, copy);
2313 /*
2314 * Create effective namespaces declarations.
2315 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2316 */
2317 if (lrInfo->effectiveNs != NULL) {
2318 xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2319 xmlNsPtr ns, lastns = NULL;
2320
2321 while (effNs != NULL) {
2322 /*
2323 * Avoid generating redundant namespace
2324 * declarations; thus lookup if there is already
2325 * such a ns-decl in the result.
2326 */
2327 ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2328 if ((ns != NULL) &&
2329 (xmlStrEqual(ns->href, effNs->nsName)))
2330 {
2331 effNs = effNs->next;
2332 continue;
2333 }
2334 ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2335 if (ns == NULL) {
2336 xsltTransformError(ctxt, NULL, cur,
2337 "Internal error in "
2338 "xsltApplySequenceConstructor(): "
2339 "Failed to copy a namespace "
2340 "declaration.\n");
2341 goto error;
2342 }
2343
2344 if (lastns == NULL)
2345 copy->nsDef = ns;
2346 else
2347 lastns->next =ns;
2348 lastns = ns;
2349
2350 effNs = effNs->next;
2351 }
2352
2353 }
2354 /*
2355 * NOTE that we don't need to apply ns-alising: this was
2356 * already done at compile-time.
2357 */
2358 if (cur->ns != NULL) {
2359 /*
2360 * If there's no such ns-decl in the result tree,
2361 * then xsltGetSpecialNamespace() will
2362 * create a ns-decl on the copied node.
2363 */
2364 copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2365 cur->ns->href, cur->ns->prefix, copy);
2366 } else {
2367 /*
2368 * Undeclare the default namespace if needed.
2369 * This can be skipped, if the result element has
2370 * no ns-decls, in which case the result element
2371 * obviously does not declare a default namespace;
2372 * AND there's either no parent, or the parent
2373 * element is in no namespace; this means there's no
2374 * default namespace is scope to care about.
2375 *
2376 * REVISIT: This might result in massive
2377 * generation of ns-decls if nodes in a default
2378 * namespaces are mixed with nodes in no namespace.
2379 *
2380 */
2381 if (copy->nsDef ||
2382 ((insert != NULL) &&
2383 (insert->type == XML_ELEMENT_NODE) &&
2384 (insert->ns != NULL)))
2385 {
2386 xsltGetSpecialNamespace(ctxt, cur,
2387 NULL, NULL, copy);
2388 }
2389 }
2390 }
2391 /*
2392 * SPEC XSLT 2.0 "Each attribute of the literal result
2393 * element, other than an attribute in the XSLT namespace,
2394 * is processed to produce an attribute for the element in
2395 * the result tree."
2396 * NOTE: See bug #341325.
2397 */
2398 if (cur->properties != NULL) {
2399 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2400 }
2401 } else if (IS_XSLT_ELEM_FAST(cur)) {
2402 /*
2403 * XSLT instructions
2404 * --------------------------------------------------------
2405 */
2406 if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2407 /*
2408 * We hit an unknown XSLT element.
2409 * Try to apply one of the fallback cases.
2410 */
2411 ctxt->insert = insert;
2412 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2413 xsltTransformError(ctxt, NULL, cur,
2414 "The is no fallback behaviour defined for "
2415 "the unknown XSLT element '%s'.\n",
2416 cur->name);
2417 }
2418 ctxt->insert = oldInsert;
2419 } else if (info->func != NULL) {
2420 /*
2421 * Execute the XSLT instruction.
2422 */
2423 ctxt->insert = insert;
2424
2425 info->func(ctxt, contextNode, cur,
2426 (xsltElemPreCompPtr) info);
2427
2428 /*
2429 * Cleanup temporary tree fragments.
2430 */
2431 if (oldLocalFragmentTop != ctxt->localRVT)
2432 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2433
2434 ctxt->insert = oldInsert;
2435 } else if (info->type == XSLT_FUNC_VARIABLE) {
2436 xsltStackElemPtr tmpvar = ctxt->vars;
2437
2438 xsltParseStylesheetVariable(ctxt, cur);
2439
2440 if (tmpvar != ctxt->vars) {
2441 /*
2442 * TODO: Using a @tmpvar is an annoying workaround, but
2443 * the current mechanisms do not provide any other way
2444 * of knowing if the var was really pushed onto the
2445 * stack.
2446 */
2447 ctxt->vars->level = level;
2448 }
2449 } else if (info->type == XSLT_FUNC_MESSAGE) {
2450 /*
2451 * TODO: Won't be hit, since we don't compile xsl:message.
2452 */
2453 xsltMessage(ctxt, contextNode, cur);
2454 } else {
2455 xsltTransformError(ctxt, NULL, cur,
2456 "Unexpected XSLT element '%s'.\n", cur->name);
2457 }
2458 goto skip_children;
2459
2460 } else {
2461 xsltTransformFunction func;
2462 /*
2463 * Extension intructions (elements)
2464 * --------------------------------------------------------
2465 */
2466 if (cur->psvi == xsltExtMarker) {
2467 /*
2468 * The xsltExtMarker was set during the compilation
2469 * of extension instructions if there was no registered
2470 * handler for this specific extension function at
2471 * compile-time.
2472 * Libxslt will now lookup if a handler is
2473 * registered in the context of this transformation.
2474 */
2475 func = (xsltTransformFunction)
2476 xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2477 } else
2478 func = ((xsltElemPreCompPtr) cur->psvi)->func;
2479
2480 if (func == NULL) {
2481 /*
2482 * No handler available.
2483 * Try to execute fallback behaviour via xsl:fallback.
2484 */
2485#ifdef WITH_XSLT_DEBUG_PROCESS
2486 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2487 xsltGenericDebug(xsltGenericDebugContext,
2488 "xsltApplySequenceConstructor: unknown extension %s\n",
2489 cur->name));
2490#endif
2491 ctxt->insert = insert;
2492 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2493 xsltTransformError(ctxt, NULL, cur,
2494 "Unknown extension instruction '{%s}%s'.\n",
2495 cur->ns->href, cur->name);
2496 }
2497 ctxt->insert = oldInsert;
2498 } else {
2499 /*
2500 * Execute the handler-callback.
2501 */
2502#ifdef WITH_XSLT_DEBUG_PROCESS
2503 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2504 "xsltApplySequenceConstructor: extension construct %s\n",
2505 cur->name));
2506#endif
2507 ctxt->insert = insert;
2508 /*
2509 * We need the fragment base for extension instructions
2510 * which return values (like EXSLT's function).
2511 */
2512 oldLocalFragmentBase = ctxt->localRVTBase;
2513 ctxt->localRVTBase = NULL;
2514
2515 func(ctxt, contextNode, cur, cur->psvi);
2516
2517 ctxt->localRVTBase = oldLocalFragmentBase;
2518 /*
2519 * Cleanup temporary tree fragments.
2520 */
2521 if (oldLocalFragmentTop != ctxt->localRVT)
2522 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2523
2524 ctxt->insert = oldInsert;
2525 }
2526 goto skip_children;
2527 }
2528
2529 } else if (XSLT_IS_TEXT_NODE(cur)) {
2530 /*
2531 * Text
2532 * ------------------------------------------------------------
2533 */
2534#ifdef WITH_XSLT_DEBUG_PROCESS
2535 if (cur->name == xmlStringTextNoenc) {
2536 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2537 xsltGenericDebug(xsltGenericDebugContext,
2538 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2539 cur->content));
2540 } else {
2541 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2542 xsltGenericDebug(xsltGenericDebugContext,
2543 "xsltApplySequenceConstructor: copy text '%s'\n",
2544 cur->content));
2545 }
2546#endif
2547 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2548 goto error;
2549 }
2550
2551#else /* XSLT_REFACTORED */
2552
2553 if (IS_XSLT_ELEM(cur)) {
2554 /*
2555 * This is an XSLT node
2556 */
2557 xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
2558
2559 if (info == NULL) {
2560 if (IS_XSLT_NAME(cur, "message")) {
2561 xsltMessage(ctxt, contextNode, cur);
2562 } else {
2563 /*
2564 * That's an error try to apply one of the fallback cases
2565 */
2566 ctxt->insert = insert;
2567 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2568 xsltGenericError(xsltGenericErrorContext,
2569 "xsltApplySequenceConstructor: %s was not compiled\n",
2570 cur->name);
2571 }
2572 ctxt->insert = oldInsert;
2573 }
2574 goto skip_children;
2575 }
2576
2577 if (info->func != NULL) {
2578 oldCurInst = ctxt->inst;
2579 ctxt->inst = cur;
2580 ctxt->insert = insert;
2581 oldLocalFragmentBase = ctxt->localRVTBase;
2582 ctxt->localRVTBase = NULL;
2583
2584 info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2585
2586 ctxt->localRVTBase = oldLocalFragmentBase;
2587 /*
2588 * Cleanup temporary tree fragments.
2589 */
2590 if (oldLocalFragmentTop != ctxt->localRVT)
2591 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2592
2593 ctxt->insert = oldInsert;
2594 ctxt->inst = oldCurInst;
2595 goto skip_children;
2596 }
2597
2598 if (IS_XSLT_NAME(cur, "variable")) {
2599 xsltStackElemPtr tmpvar = ctxt->vars;
2600
2601 oldCurInst = ctxt->inst;
2602 ctxt->inst = cur;
2603
2604 xsltParseStylesheetVariable(ctxt, cur);
2605
2606 ctxt->inst = oldCurInst;
2607
2608 if (tmpvar != ctxt->vars) {
2609 /*
2610 * TODO: Using a @tmpvar is an annoying workaround, but
2611 * the current mechanisms do not provide any other way
2612 * of knowing if the var was really pushed onto the
2613 * stack.
2614 */
2615 ctxt->vars->level = level;
2616 }
2617 } else if (IS_XSLT_NAME(cur, "message")) {
2618 xsltMessage(ctxt, contextNode, cur);
2619 } else {
2620 xsltTransformError(ctxt, NULL, cur,
2621 "Unexpected XSLT element '%s'.\n", cur->name);
2622 }
2623 goto skip_children;
2624 } else if ((cur->type == XML_TEXT_NODE) ||
2625 (cur->type == XML_CDATA_SECTION_NODE)) {
2626
2627 /*
2628 * This text comes from the stylesheet
2629 * For stylesheets, the set of whitespace-preserving
2630 * element names consists of just xsl:text.
2631 */
2632#ifdef WITH_XSLT_DEBUG_PROCESS
2633 if (cur->type == XML_CDATA_SECTION_NODE) {
2634 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2635 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2636 cur->content));
2637 } else if (cur->name == xmlStringTextNoenc) {
2638 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2639 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2640 cur->content));
2641 } else {
2642 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2643 "xsltApplySequenceConstructor: copy text %s\n",
2644 cur->content));
2645 }
2646#endif
2647 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2648 goto error;
2649 } else if ((cur->type == XML_ELEMENT_NODE) &&
2650 (cur->ns != NULL) && (cur->psvi != NULL)) {
2651 xsltTransformFunction function;
2652
2653 oldCurInst = ctxt->inst;
2654 ctxt->inst = cur;
2655 /*
2656 * Flagged as an extension element
2657 */
2658 if (cur->psvi == xsltExtMarker)
2659 function = (xsltTransformFunction)
2660 xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2661 else
2662 function = ((xsltElemPreCompPtr) cur->psvi)->func;
2663
2664 if (function == NULL) {
2665 xmlNodePtr child;
2666 int found = 0;
2667
2668#ifdef WITH_XSLT_DEBUG_PROCESS
2669 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2670 "xsltApplySequenceConstructor: unknown extension %s\n",
2671 cur->name));
2672#endif
2673 /*
2674 * Search if there are fallbacks
2675 */
2676 child = cur->children;
2677 while (child != NULL) {
2678 if ((IS_XSLT_ELEM(child)) &&
2679 (IS_XSLT_NAME(child, "fallback")))
2680 {
2681 found = 1;
2682 xsltApplySequenceConstructor(ctxt, contextNode,
2683 child->children, NULL);
2684 }
2685 child = child->next;
2686 }
2687
2688 if (!found) {
2689 xsltTransformError(ctxt, NULL, cur,
2690 "xsltApplySequenceConstructor: failed to find extension %s\n",
2691 cur->name);
2692 }
2693 } else {
2694#ifdef WITH_XSLT_DEBUG_PROCESS
2695 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2696 "xsltApplySequenceConstructor: extension construct %s\n",
2697 cur->name));
2698#endif
2699
2700 ctxt->insert = insert;
2701 /*
2702 * We need the fragment base for extension instructions
2703 * which return values (like EXSLT's function).
2704 */
2705 oldLocalFragmentBase = ctxt->localRVTBase;
2706 ctxt->localRVTBase = NULL;
2707
2708 function(ctxt, contextNode, cur, cur->psvi);
2709 /*
2710 * Cleanup temporary tree fragments.
2711 */
2712 if (oldLocalFragmentTop != ctxt->localRVT)
2713 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2714
2715 ctxt->localRVTBase = oldLocalFragmentBase;
2716 ctxt->insert = oldInsert;
2717
2718 }
2719 ctxt->inst = oldCurInst;
2720 goto skip_children;
2721 } else if (cur->type == XML_ELEMENT_NODE) {
2722#ifdef WITH_XSLT_DEBUG_PROCESS
2723 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2724 "xsltApplySequenceConstructor: copy node %s\n",
2725 cur->name));
2726#endif
2727 oldCurInst = ctxt->inst;
2728 ctxt->inst = cur;
2729
2730 if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2731 goto error;
2732 /*
2733 * Add extra namespaces inherited from the current template
2734 * if we are in the first level children and this is a
2735 * "real" template.
2736 */
2737 if ((templ != NULL) && (oldInsert == insert) &&
2738 (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2739 int i;
2740 xmlNsPtr ns, ret;
2741
2742 for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2743 const xmlChar *URI = NULL;
2744 xsltStylesheetPtr style;
2745 ns = ctxt->templ->inheritedNs[i];
2746
2747 /* Note that the XSLT namespace was already excluded
2748 * in xsltGetInheritedNsList().
2749 */
2750#if 0
2751 if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2752 continue;
2753#endif
2754 style = ctxt->style;
2755 while (style != NULL) {
2756 if (style->nsAliases != NULL)
2757 URI = (const xmlChar *)
2758 xmlHashLookup(style->nsAliases, ns->href);
2759 if (URI != NULL)
2760 break;
2761
2762 style = xsltNextImport(style);
2763 }
2764 if (URI == UNDEFINED_DEFAULT_NS)
2765 continue;
2766 if (URI == NULL)
2767 URI = ns->href;
2768 /*
2769 * TODO: The following will still be buggy for the
2770 * non-refactored code.
2771 */
2772 ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2773 if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2774 {
2775 xmlNewNs(copy, URI, ns->prefix);
2776 }
2777 }
2778 if (copy->ns != NULL) {
2779 /*
2780 * Fix the node namespace if needed
2781 */
2782 copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2783 }
2784 }
2785 /*
2786 * all the attributes are directly inherited
2787 */
2788 if (cur->properties != NULL) {
2789 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2790 }
2791 ctxt->inst = oldCurInst;
2792 }
2793#endif /* else of XSLT_REFACTORED */
2794
2795 /*
2796 * Descend into content in document order.
2797 */
2798 if (cur->children != NULL) {
2799 if (cur->children->type != XML_ENTITY_DECL) {
2800 cur = cur->children;
2801 level++;
2802 if (copy != NULL)
2803 insert = copy;
2804 continue;
2805 }
2806 }
2807
2808skip_children:
2809 /*
2810 * If xslt:message was just processed, we might have hit a
2811 * terminate='yes'; if so, then break the loop and clean up.
2812 * TODO: Do we need to check this also before trying to descend
2813 * into the content?
2814 */
2815 if (ctxt->state == XSLT_STATE_STOPPED)
2816 break;
2817 if (cur->next != NULL) {
2818 cur = cur->next;
2819 continue;
2820 }
2821
2822 do {
2823 cur = cur->parent;
2824 level--;
2825 /*
2826 * Pop variables/params (xsl:variable and xsl:param).
2827 */
2828 if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
2829 xsltLocalVariablePop(ctxt, oldVarsNr, level);
2830 }
2831
2832 insert = insert->parent;
2833 if (cur == NULL)
2834 break;
2835 if (cur == list->parent) {
2836 cur = NULL;
2837 break;
2838 }
2839 if (cur->next != NULL) {
2840 cur = cur->next;
2841 break;
2842 }
2843 } while (cur != NULL);
2844 }
2845
2846error:
2847 /*
2848 * In case of errors: pop remaining variables.
2849 */
2850 if (ctxt->varsNr > oldVarsNr)
2851 xsltLocalVariablePop(ctxt, oldVarsNr, -1);
2852
2853 ctxt->node = oldContextNode;
2854 ctxt->inst = oldInst;
2855 ctxt->insert = oldInsert;
2856
2857#ifdef WITH_DEBUGGER
2858 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
2859 xslDropCall();
2860 }
2861#endif
2862}
2863
2864/*
2865* xsltApplyXSLTTemplate:
2866* @ctxt: a XSLT transformation context
2867* @contextNode: the node in the source tree.
2868* @list: the nodes of a sequence constructor;
2869* (plus leading xsl:param elements)
2870* @templ: the compiled xsl:template declaration;
2871* NULL if a sequence constructor
2872* @withParams: a set of caller-parameters (xsl:with-param) or NULL
2873*
2874* Called by:
2875* - xsltApplyImports()
2876* - xsltCallTemplate()
2877* - xsltDefaultProcessOneNode()
2878* - xsltProcessOneNode()
2879*/
2880static void
2881xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
2882 xmlNodePtr contextNode,
2883 xmlNodePtr list,
2884 xsltTemplatePtr templ,
2885 xsltStackElemPtr withParams)
2886{
2887 int oldVarsBase = 0;
2888 long start = 0;
2889 xmlNodePtr cur;
2890 xsltStackElemPtr tmpParam = NULL;
2891 xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop;
2892
2893#ifdef XSLT_REFACTORED
2894 xsltStyleItemParamPtr iparam;
2895#else
2896 xsltStylePreCompPtr iparam;
2897#endif
2898
2899#ifdef WITH_DEBUGGER
2900 int addCallResult = 0;
2901#endif
2902
2903 if (ctxt == NULL)
2904 return;
2905 if (templ == NULL) {
2906 xsltTransformError(ctxt, NULL, list,
2907 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
2908 return;
2909 }
2910
2911#ifdef WITH_DEBUGGER
2912 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2913 if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2914 list, templ, &addCallResult) == NULL)
2915 return;
2916 }
2917#endif
2918
2919 if (list == NULL)
2920 return;
2921 CHECK_STOPPED;
2922
2923 /*
2924 * Check for infinite recursion: stop if the maximum of nested templates
2925 * is excceeded. Adjust xsltMaxDepth if you need more.
2926 */
2927 if (((ctxt->templNr >= xsltMaxDepth) ||
2928 (ctxt->varsNr >= 5 * xsltMaxDepth)))
2929 {
2930 xsltTransformError(ctxt, NULL, list,
2931 "xsltApplyXSLTTemplate: A potential infinite template recursion "
2932 "was detected.\n"
2933 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2934 "raise the maximum number of nested template calls and "
2935 "variables/params (currently set to %d).\n",
2936 xsltMaxDepth);
2937 xsltDebug(ctxt, contextNode, list, NULL);
2938 return;
2939 }
2940
2941 oldUserFragmentTop = ctxt->tmpRVT;
2942 ctxt->tmpRVT = NULL;
2943 oldLocalFragmentTop = ctxt->localRVT;
2944
2945 /*
2946 * Initiate a distinct scope of local params/variables.
2947 */
2948 oldVarsBase = ctxt->varsBase;
2949 ctxt->varsBase = ctxt->varsNr;
2950
2951 ctxt->node = contextNode;
2952 if (ctxt->profile) {
2953 templ->nbCalls++;
2954 start = xsltTimestamp();
2955 profPush(ctxt, 0);
2956 }
2957 /*
2958 * Push the xsl:template declaration onto the stack.
2959 */
2960 templPush(ctxt, templ);
2961
2962#ifdef WITH_XSLT_DEBUG_PROCESS
2963 if (templ->name != NULL)
2964 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2965 "applying xsl:template '%s'\n", templ->name));
2966#endif
2967 /*
2968 * Process xsl:param instructions and skip those elements for
2969 * further processing.
2970 */
2971 cur = list;
2972 do {
2973 if (cur->type == XML_TEXT_NODE) {
2974 cur = cur->next;
2975 continue;
2976 }
2977 if ((cur->type != XML_ELEMENT_NODE) ||
2978 (cur->name[0] != 'p') ||
2979 (cur->psvi == NULL) ||
2980 (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
2981 (! IS_XSLT_ELEM(cur)))
2982 {
2983 break;
2984 }
2985
2986 list = cur->next;
2987
2988#ifdef XSLT_REFACTORED
2989 iparam = (xsltStyleItemParamPtr) cur->psvi;
2990#else
2991 iparam = (xsltStylePreCompPtr) cur->psvi;
2992#endif
2993
2994 /*
2995 * Substitute xsl:param for a given xsl:with-param.
2996 * Since the XPath expression will reference the params/vars
2997 * by index, we need to slot the xsl:with-params in the
2998 * order of encountered xsl:params to keep the sequence of
2999 * params/variables in the stack exactly as it was at
3000 * compile time,
3001 */
3002 tmpParam = NULL;
3003 if (withParams) {
3004 tmpParam = withParams;
3005 do {
3006 if ((tmpParam->name == (iparam->name)) &&
3007 (tmpParam->nameURI == (iparam->ns)))
3008 {
3009 /*
3010 * Push the caller-parameter.
3011 */
3012 xsltLocalVariablePush(ctxt, tmpParam, -1);
3013 break;
3014 }
3015 tmpParam = tmpParam->next;
3016 } while (tmpParam != NULL);
3017 }
3018 /*
3019 * Push the xsl:param.
3020 */
3021 if (tmpParam == NULL) {
3022 /*
3023 * Note that we must assume that the added parameter
3024 * has a @depth of 0.
3025 */
3026 xsltParseStylesheetParam(ctxt, cur);
3027 }
3028 cur = cur->next;
3029 } while (cur != NULL);
3030 /*
3031 * Process the sequence constructor.
3032 */
3033 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3034
3035 /*
3036 * Remove remaining xsl:param and xsl:with-param items from
3037 * the stack. Don't free xsl:with-param items.
3038 */
3039 if (ctxt->varsNr > ctxt->varsBase)
3040 xsltTemplateParamsCleanup(ctxt);
3041 ctxt->varsBase = oldVarsBase;
3042
3043 /*
3044 * Clean up remaining local tree fragments.
3045 * This also frees fragments which are the result of
3046 * extension instructions. Should normally not be hit; but
3047 * just for the case xsltExtensionInstructionResultFinalize()
3048 * was not called by the extension author.
3049 */
3050 if (oldLocalFragmentTop != ctxt->localRVT) {
3051 xmlDocPtr curdoc = ctxt->localRVT, tmp;
3052
3053 do {
3054 tmp = curdoc;
3055 curdoc = (xmlDocPtr) curdoc->next;
3056 /* Need to housekeep localRVTBase */
3057 if (tmp == ctxt->localRVTBase)
3058 ctxt->localRVTBase = curdoc;
3059 if (tmp->prev)
3060 tmp->prev->next = (xmlNodePtr) curdoc;
3061 if (curdoc)
3062 curdoc->prev = tmp->prev;
3063 xsltReleaseRVT(ctxt, tmp);
3064 } while (curdoc != oldLocalFragmentTop);
3065 }
3066 ctxt->localRVT = oldLocalFragmentTop;
3067
3068 /*
3069 * Release user-created fragments stored in the scope
3070 * of xsl:template. Note that this mechanism is deprecated:
3071 * user code should now use xsltRegisterLocalRVT() instead
3072 * of the obsolete xsltRegisterTmpRVT().
3073 */
3074 if (ctxt->tmpRVT) {
3075 xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3076
3077 while (curdoc != NULL) {
3078 tmp = curdoc;
3079 curdoc = (xmlDocPtr) curdoc->next;
3080 xsltReleaseRVT(ctxt, tmp);
3081 }
3082 }
3083 ctxt->tmpRVT = oldUserFragmentTop;
3084
3085 /*
3086 * Pop the xsl:template declaration from the stack.
3087 */
3088 templPop(ctxt);
3089 if (ctxt->profile) {
3090 long spent, child, total, end;
3091
3092 end = xsltTimestamp();
3093 child = profPop(ctxt);
3094 total = end - start;
3095 spent = total - child;
3096 if (spent <= 0) {
3097 /*
3098 * Not possible unless the original calibration failed
3099 * we can try to correct it on the fly.
3100 */
3101 xsltCalibrateAdjust(spent);
3102 spent = 0;
3103 }
3104
3105 templ->time += spent;
3106 if (ctxt->profNr > 0)
3107 ctxt->profTab[ctxt->profNr - 1] += total;
3108 }
3109
3110#ifdef WITH_DEBUGGER
3111 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3112 xslDropCall();
3113 }
3114#endif
3115}
3116
3117
3118/**
3119 * xsltApplyOneTemplate:
3120 * @ctxt: a XSLT process context
3121 * @contextNode: the node in the source tree.
3122 * @list: the nodes of a sequence constructor
3123 * @templ: not used
3124 * @params: a set of parameters (xsl:param) or NULL
3125 *
3126 * Processes a sequence constructor on the current node in the source tree.
3127 *
3128 * @params are the already computed variable stack items; this function
3129 * pushes them on the variable stack, and pops them before exiting; it's
3130 * left to the caller to free or reuse @params afterwards. The initial
3131 * states of the variable stack will always be restored before this
3132 * function exits.
3133 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3134 * variables already on the stack are visible to the process. The caller's
3135 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3136 *
3137 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3138 * provide a @templ); a non-NULL @templ might raise an error in the future.
3139 *
3140 * BIG NOTE: This function is not intended to process the content of an
3141 * xsl:template; it does not expect xsl:param instructions in @list and
3142 * will report errors if found.
3143 *
3144 * Called by:
3145 * - xsltEvalVariable() (variables.c)
3146 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3147 */
3148void
3149xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
3150 xmlNodePtr contextNode,
3151 xmlNodePtr list,
3152 xsltTemplatePtr templ ATTRIBUTE_UNUSED,
3153 xsltStackElemPtr params)
3154{
3155 if ((ctxt == NULL) || (list == NULL))
3156 return;
3157 CHECK_STOPPED;
3158
3159 if (params) {
3160 /*
3161 * This code should be obsolete - was previously used
3162 * by libexslt/functions.c, but due to bug 381319 the
3163 * logic there was changed.
3164 */
3165 int oldVarsNr = ctxt->varsNr;
3166
3167 /*
3168 * Push the given xsl:param(s) onto the variable stack.
3169 */
3170 while (params != NULL) {
3171 xsltLocalVariablePush(ctxt, params, -1);
3172 params = params->next;
3173 }
3174 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3175 /*
3176 * Pop the given xsl:param(s) from the stack but don't free them.
3177 */
3178 xsltLocalVariablePop(ctxt, oldVarsNr, -2);
3179 } else
3180 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3181}
3182
3183/************************************************************************
3184 * *
3185 * XSLT-1.1 extensions *
3186 * *
3187 ************************************************************************/
3188
3189/**
3190 * xsltDocumentElem:
3191 * @ctxt: an XSLT processing context
3192 * @node: The current node
3193 * @inst: the instruction in the stylesheet
3194 * @castedComp: precomputed information
3195 *
3196 * Process an EXSLT/XSLT-1.1 document element
3197 */
3198void
3199xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
3200 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
3201{
3202#ifdef XSLT_REFACTORED
3203 xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
3204#else
3205 xsltStylePreCompPtr comp = castedComp;
3206#endif
3207 xsltStylesheetPtr style = NULL;
3208 int ret;
3209 xmlChar *filename = NULL, *prop, *elements;
3210 xmlChar *element, *end;
3211 xmlDocPtr res = NULL;
3212 xmlDocPtr oldOutput;
3213 xmlNodePtr oldInsert, root;
3214 const char *oldOutputFile;
3215 xsltOutputType oldType;
3216 xmlChar *URL = NULL;
3217 const xmlChar *method;
3218 const xmlChar *doctypePublic;
3219 const xmlChar *doctypeSystem;
3220 const xmlChar *version;
3221
3222 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
3223 return;
3224
3225 if (comp->filename == NULL) {
3226
3227 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
3228 /*
3229 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3230 * (http://icl.com/saxon)
3231 * The @file is in no namespace.
3232 */
3233#ifdef WITH_XSLT_DEBUG_EXTRA
3234 xsltGenericDebug(xsltGenericDebugContext,
3235 "Found saxon:output extension\n");
3236#endif
3237 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3238 (const xmlChar *) "file",
3239 XSLT_SAXON_NAMESPACE);
3240
3241 if (URL == NULL)
3242 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3243 (const xmlChar *) "href",
3244 XSLT_SAXON_NAMESPACE);
3245 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
3246#ifdef WITH_XSLT_DEBUG_EXTRA
3247 xsltGenericDebug(xsltGenericDebugContext,
3248 "Found xalan:write extension\n");
3249#endif
3250 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3251 (const xmlChar *)
3252 "select",
3253 XSLT_XALAN_NAMESPACE);
3254 if (URL != NULL) {
3255 xmlXPathCompExprPtr cmp;
3256 xmlChar *val;
3257
3258 /*
3259 * Trying to handle bug #59212
3260 * The value of the "select" attribute is an
3261 * XPath expression.
3262 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3263 */
3264 cmp = xmlXPathCompile(URL);
3265 val = xsltEvalXPathString(ctxt, cmp);
3266 xmlXPathFreeCompExpr(cmp);
3267 xmlFree(URL);
3268 URL = val;
3269 }
3270 if (URL == NULL)
3271 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3272 (const xmlChar *)
3273 "file",
3274 XSLT_XALAN_NAMESPACE);
3275 if (URL == NULL)
3276 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3277 (const xmlChar *)
3278 "href",
3279 XSLT_XALAN_NAMESPACE);
3280 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
3281 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3282 (const xmlChar *) "href",
3283 NULL);
3284 }
3285
3286 } else {
3287 URL = xmlStrdup(comp->filename);
3288 }
3289
3290 if (URL == NULL) {
3291 xsltTransformError(ctxt, NULL, inst,
3292 "xsltDocumentElem: href/URI-Reference not found\n");
3293 return;
3294 }
3295
3296 /*
3297 * If the computation failed, it's likely that the URL wasn't escaped
3298 */
3299 filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
3300 if (filename == NULL) {
3301 xmlChar *escURL;
3302
3303 escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
3304 if (escURL != NULL) {
3305 filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
3306 xmlFree(escURL);
3307 }
3308 }
3309
3310 if (filename == NULL) {
3311 xsltTransformError(ctxt, NULL, inst,
3312 "xsltDocumentElem: URL computation failed for %s\n",
3313 URL);
3314 xmlFree(URL);
3315 return;
3316 }
3317
3318 /*
3319 * Security checking: can we write to this resource
3320 */
3321 if (ctxt->sec != NULL) {
3322 ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
3323 if (ret == 0) {
3324 xsltTransformError(ctxt, NULL, inst,
3325 "xsltDocumentElem: write rights for %s denied\n",
3326 filename);
3327 xmlFree(URL);
3328 xmlFree(filename);
3329 return;
3330 }
3331 }
3332
3333 oldOutputFile = ctxt->outputFile;
3334 oldOutput = ctxt->output;
3335 oldInsert = ctxt->insert;
3336 oldType = ctxt->type;
3337 ctxt->outputFile = (const char *) filename;
3338
3339 style = xsltNewStylesheet();
3340 if (style == NULL) {
3341 xsltTransformError(ctxt, NULL, inst,
3342 "xsltDocumentElem: out of memory\n");
3343 goto error;
3344 }
3345
3346 /*
3347 * Version described in 1.1 draft allows full parameterization
3348 * of the output.
3349 */
3350 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3351 (const xmlChar *) "version",
3352 NULL);
3353 if (prop != NULL) {
3354 if (style->version != NULL)
3355 xmlFree(style->version);
3356 style->version = prop;
3357 }
3358 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3359 (const xmlChar *) "encoding",
3360 NULL);
3361 if (prop != NULL) {
3362 if (style->encoding != NULL)
3363 xmlFree(style->encoding);
3364 style->encoding = prop;
3365 }
3366 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3367 (const xmlChar *) "method",
3368 NULL);
3369 if (prop != NULL) {
3370 const xmlChar *URI;
3371
3372 if (style->method != NULL)
3373 xmlFree(style->method);
3374 style->method = NULL;
3375 if (style->methodURI != NULL)
3376 xmlFree(style->methodURI);
3377 style->methodURI = NULL;
3378
3379 URI = xsltGetQNameURI(inst, &prop);
3380 if (prop == NULL) {
3381 if (style != NULL) style->errors++;
3382 } else if (URI == NULL) {
3383 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3384 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
3385 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
3386 style->method = prop;
3387 } else {
3388 xsltTransformError(ctxt, NULL, inst,
3389 "invalid value for method: %s\n", prop);
3390 if (style != NULL) style->warnings++;
3391 }
3392 } else {
3393 style->method = prop;
3394 style->methodURI = xmlStrdup(URI);
3395 }
3396 }
3397 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3398 (const xmlChar *)
3399 "doctype-system", NULL);
3400 if (prop != NULL) {
3401 if (style->doctypeSystem != NULL)
3402 xmlFree(style->doctypeSystem);
3403 style->doctypeSystem = prop;
3404 }
3405 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3406 (const xmlChar *)
3407 "doctype-public", NULL);
3408 if (prop != NULL) {
3409 if (style->doctypePublic != NULL)
3410 xmlFree(style->doctypePublic);
3411 style->doctypePublic = prop;
3412 }
3413 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3414 (const xmlChar *) "standalone",
3415 NULL);
3416 if (prop != NULL) {
3417 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3418 style->standalone = 1;
3419 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3420 style->standalone = 0;
3421 } else {
3422 xsltTransformError(ctxt, NULL, inst,
3423 "invalid value for standalone: %s\n",
3424 prop);
3425 if (style != NULL) style->warnings++;
3426 }
3427 xmlFree(prop);
3428 }
3429
3430 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3431 (const xmlChar *) "indent",
3432 NULL);
3433 if (prop != NULL) {
3434 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3435 style->indent = 1;
3436 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3437 style->indent = 0;
3438 } else {
3439 xsltTransformError(ctxt, NULL, inst,
3440 "invalid value for indent: %s\n", prop);
3441 if (style != NULL) style->warnings++;
3442 }
3443 xmlFree(prop);
3444 }
3445
3446 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3447 (const xmlChar *)
3448 "omit-xml-declaration",
3449 NULL);
3450 if (prop != NULL) {
3451 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3452 style->omitXmlDeclaration = 1;
3453 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3454 style->omitXmlDeclaration = 0;
3455 } else {
3456 xsltTransformError(ctxt, NULL, inst,
3457 "invalid value for omit-xml-declaration: %s\n",
3458 prop);
3459 if (style != NULL) style->warnings++;
3460 }
3461 xmlFree(prop);
3462 }
3463
3464 elements = xsltEvalAttrValueTemplate(ctxt, inst,
3465 (const xmlChar *)
3466 "cdata-section-elements",
3467 NULL);
3468 if (elements != NULL) {
3469 if (style->stripSpaces == NULL)
3470 style->stripSpaces = xmlHashCreate(10);
3471 if (style->stripSpaces == NULL)
3472 return;
3473
3474 element = elements;
3475 while (*element != 0) {
3476 while (IS_BLANK_CH(*element))
3477 element++;
3478 if (*element == 0)
3479 break;
3480 end = element;
3481 while ((*end != 0) && (!IS_BLANK_CH(*end)))
3482 end++;
3483 element = xmlStrndup(element, end - element);
3484 if (element) {
3485 const xmlChar *URI;
3486
3487#ifdef WITH_XSLT_DEBUG_PARSING
3488 xsltGenericDebug(xsltGenericDebugContext,
3489 "add cdata section output element %s\n",
3490 element);
3491#endif
3492 URI = xsltGetQNameURI(inst, &element);
3493
3494 xmlHashAddEntry2(style->stripSpaces, element, URI,
3495 (xmlChar *) "cdata");
3496 xmlFree(element);
3497 }
3498 element = end;
3499 }
3500 xmlFree(elements);
3501 }
3502
3503 /*
3504 * Create a new document tree and process the element template
3505 */
3506 XSLT_GET_IMPORT_PTR(method, style, method)
3507 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3508 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3509 XSLT_GET_IMPORT_PTR(version, style, version)
3510
3511 if ((method != NULL) &&
3512 (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3513 if (xmlStrEqual(method, (const xmlChar *) "html")) {
3514 ctxt->type = XSLT_OUTPUT_HTML;
3515 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3516 res = htmlNewDoc(doctypeSystem, doctypePublic);
3517 else {
3518 if (version != NULL) {
3519#ifdef XSLT_GENERATE_HTML_DOCTYPE
3520 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3521#endif
3522 }
3523 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3524 }
3525 if (res == NULL)
3526 goto error;
3527 res->dict = ctxt->dict;
3528 xmlDictReference(res->dict);
3529 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3530 xsltTransformError(ctxt, NULL, inst,
3531 "xsltDocumentElem: unsupported method xhtml\n",
3532 style->method);
3533 ctxt->type = XSLT_OUTPUT_HTML;
3534 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3535 if (res == NULL)
3536 goto error;
3537 res->dict = ctxt->dict;
3538 xmlDictReference(res->dict);
3539 } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3540 ctxt->type = XSLT_OUTPUT_TEXT;
3541 res = xmlNewDoc(style->version);
3542 if (res == NULL)
3543 goto error;
3544 res->dict = ctxt->dict;
3545 xmlDictReference(res->dict);
3546#ifdef WITH_XSLT_DEBUG
3547 xsltGenericDebug(xsltGenericDebugContext,
3548 "reusing transformation dict for output\n");
3549#endif
3550 } else {
3551 xsltTransformError(ctxt, NULL, inst,
3552 "xsltDocumentElem: unsupported method %s\n",
3553 style->method);
3554 goto error;
3555 }
3556 } else {
3557 ctxt->type = XSLT_OUTPUT_XML;
3558 res = xmlNewDoc(style->version);
3559 if (res == NULL)
3560 goto error;
3561 res->dict = ctxt->dict;
3562 xmlDictReference(res->dict);
3563#ifdef WITH_XSLT_DEBUG
3564 xsltGenericDebug(xsltGenericDebugContext,
3565 "reusing transformation dict for output\n");
3566#endif
3567 }
3568 res->charset = XML_CHAR_ENCODING_UTF8;
3569 if (style->encoding != NULL)
3570 res->encoding = xmlStrdup(style->encoding);
3571 ctxt->output = res;
3572 ctxt->insert = (xmlNodePtr) res;
3573 xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
3574
3575 /*
3576 * Do some post processing work depending on the generated output
3577 */
3578 root = xmlDocGetRootElement(res);
3579 if (root != NULL) {
3580 const xmlChar *doctype = NULL;
3581
3582 if ((root->ns != NULL) && (root->ns->prefix != NULL))
3583 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3584 if (doctype == NULL)
3585 doctype = root->name;
3586
3587 /*
3588 * Apply the default selection of the method
3589 */
3590 if ((method == NULL) &&
3591 (root->ns == NULL) &&
3592 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3593 xmlNodePtr tmp;
3594
3595 tmp = res->children;
3596 while ((tmp != NULL) && (tmp != root)) {
3597 if (tmp->type == XML_ELEMENT_NODE)
3598 break;
3599 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3600 break;
3601 tmp = tmp->next;
3602 }
3603 if (tmp == root) {
3604 ctxt->type = XSLT_OUTPUT_HTML;
3605 res->type = XML_HTML_DOCUMENT_NODE;
3606 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3607 res->intSubset = xmlCreateIntSubset(res, doctype,
3608 doctypePublic,
3609 doctypeSystem);
3610#ifdef XSLT_GENERATE_HTML_DOCTYPE
3611 } else if (version != NULL) {
3612 xsltGetHTMLIDs(version, &doctypePublic,
3613 &doctypeSystem);
3614 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3615 res->intSubset =
3616 xmlCreateIntSubset(res, doctype,
3617 doctypePublic,
3618 doctypeSystem);
3619#endif
3620 }
3621 }
3622
3623 }
3624 if (ctxt->type == XSLT_OUTPUT_XML) {
3625 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3626 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3627 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3628 res->intSubset = xmlCreateIntSubset(res, doctype,
3629 doctypePublic,
3630 doctypeSystem);
3631 }
3632 }
3633
3634 /*
3635 * Save the result
3636 */
3637 ret = xsltSaveResultToFilename((const char *) filename,
3638 res, style, 0);
3639 if (ret < 0) {
3640 xsltTransformError(ctxt, NULL, inst,
3641 "xsltDocumentElem: unable to save to %s\n",
3642 filename);
3643 ctxt->state = XSLT_STATE_ERROR;
3644#ifdef WITH_XSLT_DEBUG_EXTRA
3645 } else {
3646 xsltGenericDebug(xsltGenericDebugContext,
3647 "Wrote %d bytes to %s\n", ret, filename);
3648#endif
3649 }
3650
3651 error:
3652 ctxt->output = oldOutput;
3653 ctxt->insert = oldInsert;
3654 ctxt->type = oldType;
3655 ctxt->outputFile = oldOutputFile;
3656 if (URL != NULL)
3657 xmlFree(URL);
3658 if (filename != NULL)
3659 xmlFree(filename);
3660 if (style != NULL)
3661 xsltFreeStylesheet(style);
3662 if (res != NULL)
3663 xmlFreeDoc(res);
3664}
3665
3666/************************************************************************
3667 * *
3668 * Most of the XSLT-1.0 transformations *
3669 * *
3670 ************************************************************************/
3671
3672/**
3673 * xsltSort:
3674 * @ctxt: a XSLT process context
3675 * @node: the node in the source tree.
3676 * @inst: the xslt sort node
3677 * @comp: precomputed information
3678 *
3679 * function attached to xsl:sort nodes, but this should not be
3680 * called directly
3681 */
3682void
3683xsltSort(xsltTransformContextPtr ctxt,
3684 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
3685 xsltStylePreCompPtr comp) {
3686 if (comp == NULL) {
3687 xsltTransformError(ctxt, NULL, inst,
3688 "xsl:sort : compilation failed\n");
3689 return;
3690 }
3691 xsltTransformError(ctxt, NULL, inst,
3692 "xsl:sort : improper use this should not be reached\n");
3693}
3694
3695/**
3696 * xsltCopy:
3697 * @ctxt: an XSLT process context
3698 * @node: the node in the source tree
3699 * @inst: the element node of the XSLT-copy instruction
3700 * @castedComp: computed information of the XSLT-copy instruction
3701 *
3702 * Execute the XSLT-copy instruction on the source node.
3703 */
3704void
3705xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
3706 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
3707{
3708#ifdef XSLT_REFACTORED
3709 xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3710#else
3711 xsltStylePreCompPtr comp = castedComp;
3712#endif
3713 xmlNodePtr copy, oldInsert;
3714
3715 oldInsert = ctxt->insert;
3716 if (ctxt->insert != NULL) {
3717 switch (node->type) {
3718 case XML_TEXT_NODE:
3719 case XML_CDATA_SECTION_NODE:
3720 /*
3721 * This text comes from the stylesheet
3722 * For stylesheets, the set of whitespace-preserving
3723 * element names consists of just xsl:text.
3724 */
3725#ifdef WITH_XSLT_DEBUG_PROCESS
3726 if (node->type == XML_CDATA_SECTION_NODE) {
3727 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3728 "xsltCopy: CDATA text %s\n", node->content));
3729 } else {
3730 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3731 "xsltCopy: text %s\n", node->content));
3732 }
3733#endif
3734 xsltCopyText(ctxt, ctxt->insert, node, 0);
3735 break;
3736 case XML_DOCUMENT_NODE:
3737 case XML_HTML_DOCUMENT_NODE:
3738 break;
3739 case XML_ELEMENT_NODE:
3740 /*
3741 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3742 * REMOVED:
3743 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3744 * return;
3745 */
3746
3747#ifdef WITH_XSLT_DEBUG_PROCESS
3748 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3749 "xsltCopy: node %s\n", node->name));
3750#endif
3751 copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3752 ctxt->insert = copy;
3753 if (comp->use != NULL) {
3754 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3755 }
3756 break;
3757 case XML_ATTRIBUTE_NODE: {
3758#ifdef WITH_XSLT_DEBUG_PROCESS
3759 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3760 "xsltCopy: attribute %s\n", node->name));
3761#endif
3762 /*
3763 * REVISIT: We could also raise an error if the parent is not
3764 * an element node.
3765 * OPTIMIZE TODO: Can we set the value/children of the
3766 * attribute without an intermediate copy of the string value?
3767 */
3768 xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
3769 break;
3770 }
3771 case XML_PI_NODE:
3772#ifdef WITH_XSLT_DEBUG_PROCESS
3773 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3774 "xsltCopy: PI %s\n", node->name));
3775#endif
3776 copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3777 node->content);
3778 xmlAddChild(ctxt->insert, copy);
3779 break;
3780 case XML_COMMENT_NODE:
3781#ifdef WITH_XSLT_DEBUG_PROCESS
3782 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3783 "xsltCopy: comment\n"));
3784#endif
3785 copy = xmlNewComment(node->content);
3786 xmlAddChild(ctxt->insert, copy);
3787 break;
3788 case XML_NAMESPACE_DECL:
3789#ifdef WITH_XSLT_DEBUG_PROCESS
3790 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3791 "xsltCopy: namespace declaration\n"));
3792#endif
3793 xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3794 break;
3795 default:
3796 break;
3797
3798 }
3799 }
3800
3801 switch (node->type) {
3802 case XML_DOCUMENT_NODE:
3803 case XML_HTML_DOCUMENT_NODE:
3804 case XML_ELEMENT_NODE:
3805 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
3806 NULL);
3807 break;
3808 default:
3809 break;
3810 }
3811 ctxt->insert = oldInsert;
3812}
3813
3814/**
3815 * xsltText:
3816 * @ctxt: a XSLT process context
3817 * @node: the node in the source tree.
3818 * @inst: the xslt text node
3819 * @comp: precomputed information
3820 *
3821 * Process the xslt text node on the source node
3822 */
3823void
3824xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
3825 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
3826 if ((inst->children != NULL) && (comp != NULL)) {
3827 xmlNodePtr text = inst->children;
3828 xmlNodePtr copy;
3829
3830 while (text != NULL) {
3831 if ((text->type != XML_TEXT_NODE) &&
3832 (text->type != XML_CDATA_SECTION_NODE)) {
3833 xsltTransformError(ctxt, NULL, inst,
3834 "xsl:text content problem\n");
3835 break;
3836 }
3837 copy = xmlNewDocText(ctxt->output, text->content);
3838 if (text->type != XML_CDATA_SECTION_NODE) {
3839#ifdef WITH_XSLT_DEBUG_PARSING
3840 xsltGenericDebug(xsltGenericDebugContext,
3841 "Disable escaping: %s\n", text->content);
3842#endif
3843 copy->name = xmlStringTextNoenc;
3844 }
3845 xmlAddChild(ctxt->insert, copy);
3846 text = text->next;
3847 }
3848 }
3849}
3850
3851/**
3852 * xsltElement:
3853 * @ctxt: a XSLT process context
3854 * @node: the node in the source tree.
3855 * @inst: the xslt element node
3856 * @castedComp: precomputed information
3857 *
3858 * Process the xslt element node on the source node
3859 */
3860void
3861xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
3862 xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
3863#ifdef XSLT_REFACTORED
3864 xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
3865#else
3866 xsltStylePreCompPtr comp = castedComp;
3867#endif
3868 xmlChar *prop = NULL;
3869 const xmlChar *name, *prefix = NULL, *nsName = NULL;
3870 xmlNodePtr copy;
3871 xmlNodePtr oldInsert;
3872
3873 if (ctxt->insert == NULL)
3874 return;
3875
3876 /*
3877 * A comp->has_name == 0 indicates that we need to skip this instruction,
3878 * since it was evaluated to be invalid already during compilation.
3879 */
3880 if (!comp->has_name)
3881 return;
3882
3883 /*
3884 * stack and saves
3885 */
3886 oldInsert = ctxt->insert;
3887
3888 if (comp->name == NULL) {
3889 /* TODO: fix attr acquisition wrt to the XSLT namespace */
3890 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3891 (const xmlChar *) "name", XSLT_NAMESPACE);
3892 if (prop == NULL) {
3893 xsltTransformError(ctxt, NULL, inst,
3894 "xsl:element: The attribute 'name' is missing.\n");
3895 goto error;
3896 }
3897 if (xmlValidateQName(prop, 0)) {
3898 xsltTransformError(ctxt, NULL, inst,
3899 "xsl:element: The effective name '%s' is not a "
3900 "valid QName.\n", prop);
3901 /* we fall through to catch any further errors, if possible */
3902 }
3903 name = xsltSplitQName(ctxt->dict, prop, &prefix);
3904 xmlFree(prop);
3905 if ((prefix != NULL) &&
3906 (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
3907 {
3908 /*
3909 * TODO: Should we really disallow an "xml" prefix?
3910 */
3911 goto error;
3912 }
3913 } else {
3914 /*
3915 * The "name" value was static.
3916 */
3917#ifdef XSLT_REFACTORED
3918 prefix = comp->nsPrefix;
3919 name = comp->name;
3920#else
3921 name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
3922#endif
3923 }
3924
3925 /*
3926 * Create the new element
3927 */
3928 if (ctxt->output->dict == ctxt->dict) {
3929 copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
3930 } else {
3931 copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
3932 }
3933 if (copy == NULL) {
3934 xsltTransformError(ctxt, NULL, inst,
3935 "xsl:element : creation of %s failed\n", name);
3936 return;
3937 }
3938 xmlAddChild(ctxt->insert, copy);
3939
3940 /*
3941 * Namespace
3942 * ---------
3943 */
3944 if (comp->has_ns) {
3945 if (comp->ns != NULL) {
3946 /*
3947 * No AVT; just plain text for the namespace name.
3948 */
3949 if (comp->ns[0] != 0)
3950 nsName = comp->ns;
3951 } else {
3952 xmlChar *tmpNsName;
3953 /*
3954 * Eval the AVT.
3955 */
3956 /* TODO: check attr acquisition wrt to the XSLT namespace */
3957 tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
3958 (const xmlChar *) "namespace", XSLT_NAMESPACE);
3959 /*
3960 * SPEC XSLT 1.0:
3961 * "If the string is empty, then the expanded-name of the
3962 * attribute has a null namespace URI."
3963 */
3964 if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
3965 nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
3966 xmlFree(tmpNsName);
3967 };
3968 } else {
3969 xmlNsPtr ns;
3970 /*
3971 * SPEC XSLT 1.0:
3972 * "If the namespace attribute is not present, then the QName is
3973 * expanded into an expanded-name using the namespace declarations
3974 * in effect for the xsl:element element, including any default
3975 * namespace declaration.
3976 */
3977 ns = xmlSearchNs(inst->doc, inst, prefix);
3978 if (ns == NULL) {
3979 /*
3980 * TODO: Check this in the compilation layer in case it's a
3981 * static value.
3982 */
3983 if (prefix != NULL) {
3984 xsltTransformError(ctxt, NULL, inst,
3985 "xsl:element: The QName '%s:%s' has no "
3986 "namespace binding in scope in the stylesheet; "
3987 "this is an error, since the namespace was not "
3988 "specified by the instruction itself.\n", prefix, name);
3989 }
3990 } else
3991 nsName = ns->href;
3992 }
3993 /*
3994 * Find/create a matching ns-decl in the result tree.
3995 */
3996 if (nsName != NULL) {
3997 copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy);
3998 } else if ((copy->parent != NULL) &&
3999 (copy->parent->type == XML_ELEMENT_NODE) &&
4000 (copy->parent->ns != NULL))
4001 {
4002 /*
4003 * "Undeclare" the default namespace.
4004 */
4005 xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4006 }
4007
4008 ctxt->insert = copy;
4009
4010 if (comp->has_use) {
4011 if (comp->use != NULL) {
4012 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4013 } else {
4014 xmlChar *attrSets = NULL;
4015 /*
4016 * BUG TODO: use-attribute-sets is not a value template.
4017 * use-attribute-sets = qnames
4018 */
4019 attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4020 (const xmlChar *)"use-attribute-sets", NULL);
4021 if (attrSets != NULL) {
4022 xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4023 xmlFree(attrSets);
4024 }
4025 }
4026 }
4027 /*
4028 * Instantiate the sequence constructor.
4029 */
4030 if (inst->children != NULL)
4031 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4032 NULL);
4033
4034error:
4035 ctxt->insert = oldInsert;
4036 return;
4037}
4038
4039
4040/**
4041 * xsltComment:
4042 * @ctxt: a XSLT process context
4043 * @node: the node in the source tree.
4044 * @inst: the xslt comment node
4045 * @comp: precomputed information
4046 *
4047 * Process the xslt comment node on the source node
4048 */
4049void
4050xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
4051 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
4052 xmlChar *value = NULL;
4053 xmlNodePtr commentNode;
4054 int len;
4055
4056 value = xsltEvalTemplateString(ctxt, node, inst);
4057 /* TODO: use or generate the compiled form */
4058 len = xmlStrlen(value);
4059 if (len > 0) {
4060 if ((value[len-1] == '-') ||
4061 (xmlStrstr(value, BAD_CAST "--"))) {
4062 xsltTransformError(ctxt, NULL, inst,
4063 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4064 /* fall through to try to catch further errors */
4065 }
4066 }
4067#ifdef WITH_XSLT_DEBUG_PROCESS
4068 if (value == NULL) {
4069 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4070 "xsltComment: empty\n"));
4071 } else {
4072 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4073 "xsltComment: content %s\n", value));
4074 }
4075#endif
4076
4077 commentNode = xmlNewComment(value);
4078 xmlAddChild(ctxt->insert, commentNode);
4079
4080 if (value != NULL)
4081 xmlFree(value);
4082}
4083
4084/**
4085 * xsltProcessingInstruction:
4086 * @ctxt: a XSLT process context
4087 * @node: the node in the source tree.
4088 * @inst: the xslt processing-instruction node
4089 * @castedComp: precomputed information
4090 *
4091 * Process the xslt processing-instruction node on the source node
4092 */
4093void
4094xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
4095 xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
4096#ifdef XSLT_REFACTORED
4097 xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4098#else
4099 xsltStylePreCompPtr comp = castedComp;
4100#endif
4101 const xmlChar *name;
4102 xmlChar *value = NULL;
4103 xmlNodePtr pi;
4104
4105
4106 if (ctxt->insert == NULL)
4107 return;
4108 if (comp->has_name == 0)
4109 return;
4110 if (comp->name == NULL) {
4111 name = xsltEvalAttrValueTemplate(ctxt, inst,
4112 (const xmlChar *)"name", NULL);
4113 if (name == NULL) {
4114 xsltTransformError(ctxt, NULL, inst,
4115 "xsl:processing-instruction : name is missing\n");
4116 goto error;
4117 }
4118 } else {
4119 name = comp->name;
4120 }
4121 /* TODO: check that it's both an an NCName and a PITarget. */
4122
4123
4124 value = xsltEvalTemplateString(ctxt, node, inst);
4125 if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4126 xsltTransformError(ctxt, NULL, inst,
4127 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4128 goto error;
4129 }
4130#ifdef WITH_XSLT_DEBUG_PROCESS
4131 if (value == NULL) {
4132 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4133 "xsltProcessingInstruction: %s empty\n", name));
4134 } else {
4135 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4136 "xsltProcessingInstruction: %s content %s\n", name, value));
4137 }
4138#endif
4139
4140 pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4141 xmlAddChild(ctxt->insert, pi);
4142
4143error:
4144 if ((name != NULL) && (name != comp->name))
4145 xmlFree((xmlChar *) name);
4146 if (value != NULL)
4147 xmlFree(value);
4148}
4149
4150/**
4151 * xsltCopyOf:
4152 * @ctxt: an XSLT transformation context
4153 * @node: the current node in the source tree
4154 * @inst: the element node of the XSLT copy-of instruction
4155 * @castedComp: precomputed information of the XSLT copy-of instruction
4156 *
4157 * Process the XSLT copy-of instruction.
4158 */
4159void
4160xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4161 xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
4162#ifdef XSLT_REFACTORED
4163 xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4164#else
4165 xsltStylePreCompPtr comp = castedComp;
4166#endif
4167 xmlXPathObjectPtr res = NULL;
4168 xmlNodeSetPtr list = NULL;
4169 int i;
4170 xmlDocPtr oldXPContextDoc;
4171 xmlNsPtr *oldXPNamespaces;
4172 xmlNodePtr oldXPContextNode;
4173 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
4174 xmlXPathContextPtr xpctxt;
4175
4176 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4177 return;
4178 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4179 xsltTransformError(ctxt, NULL, inst,
4180 "xsl:copy-of : compilation failed\n");
4181 return;
4182 }
4183
4184 /*
4185 * SPEC XSLT 1.0:
4186 * "The xsl:copy-of element can be used to insert a result tree
4187 * fragment into the result tree, without first converting it to
4188 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4189 * xsl:value-of]). The required select attribute contains an
4190 * expression. When the result of evaluating the expression is a
4191 * result tree fragment, the complete fragment is copied into the
4192 * result tree. When the result is a node-set, all the nodes in the
4193 * set are copied in document order into the result tree; copying
4194 * an element node copies the attribute nodes, namespace nodes and
4195 * children of the element node as well as the element node itself;
4196 * a root node is copied by copying its children. When the result
4197 * is neither a node-set nor a result tree fragment, the result is
4198 * converted to a string and then inserted into the result tree,
4199 * as with xsl:value-of.
4200 */
4201
4202#ifdef WITH_XSLT_DEBUG_PROCESS
4203 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4204 "xsltCopyOf: select %s\n", comp->select));
4205#endif
4206
4207 /*
4208 * Evaluate the "select" expression.
4209 */
4210 xpctxt = ctxt->xpathCtxt;
4211 oldXPContextDoc = xpctxt->doc;
4212 oldXPContextNode = xpctxt->node;
4213 oldXPProximityPosition = xpctxt->proximityPosition;
4214 oldXPContextSize = xpctxt->contextSize;
4215 oldXPNsNr = xpctxt->nsNr;
4216 oldXPNamespaces = xpctxt->namespaces;
4217
4218 xpctxt->node = node;
4219 if (comp != NULL) {
4220
4221#ifdef XSLT_REFACTORED
4222 if (comp->inScopeNs != NULL) {
4223 xpctxt->namespaces = comp->inScopeNs->list;
4224 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4225 } else {
4226 xpctxt->namespaces = NULL;
4227 xpctxt->nsNr = 0;
4228 }
4229#else
4230 xpctxt->namespaces = comp->nsList;
4231 xpctxt->nsNr = comp->nsNr;
4232#endif
4233 } else {
4234 xpctxt->namespaces = NULL;
4235 xpctxt->nsNr = 0;
4236 }
4237
4238 res = xmlXPathCompiledEval(comp->comp, xpctxt);
4239
4240 xpctxt->doc = oldXPContextDoc;
4241 xpctxt->node = oldXPContextNode;
4242 xpctxt->contextSize = oldXPContextSize;
4243 xpctxt->proximityPosition = oldXPProximityPosition;
4244 xpctxt->nsNr = oldXPNsNr;
4245 xpctxt->namespaces = oldXPNamespaces;
4246
4247 if (res != NULL) {
4248 if (res->type == XPATH_NODESET) {
4249 /*
4250 * Node-set
4251 * --------
4252 */
4253#ifdef WITH_XSLT_DEBUG_PROCESS
4254 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4255 "xsltCopyOf: result is a node set\n"));
4256#endif
4257 list = res->nodesetval;
4258 if (list != NULL) {
4259 xmlNodePtr cur;
4260 /*
4261 * The list is already sorted in document order by XPath.
4262 * Append everything in this order under ctxt->insert.
4263 */
4264 for (i = 0;i < list->nodeNr;i++) {
4265 cur = list->nodeTab[i];
4266 if (cur == NULL)
4267 continue;
4268 if ((cur->type == XML_DOCUMENT_NODE) ||
4269 (cur->type == XML_HTML_DOCUMENT_NODE))
4270 {
4271 xsltCopyTreeList(ctxt, inst,
4272 cur->children, ctxt->insert, 0, 0);
4273 } else if (cur->type == XML_ATTRIBUTE_NODE) {
4274 xsltShallowCopyAttr(ctxt, inst,
4275 ctxt->insert, (xmlAttrPtr) cur);
4276 } else {
4277 xsltCopyTreeInternal(ctxt, inst,
4278 cur, ctxt->insert, 0, 0);
4279 }
4280 }
4281 }
4282 } else if (res->type == XPATH_XSLT_TREE) {
4283 /*
4284 * Result tree fragment
4285 * --------------------
4286 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4287 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4288 */
4289#ifdef WITH_XSLT_DEBUG_PROCESS
4290 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4291 "xsltCopyOf: result is a result tree fragment\n"));
4292#endif
4293 list = res->nodesetval;
4294 if ((list != NULL) && (list->nodeTab != NULL) &&
4295 (list->nodeTab[0] != NULL) &&
4296 (IS_XSLT_REAL_NODE(list->nodeTab[0])))
4297 {
4298 xsltCopyTreeList(ctxt, inst,
4299 list->nodeTab[0]->children, ctxt->insert, 0, 0);
4300 }
4301 } else {
4302 xmlChar *value = NULL;
4303 /*
4304 * Convert to a string.
4305 */
4306 value = xmlXPathCastToString(res);
4307 if (value == NULL) {
4308 xsltTransformError(ctxt, NULL, inst,
4309 "Internal error in xsltCopyOf(): "
4310 "failed to cast an XPath object to string.\n");
4311 ctxt->state = XSLT_STATE_STOPPED;
4312 } else {
4313 if (value[0] != 0) {
4314 /*
4315 * Append content as text node.
4316 */
4317 xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4318 }
4319 xmlFree(value);
4320
4321#ifdef WITH_XSLT_DEBUG_PROCESS
4322 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4323 "xsltCopyOf: result %s\n", res->stringval));
4324#endif
4325 }
4326 }
4327 } else {
4328 ctxt->state = XSLT_STATE_STOPPED;
4329 }
4330
4331 if (res != NULL)
4332 xmlXPathFreeObject(res);
4333}
4334
4335/**
4336 * xsltValueOf:
4337 * @ctxt: a XSLT process context
4338 * @node: the node in the source tree.
4339 * @inst: the xslt value-of node
4340 * @castedComp: precomputed information
4341 *
4342 * Process the xslt value-of node on the source node
4343 */
4344void
4345xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4346 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4347{
4348#ifdef XSLT_REFACTORED
4349 xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4350#else
4351 xsltStylePreCompPtr comp = castedComp;
4352#endif
4353 xmlXPathObjectPtr res = NULL;
4354 xmlNodePtr copy = NULL;
4355 xmlChar *value = NULL;
4356 xmlDocPtr oldXPContextDoc;
4357 xmlNsPtr *oldXPNamespaces;
4358 xmlNodePtr oldXPContextNode;
4359 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
4360 xmlXPathContextPtr xpctxt;
4361
4362 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4363 return;
4364
4365 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4366 xsltTransformError(ctxt, NULL, inst,
4367 "Internal error in xsltValueOf(): "
4368 "The XSLT 'value-of' instruction was not compiled.\n");
4369 return;
4370 }
4371
4372#ifdef WITH_XSLT_DEBUG_PROCESS
4373 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4374 "xsltValueOf: select %s\n", comp->select));
4375#endif
4376
4377 xpctxt = ctxt->xpathCtxt;
4378 oldXPContextDoc = xpctxt->doc;
4379 oldXPContextNode = xpctxt->node;
4380 oldXPProximityPosition = xpctxt->proximityPosition;
4381 oldXPContextSize = xpctxt->contextSize;
4382 oldXPNsNr = xpctxt->nsNr;
4383 oldXPNamespaces = xpctxt->namespaces;
4384
4385 xpctxt->node = node;
4386 if (comp != NULL) {
4387
4388#ifdef XSLT_REFACTORED
4389 if (comp->inScopeNs != NULL) {
4390 xpctxt->namespaces = comp->inScopeNs->list;
4391 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4392 } else {
4393 xpctxt->namespaces = NULL;
4394 xpctxt->nsNr = 0;
4395 }
4396#else
4397 xpctxt->namespaces = comp->nsList;
4398 xpctxt->nsNr = comp->nsNr;
4399#endif
4400 } else {
4401 xpctxt->namespaces = NULL;
4402 xpctxt->nsNr = 0;
4403 }
4404
4405 res = xmlXPathCompiledEval(comp->comp, xpctxt);
4406
4407 xpctxt->doc = oldXPContextDoc;
4408 xpctxt->node = oldXPContextNode;
4409 xpctxt->contextSize = oldXPContextSize;
4410 xpctxt->proximityPosition = oldXPProximityPosition;
4411 xpctxt->nsNr = oldXPNsNr;
4412 xpctxt->namespaces = oldXPNamespaces;
4413
4414 /*
4415 * Cast the XPath object to string.
4416 */
4417 if (res != NULL) {
4418 value = xmlXPathCastToString(res);
4419 if (value == NULL) {
4420 xsltTransformError(ctxt, NULL, inst,
4421 "Internal error in xsltValueOf(): "
4422 "failed to cast an XPath object to string.\n");
4423 ctxt->state = XSLT_STATE_STOPPED;
4424 goto error;
4425 }
4426 if (value[0] != 0) {
4427 copy = xsltCopyTextString(ctxt,
4428 ctxt->insert, value, comp->noescape);
4429 }
4430 } else {
4431 xsltTransformError(ctxt, NULL, inst,
4432 "XPath evaluation returned no result.\n");
4433 ctxt->state = XSLT_STATE_STOPPED;
4434 goto error;
4435 }
4436
4437#ifdef WITH_XSLT_DEBUG_PROCESS
4438 if (value) {
4439 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4440 "xsltValueOf: result '%s'\n", value));
4441 }
4442#endif
4443
4444error:
4445 if (value != NULL)
4446 xmlFree(value);
4447 if (res != NULL)
4448 xmlXPathFreeObject(res);
4449}
4450
4451/**
4452 * xsltNumber:
4453 * @ctxt: a XSLT process context
4454 * @node: the node in the source tree.
4455 * @inst: the xslt number node
4456 * @castedComp: precomputed information
4457 *
4458 * Process the xslt number node on the source node
4459 */
4460void
4461xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
4462 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4463{
4464#ifdef XSLT_REFACTORED
4465 xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4466#else
4467 xsltStylePreCompPtr comp = castedComp;
4468#endif
4469 if (comp == NULL) {
4470 xsltTransformError(ctxt, NULL, inst,
4471 "xsl:number : compilation failed\n");
4472 return;
4473 }
4474
4475 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4476 return;
4477
4478 comp->numdata.doc = inst->doc;
4479 comp->numdata.node = inst;
4480
4481 xsltNumberFormat(ctxt, &comp->numdata, node);
4482}
4483
4484/**
4485 * xsltApplyImports:
4486 * @ctxt: an XSLT transformation context
4487 * @contextNode: the current node in the source tree.
4488 * @inst: the element node of the XSLT 'apply-imports' instruction
4489 * @comp: the compiled instruction
4490 *
4491 * Process the XSLT apply-imports element.
4492 */
4493void
4494xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
4495 xmlNodePtr inst,
4496 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
4497{
4498 xsltTemplatePtr templ;
4499
4500 if ((ctxt == NULL) || (inst == NULL))
4501 return;
4502
4503 if (comp == NULL) {
4504 xsltTransformError(ctxt, NULL, inst,
4505 "Internal error in xsltApplyImports(): "
4506 "The XSLT 'apply-imports' instruction was not compiled.\n");
4507 return;
4508 }
4509 /*
4510 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4511 * same; the former is the "Current Template Rule" as defined by the
4512 * XSLT spec, the latter is simply the template struct being
4513 * currently processed.
4514 */
4515 if (ctxt->currentTemplateRule == NULL) {
4516 /*
4517 * SPEC XSLT 2.0:
4518 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4519 * xsl:apply-imports or xsl:next-match is evaluated when the
4520 * current template rule is null."
4521 */
4522 xsltTransformError(ctxt, NULL, inst,
4523 "It is an error to call 'apply-imports' "
4524 "when there's no current template rule.\n");
4525 return;
4526 }
4527 /*
4528 * TODO: Check if this is correct.
4529 */
4530 templ = xsltGetTemplate(ctxt, contextNode,
4531 ctxt->currentTemplateRule->style);
4532
4533 if (templ != NULL) {
4534 xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4535 /*
4536 * Set the current template rule.
4537 */
4538 ctxt->currentTemplateRule = templ;
4539 /*
4540 * URGENT TODO: Need xsl:with-param be handled somehow here?
4541 */
4542 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4543 templ, NULL);
4544
4545 ctxt->currentTemplateRule = oldCurTemplRule;
4546 }
4547}
4548
4549/**
4550 * xsltCallTemplate:
4551 * @ctxt: a XSLT transformation context
4552 * @node: the "current node" in the source tree
4553 * @inst: the XSLT 'call-template' instruction
4554 * @castedComp: the compiled information of the instruction
4555 *
4556 * Processes the XSLT call-template instruction on the source node.
4557 */
4558void
4559xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
4560 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4561{
4562#ifdef XSLT_REFACTORED
4563 xsltStyleItemCallTemplatePtr comp =
4564 (xsltStyleItemCallTemplatePtr) castedComp;
4565#else
4566 xsltStylePreCompPtr comp = castedComp;
4567#endif
4568 xsltStackElemPtr withParams = NULL;
4569
4570 if (ctxt->insert == NULL)
4571 return;
4572 if (comp == NULL) {
4573 xsltTransformError(ctxt, NULL, inst,
4574 "The XSLT 'call-template' instruction was not compiled.\n");
4575 return;
4576 }
4577
4578 /*
4579 * The template must have been precomputed
4580 */
4581 if (comp->templ == NULL) {
4582 comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4583 if (comp->templ == NULL) {
4584 if (comp->ns != NULL) {
4585 xsltTransformError(ctxt, NULL, inst,
4586 "The called template '{%s}%s' was not found.\n",
4587 comp->ns, comp->name);
4588 } else {
4589 xsltTransformError(ctxt, NULL, inst,
4590 "The called template '%s' was not found.\n",
4591 comp->name);
4592 }
4593 return;
4594 }
4595 }
4596
4597#ifdef WITH_XSLT_DEBUG_PROCESS
4598 if ((comp != NULL) && (comp->name != NULL))
4599 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4600 "call-template: name %s\n", comp->name));
4601#endif
4602
4603 if (inst->children) {
4604 xmlNodePtr cur;
4605 xsltStackElemPtr param;
4606
4607 cur = inst->children;
4608 while (cur != NULL) {
4609#ifdef WITH_DEBUGGER
4610 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4611 xslHandleDebugger(cur, node, comp->templ, ctxt);
4612#endif
4613 if (ctxt->state == XSLT_STATE_STOPPED) break;
4614 /*
4615 * TODO: The "with-param"s could be part of the "call-template"
4616 * structure. Avoid to "search" for params dynamically
4617 * in the XML tree every time.
4618 */
4619 if (IS_XSLT_ELEM(cur)) {
4620 if (IS_XSLT_NAME(cur, "with-param")) {
4621 param = xsltParseStylesheetCallerParam(ctxt, cur);
4622 if (param != NULL) {
4623 param->next = withParams;
4624 withParams = param;
4625 }
4626 } else {
4627 xsltGenericError(xsltGenericErrorContext,
4628 "xsl:call-template: misplaced xsl:%s\n", cur->name);
4629 }
4630 } else {
4631 xsltGenericError(xsltGenericErrorContext,
4632 "xsl:call-template: misplaced %s element\n", cur->name);
4633 }
4634 cur = cur->next;
4635 }
4636 }
4637 /*
4638 * Create a new frame using the params first
4639 */
4640 xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4641 withParams);
4642 if (withParams != NULL)
4643 xsltFreeStackElemList(withParams);
4644
4645#ifdef WITH_XSLT_DEBUG_PROCESS
4646 if ((comp != NULL) && (comp->name != NULL))
4647 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4648 "call-template returned: name %s\n", comp->name));
4649#endif
4650}
4651
4652/**
4653 * xsltApplyTemplates:
4654 * @ctxt: a XSLT transformation context
4655 * @node: the 'current node' in the source tree
4656 * @inst: the element node of an XSLT 'apply-templates' instruction
4657 * @castedComp: the compiled instruction
4658 *
4659 * Processes the XSLT 'apply-templates' instruction on the current node.
4660 */
4661void
4662xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
4663 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4664{
4665#ifdef XSLT_REFACTORED
4666 xsltStyleItemApplyTemplatesPtr comp =
4667 (xsltStyleItemApplyTemplatesPtr) castedComp;
4668#else
4669 xsltStylePreCompPtr comp = castedComp;
4670#endif
4671 int i;
4672 xmlNodePtr cur, delNode = NULL, oldContextNode;
4673 xmlNodeSetPtr list = NULL, oldList;
4674 xsltStackElemPtr withParams = NULL;
4675 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
4676 const xmlChar *oldMode, *oldModeURI;
4677 xmlDocPtr oldXPDoc;
4678 xsltDocumentPtr oldDocInfo;
4679 xmlXPathContextPtr xpctxt;
4680 xmlNsPtr *oldXPNamespaces;
4681
4682 if (comp == NULL) {
4683 xsltTransformError(ctxt, NULL, inst,
4684 "xsl:apply-templates : compilation failed\n");
4685 return;
4686 }
4687 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4688 return;
4689
4690#ifdef WITH_XSLT_DEBUG_PROCESS
4691 if ((node != NULL) && (node->name != NULL))
4692 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4693 "xsltApplyTemplates: node: '%s'\n", node->name));
4694#endif
4695
4696 xpctxt = ctxt->xpathCtxt;
4697 /*
4698 * Save context states.
4699 */
4700 oldContextNode = ctxt->node;
4701 oldMode = ctxt->mode;
4702 oldModeURI = ctxt->modeURI;
4703 oldDocInfo = ctxt->document;
4704 oldList = ctxt->nodeList;
4705
4706 /*
4707 * The xpath context size and proximity position, as
4708 * well as the xpath and context documents, may be changed
4709 * so we save their initial state and will restore on exit
4710 */
4711 oldXPContextSize = xpctxt->contextSize;
4712 oldXPProximityPosition = xpctxt->proximityPosition;
4713 oldXPDoc = xpctxt->doc;
4714 oldXPNsNr = xpctxt->nsNr;
4715 oldXPNamespaces = xpctxt->namespaces;
4716
4717 /*
4718 * Set up contexts.
4719 */
4720 ctxt->mode = comp->mode;
4721 ctxt->modeURI = comp->modeURI;
4722
4723 if (comp->select != NULL) {
4724 xmlXPathObjectPtr res = NULL;
4725
4726 if (comp->comp == NULL) {
4727 xsltTransformError(ctxt, NULL, inst,
4728 "xsl:apply-templates : compilation failed\n");
4729 goto error;
4730 }
4731#ifdef WITH_XSLT_DEBUG_PROCESS
4732 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4733 "xsltApplyTemplates: select %s\n", comp->select));
4734#endif
4735
4736 /*
4737 * Set up XPath.
4738 */
4739 xpctxt->node = node; /* Set the "context node" */
4740#ifdef XSLT_REFACTORED
4741 if (comp->inScopeNs != NULL) {
4742 xpctxt->namespaces = comp->inScopeNs->list;
4743 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4744 } else {
4745 xpctxt->namespaces = NULL;
4746 xpctxt->nsNr = 0;
4747 }
4748#else
4749 xpctxt->namespaces = comp->nsList;
4750 xpctxt->nsNr = comp->nsNr;
4751#endif
4752 res = xmlXPathCompiledEval(comp->comp, xpctxt);
4753
4754 xpctxt->contextSize = oldXPContextSize;
4755 xpctxt->proximityPosition = oldXPProximityPosition;
4756 if (res != NULL) {
4757 if (res->type == XPATH_NODESET) {
4758 list = res->nodesetval; /* consume the node set */
4759 res->nodesetval = NULL;
4760 } else {
4761 xsltTransformError(ctxt, NULL, inst,
4762 "The 'select' expression did not evaluate to a "
4763 "node set.\n");
4764 ctxt->state = XSLT_STATE_STOPPED;
4765 xmlXPathFreeObject(res);
4766 goto error;
4767 }
4768 xmlXPathFreeObject(res);
4769 /*
4770 * Note: An xsl:apply-templates with a 'select' attribute,
4771 * can change the current source doc.
4772 */
4773 } else {
4774 xsltTransformError(ctxt, NULL, inst,
4775 "Failed to evaluate the 'select' expression.\n");
4776 ctxt->state = XSLT_STATE_STOPPED;
4777 goto error;
4778 }
4779 if (list == NULL) {
4780#ifdef WITH_XSLT_DEBUG_PROCESS
4781 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4782 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4783#endif
4784 goto exit;
4785 }
4786 /*
4787 *
4788 * NOTE: Previously a document info (xsltDocument) was
4789 * created and attached to the Result Tree Fragment.
4790 * But such a document info is created on demand in
4791 * xsltKeyFunction() (functions.c), so we need to create
4792 * it here beforehand.
4793 * In order to take care of potential keys we need to
4794 * do some extra work for the case when a Result Tree Fragment
4795 * is converted into a nodeset (e.g. exslt:node-set()) :
4796 * We attach a "pseudo-doc" (xsltDocument) to _private.
4797 * This xsltDocument, together with the keyset, will be freed
4798 * when the Result Tree Fragment is freed.
4799 *
4800 */
4801#if 0
4802 if ((ctxt->nbKeys > 0) &&
4803 (list->nodeNr != 0) &&
4804 (list->nodeTab[0]->doc != NULL) &&
4805 XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
4806 {
4807 /*
4808 * NOTE that it's also OK if @effectiveDocInfo will be
4809 * set to NULL.
4810 */
4811 isRTF = 1;
4812 effectiveDocInfo = list->nodeTab[0]->doc->_private;
4813 }
4814#endif
4815 } else {
4816 /*
4817 * Build an XPath node set with the children
4818 */
4819 list = xmlXPathNodeSetCreate(NULL);
4820 if (list == NULL)
4821 goto error;
4822 cur = node->children;
4823 while (cur != NULL) {
4824 switch (cur->type) {
4825 case XML_TEXT_NODE:
4826 if ((IS_BLANK_NODE(cur)) &&
4827 (cur->parent != NULL) &&
4828 (cur->parent->type == XML_ELEMENT_NODE) &&
4829 (ctxt->style->stripSpaces != NULL)) {
4830 const xmlChar *val;
4831
4832 if (cur->parent->ns != NULL) {
4833 val = (const xmlChar *)
4834 xmlHashLookup2(ctxt->style->stripSpaces,
4835 cur->parent->name,
4836 cur->parent->ns->href);
4837 if (val == NULL) {
4838 val = (const xmlChar *)
4839 xmlHashLookup2(ctxt->style->stripSpaces,
4840 BAD_CAST "*",
4841 cur->parent->ns->href);
4842 }
4843 } else {
4844 val = (const xmlChar *)
4845 xmlHashLookup2(ctxt->style->stripSpaces,
4846 cur->parent->name, NULL);
4847 }
4848 if ((val != NULL) &&
4849 (xmlStrEqual(val, (xmlChar *) "strip"))) {
4850 delNode = cur;
4851 break;
4852 }
4853 }
4854 /* no break on purpose */
4855 case XML_ELEMENT_NODE:
4856 case XML_DOCUMENT_NODE:
4857 case XML_HTML_DOCUMENT_NODE:
4858 case XML_CDATA_SECTION_NODE:
4859 case XML_PI_NODE:
4860 case XML_COMMENT_NODE:
4861 xmlXPathNodeSetAddUnique(list, cur);
4862 break;
4863 case XML_DTD_NODE:
4864 /* Unlink the DTD, it's still reachable
4865 * using doc->intSubset */
4866 if (cur->next != NULL)
4867 cur->next->prev = cur->prev;
4868 if (cur->prev != NULL)
4869 cur->prev->next = cur->next;
4870 break;
4871 default:
4872#ifdef WITH_XSLT_DEBUG_PROCESS
4873 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4874 "xsltApplyTemplates: skipping cur type %d\n",
4875 cur->type));
4876#endif
4877 delNode = cur;
4878 }
4879 cur = cur->next;
4880 if (delNode != NULL) {
4881#ifdef WITH_XSLT_DEBUG_PROCESS
4882 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4883 "xsltApplyTemplates: removing ignorable blank cur\n"));
4884#endif
4885 xmlUnlinkNode(delNode);
4886 xmlFreeNode(delNode);
4887 delNode = NULL;
4888 }
4889 }
4890 }
4891
4892#ifdef WITH_XSLT_DEBUG_PROCESS
4893 if (list != NULL)
4894 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4895 "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
4896#endif
4897
4898 if ((list == NULL) || (list->nodeNr == 0))
4899 goto exit;
4900
4901 /*
4902 * Set the context's node set and size; this is also needed for
4903 * for xsltDoSortFunction().
4904 */
4905 ctxt->nodeList = list;
4906 /*
4907 * Process xsl:with-param and xsl:sort instructions.
4908 * (The code became so verbose just to avoid the
4909 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
4910 * BUG TODO: We are not using namespaced potentially defined on the
4911 * xsl:sort or xsl:with-param elements; XPath expression might fail.
4912 */
4913 if (inst->children) {
4914 xsltStackElemPtr param;
4915
4916 cur = inst->children;
4917 while (cur) {
4918
4919#ifdef WITH_DEBUGGER
4920 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4921 xslHandleDebugger(cur, node, NULL, ctxt);
4922#endif
4923 if (ctxt->state == XSLT_STATE_STOPPED)
4924 break;
4925 if (cur->type == XML_TEXT_NODE) {
4926 cur = cur->next;
4927 continue;
4928 }
4929 if (! IS_XSLT_ELEM(cur))
4930 break;
4931 if (IS_XSLT_NAME(cur, "with-param")) {
4932 param = xsltParseStylesheetCallerParam(ctxt, cur);
4933 if (param != NULL) {
4934 param->next = withParams;
4935 withParams = param;
4936 }
4937 }
4938 if (IS_XSLT_NAME(cur, "sort")) {
4939 xsltTemplatePtr oldCurTempRule =
4940 ctxt->currentTemplateRule;
4941 int nbsorts = 0;
4942 xmlNodePtr sorts[XSLT_MAX_SORT];
4943
4944 sorts[nbsorts++] = cur;
4945
4946 while (cur) {
4947
4948#ifdef WITH_DEBUGGER
4949 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4950 xslHandleDebugger(cur, node, NULL, ctxt);
4951#endif
4952 if (ctxt->state == XSLT_STATE_STOPPED)
4953 break;
4954
4955 if (cur->type == XML_TEXT_NODE) {
4956 cur = cur->next;
4957 continue;
4958 }
4959
4960 if (! IS_XSLT_ELEM(cur))
4961 break;
4962 if (IS_XSLT_NAME(cur, "with-param")) {
4963 param = xsltParseStylesheetCallerParam(ctxt, cur);
4964 if (param != NULL) {
4965 param->next = withParams;
4966 withParams = param;
4967 }
4968 }
4969 if (IS_XSLT_NAME(cur, "sort")) {
4970 if (nbsorts >= XSLT_MAX_SORT) {
4971 xsltTransformError(ctxt, NULL, cur,
4972 "The number (%d) of xsl:sort instructions exceeds the "
4973 "maximum allowed by this processor's settings.\n",
4974 nbsorts);
4975 ctxt->state = XSLT_STATE_STOPPED;
4976 break;
4977 } else {
4978 sorts[nbsorts++] = cur;
4979 }
4980 }
4981 cur = cur->next;
4982 }
4983 /*
4984 * The "current template rule" is cleared for xsl:sort.
4985 */
4986 ctxt->currentTemplateRule = NULL;
4987 /*
4988 * Sort.
4989 */
4990 xsltDoSortFunction(ctxt, sorts, nbsorts);
4991 ctxt->currentTemplateRule = oldCurTempRule;
4992 break;
4993 }
4994 cur = cur->next;
4995 }
4996 }
4997 xpctxt->contextSize = list->nodeNr;
4998 /*
4999 * Apply templates for all selected source nodes.
5000 */
5001 for (i = 0; i < list->nodeNr; i++) {
5002 cur = list->nodeTab[i];
5003 /*
5004 * The node becomes the "current node".
5005 */
5006 ctxt->node = cur;
5007 /*
5008 * An xsl:apply-templates can change the current context doc.
5009 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5010 */
5011 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5012 xpctxt->doc = cur->doc;
5013
5014 xpctxt->proximityPosition = i + 1;
5015 /*
5016 * Find and apply a template for this node.
5017 */
5018 xsltProcessOneNode(ctxt, cur, withParams);
5019 }
5020
5021exit:
5022error:
5023 /*
5024 * Free the parameter list.
5025 */
5026 if (withParams != NULL)
5027 xsltFreeStackElemList(withParams);
5028 if (list != NULL)
5029 xmlXPathFreeNodeSet(list);
5030 /*
5031 * Restore context states.
5032 */
5033 xpctxt->nsNr = oldXPNsNr;
5034 xpctxt->namespaces = oldXPNamespaces;
5035 xpctxt->doc = oldXPDoc;
5036 xpctxt->contextSize = oldXPContextSize;
5037 xpctxt->proximityPosition = oldXPProximityPosition;
5038
5039 ctxt->document = oldDocInfo;
5040 ctxt->nodeList = oldList;
5041 ctxt->node = oldContextNode;
5042 ctxt->mode = oldMode;
5043 ctxt->modeURI = oldModeURI;
5044}
5045
5046
5047/**
5048 * xsltChoose:
5049 * @ctxt: a XSLT process context
5050 * @contextNode: the current node in the source tree
5051 * @inst: the xsl:choose instruction
5052 * @comp: compiled information of the instruction
5053 *
5054 * Processes the xsl:choose instruction on the source node.
5055 */
5056void
5057xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5058 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
5059{
5060 xmlNodePtr cur;
5061
5062 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5063 return;
5064
5065 /*
5066 * TODO: Content model checks should be done only at compilation
5067 * time.
5068 */
5069 cur = inst->children;
5070 if (cur == NULL) {
5071 xsltTransformError(ctxt, NULL, inst,
5072 "xsl:choose: The instruction has no content.\n");
5073 return;
5074 }
5075
5076#ifdef XSLT_REFACTORED
5077 /*
5078 * We don't check the content model during transformation.
5079 */
5080#else
5081 if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
5082 xsltTransformError(ctxt, NULL, inst,
5083 "xsl:choose: xsl:when expected first\n");
5084 return;
5085 }
5086#endif
5087
5088 {
5089 int testRes = 0, res = 0;
5090 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
5091 xmlDocPtr oldXPContextDoc = xpctxt->doc;
5092 int oldXPProximityPosition = xpctxt->proximityPosition;
5093 int oldXPContextSize = xpctxt->contextSize;
5094 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
5095 int oldXPNsNr = xpctxt->nsNr;
5096
5097#ifdef XSLT_REFACTORED
5098 xsltStyleItemWhenPtr wcomp = NULL;
5099#else
5100 xsltStylePreCompPtr wcomp = NULL;
5101#endif
5102
5103 /*
5104 * Process xsl:when ---------------------------------------------------
5105 */
5106 while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
5107 wcomp = cur->psvi;
5108
5109 if ((wcomp == NULL) || (wcomp->test == NULL) ||
5110 (wcomp->comp == NULL))
5111 {
5112 xsltTransformError(ctxt, NULL, cur,
5113 "Internal error in xsltChoose(): "
5114 "The XSLT 'when' instruction was not compiled.\n");
5115 goto error;
5116 }
5117
5118
5119#ifdef WITH_DEBUGGER
5120 if (xslDebugStatus != XSLT_DEBUG_NONE) {
5121 /*
5122 * TODO: Isn't comp->templ always NULL for xsl:choose?
5123 */
5124 xslHandleDebugger(cur, contextNode, NULL, ctxt);
5125 }
5126#endif
5127#ifdef WITH_XSLT_DEBUG_PROCESS
5128 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5129 "xsltChoose: test %s\n", wcomp->test));
5130#endif
5131
5132 xpctxt->node = contextNode;
5133 xpctxt->doc = oldXPContextDoc;
5134 xpctxt->proximityPosition = oldXPProximityPosition;
5135 xpctxt->contextSize = oldXPContextSize;
5136
5137#ifdef XSLT_REFACTORED
5138 if (wcomp->inScopeNs != NULL) {
5139 xpctxt->namespaces = wcomp->inScopeNs->list;
5140 xpctxt->nsNr = wcomp->inScopeNs->xpathNumber;
5141 } else {
5142 xpctxt->namespaces = NULL;
5143 xpctxt->nsNr = 0;
5144 }
5145#else
5146 xpctxt->namespaces = wcomp->nsList;
5147 xpctxt->nsNr = wcomp->nsNr;
5148#endif
5149
5150
5151#ifdef XSLT_FAST_IF
5152 res = xmlXPathCompiledEvalToBoolean(wcomp->comp, xpctxt);
5153
5154 if (res == -1) {
5155 ctxt->state = XSLT_STATE_STOPPED;
5156 goto error;
5157 }
5158 testRes = (res == 1) ? 1 : 0;
5159
5160#else /* XSLT_FAST_IF */
5161
5162 res = xmlXPathCompiledEval(wcomp->comp, xpctxt);
5163
5164 if (res != NULL) {
5165 if (res->type != XPATH_BOOLEAN)
5166 res = xmlXPathConvertBoolean(res);
5167 if (res->type == XPATH_BOOLEAN)
5168 testRes = res->boolval;
5169 else {
5170#ifdef WITH_XSLT_DEBUG_PROCESS
5171 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5172 "xsltChoose: test didn't evaluate to a boolean\n"));
5173#endif
5174 goto error;
5175 }
5176 xmlXPathFreeObject(res);
5177 res = NULL;
5178 } else {
5179 ctxt->state = XSLT_STATE_STOPPED;
5180 goto error;
5181 }
5182
5183#endif /* else of XSLT_FAST_IF */
5184
5185#ifdef WITH_XSLT_DEBUG_PROCESS
5186 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5187 "xsltChoose: test evaluate to %d\n", testRes));
5188#endif
5189 if (testRes)
5190 goto test_is_true;
5191
5192 cur = cur->next;
5193 }
5194
5195 /*
5196 * Process xsl:otherwise ----------------------------------------------
5197 */
5198 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
5199
5200#ifdef WITH_DEBUGGER
5201 if (xslDebugStatus != XSLT_DEBUG_NONE)
5202 xslHandleDebugger(cur, contextNode, NULL, ctxt);
5203#endif
5204
5205#ifdef WITH_XSLT_DEBUG_PROCESS
5206 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5207 "evaluating xsl:otherwise\n"));
5208#endif
5209 goto test_is_true;
5210 }
5211 xpctxt->node = contextNode;
5212 xpctxt->doc = oldXPContextDoc;
5213 xpctxt->proximityPosition = oldXPProximityPosition;
5214 xpctxt->contextSize = oldXPContextSize;
5215 xpctxt->namespaces = oldXPNamespaces;
5216 xpctxt->nsNr = oldXPNsNr;
5217 goto exit;
5218
5219test_is_true:
5220
5221 xpctxt->node = contextNode;
5222 xpctxt->doc = oldXPContextDoc;
5223 xpctxt->proximityPosition = oldXPProximityPosition;
5224 xpctxt->contextSize = oldXPContextSize;
5225 xpctxt->namespaces = oldXPNamespaces;
5226 xpctxt->nsNr = oldXPNsNr;
5227 goto process_sequence;
5228 }
5229
5230process_sequence:
5231
5232 /*
5233 * Instantiate the sequence constructor.
5234 */
5235 xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
5236 NULL);
5237
5238exit:
5239error:
5240 return;
5241}
5242
5243/**
5244 * xsltIf:
5245 * @ctxt: a XSLT process context
5246 * @contextNode: the current node in the source tree
5247 * @inst: the xsl:if instruction
5248 * @castedComp: compiled information of the instruction
5249 *
5250 * Processes the xsl:if instruction on the source node.
5251 */
5252void
5253xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5254 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
5255{
5256 int res = 0;
5257
5258#ifdef XSLT_REFACTORED
5259 xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
5260#else
5261 xsltStylePreCompPtr comp = castedComp;
5262#endif
5263
5264 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5265 return;
5266 if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
5267 xsltTransformError(ctxt, NULL, inst,
5268 "Internal error in xsltIf(): "
5269 "The XSLT 'if' instruction was not compiled.\n");
5270 return;
5271 }
5272
5273#ifdef WITH_XSLT_DEBUG_PROCESS
5274 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5275 "xsltIf: test %s\n", comp->test));
5276#endif
5277
5278#ifdef XSLT_FAST_IF
5279 {
5280 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
5281 xmlDocPtr oldXPContextDoc = xpctxt->doc;
5282 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
5283 xmlNodePtr oldXPContextNode = xpctxt->node;
5284 int oldXPProximityPosition = xpctxt->proximityPosition;
5285 int oldXPContextSize = xpctxt->contextSize;
5286 int oldXPNsNr = xpctxt->nsNr;
5287 xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
5288
5289 xpctxt->node = contextNode;
5290 if (comp != NULL) {
5291
5292#ifdef XSLT_REFACTORED
5293 if (comp->inScopeNs != NULL) {
5294 xpctxt->namespaces = comp->inScopeNs->list;
5295 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
5296 } else {
5297 xpctxt->namespaces = NULL;
5298 xpctxt->nsNr = 0;
5299 }
5300#else
5301 xpctxt->namespaces = comp->nsList;
5302 xpctxt->nsNr = comp->nsNr;
5303#endif
5304 } else {
5305 xpctxt->namespaces = NULL;
5306 xpctxt->nsNr = 0;
5307 }
5308 /*
5309 * This XPath function is optimized for boolean results.
5310 */
5311 res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
5312
5313 /*
5314 * Cleanup fragments created during evaluation of the
5315 * "select" expression.
5316 */
5317 if (oldLocalFragmentTop != ctxt->localRVT)
5318 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
5319
5320 xpctxt->doc = oldXPContextDoc;
5321 xpctxt->node = oldXPContextNode;
5322 xpctxt->contextSize = oldXPContextSize;
5323 xpctxt->proximityPosition = oldXPProximityPosition;
5324 xpctxt->nsNr = oldXPNsNr;
5325 xpctxt->namespaces = oldXPNamespaces;
5326 }
5327
5328#ifdef WITH_XSLT_DEBUG_PROCESS
5329 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5330 "xsltIf: test evaluate to %d\n", res));
5331#endif
5332
5333 if (res == -1) {
5334 ctxt->state = XSLT_STATE_STOPPED;
5335 goto error;
5336 }
5337 if (res == 1) {
5338 /*
5339 * Instantiate the sequence constructor of xsl:if.
5340 */
5341 xsltApplySequenceConstructor(ctxt,
5342 contextNode, inst->children, NULL);
5343 }
5344
5345#else /* XSLT_FAST_IF */
5346 {
5347 xmlXPathObjectPtr xpobj = NULL;
5348 /*
5349 * OLD CODE:
5350 */
5351 {
5352 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
5353 xmlDocPtr oldXPContextDoc = xpctxt->doc;
5354 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
5355 xmlNodePtr oldXPContextNode = xpctxt->node;
5356 int oldXPProximityPosition = xpctxt->proximityPosition;
5357 int oldXPContextSize = xpctxt->contextSize;
5358 int oldXPNsNr = xpctxt->nsNr;
5359
5360 xpctxt->node = contextNode;
5361 if (comp != NULL) {
5362
5363#ifdef XSLT_REFACTORED
5364 if (comp->inScopeNs != NULL) {
5365 xpctxt->namespaces = comp->inScopeNs->list;
5366 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
5367 } else {
5368 xpctxt->namespaces = NULL;
5369 xpctxt->nsNr = 0;
5370 }
5371#else
5372 xpctxt->namespaces = comp->nsList;
5373 xpctxt->nsNr = comp->nsNr;
5374#endif
5375 } else {
5376 xpctxt->namespaces = NULL;
5377 xpctxt->nsNr = 0;
5378 }
5379
5380 /*
5381 * This XPath function is optimized for boolean results.
5382 */
5383 xpobj = xmlXPathCompiledEval(comp->comp, xpctxt);
5384
5385 xpctxt->doc = oldXPContextDoc;
5386 xpctxt->node = oldXPContextNode;
5387 xpctxt->contextSize = oldXPContextSize;
5388 xpctxt->proximityPosition = oldXPProximityPosition;
5389 xpctxt->nsNr = oldXPNsNr;
5390 xpctxt->namespaces = oldXPNamespaces;
5391 }
5392 if (xpobj != NULL) {
5393 if (xpobj->type != XPATH_BOOLEAN)
5394 xpobj = xmlXPathConvertBoolean(xpobj);
5395 if (xpobj->type == XPATH_BOOLEAN) {
5396 res = xpobj->boolval;
5397
5398#ifdef WITH_XSLT_DEBUG_PROCESS
5399 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5400 "xsltIf: test evaluate to %d\n", res));
5401#endif
5402 if (res) {
5403 xsltApplySequenceConstructor(ctxt,
5404 contextNode, inst->children, NULL);
5405 }
5406 } else {
5407
5408#ifdef WITH_XSLT_DEBUG_PROCESS
5409 XSLT_TRACE(ctxt, XSLT_TRACE_IF,
5410 xsltGenericDebug(xsltGenericDebugContext,
5411 "xsltIf: test didn't evaluate to a boolean\n"));
5412#endif
5413 ctxt->state = XSLT_STATE_STOPPED;
5414 }
5415 xmlXPathFreeObject(xpobj);
5416 } else {
5417 ctxt->state = XSLT_STATE_STOPPED;
5418 }
5419 }
5420#endif /* else of XSLT_FAST_IF */
5421
5422error:
5423 return;
5424}
5425
5426/**
5427 * xsltForEach:
5428 * @ctxt: an XSLT transformation context
5429 * @contextNode: the "current node" in the source tree
5430 * @inst: the element node of the xsl:for-each instruction
5431 * @castedComp: the compiled information of the instruction
5432 *
5433 * Process the xslt for-each node on the source node
5434 */
5435void
5436xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5437 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
5438{
5439#ifdef XSLT_REFACTORED
5440 xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
5441#else
5442 xsltStylePreCompPtr comp = castedComp;
5443#endif
5444 int i;
5445 xmlXPathObjectPtr res = NULL;
5446 xmlNodePtr cur, curInst;
5447 xmlNodeSetPtr list = NULL;
5448 xmlNodeSetPtr oldList;
5449 int oldXPProximityPosition, oldXPContextSize;
5450 xmlNodePtr oldContextNode;
5451 xsltTemplatePtr oldCurTemplRule;
5452 xmlDocPtr oldXPDoc;
5453 xsltDocumentPtr oldDocInfo;
5454 xmlXPathContextPtr xpctxt;
5455
5456 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
5457 xsltGenericError(xsltGenericErrorContext,
5458 "xsltForEach(): Bad arguments.\n");
5459 return;
5460 }
5461
5462 if (comp == NULL) {
5463 xsltTransformError(ctxt, NULL, inst,
5464 "Internal error in xsltForEach(): "
5465 "The XSLT 'for-each' instruction was not compiled.\n");
5466 return;
5467 }
5468 if ((comp->select == NULL) || (comp->comp == NULL)) {
5469 xsltTransformError(ctxt, NULL, inst,
5470 "Internal error in xsltForEach(): "
5471 "The selecting expression of the XSLT 'for-each' "
5472 "instruction was not compiled correctly.\n");
5473 return;
5474 }
5475 xpctxt = ctxt->xpathCtxt;
5476
5477#ifdef WITH_XSLT_DEBUG_PROCESS
5478 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5479 "xsltForEach: select %s\n", comp->select));
5480#endif
5481
5482 /*
5483 * Save context states.
5484 */
5485 oldDocInfo = ctxt->document;
5486 oldList = ctxt->nodeList;
5487 oldContextNode = ctxt->node;
5488 /*
5489 * The "current template rule" is cleared for the instantiation of
5490 * xsl:for-each.
5491 */
5492 oldCurTemplRule = ctxt->currentTemplateRule;
5493 ctxt->currentTemplateRule = NULL;
5494
5495 oldXPDoc = xpctxt->doc;
5496 oldXPProximityPosition = xpctxt->proximityPosition;
5497 oldXPContextSize = xpctxt->contextSize;
5498 /*
5499 * Set up XPath.
5500 */
5501 xpctxt->node = contextNode;
5502#ifdef XSLT_REFACTORED
5503 if (comp->inScopeNs != NULL) {
5504 xpctxt->namespaces = comp->inScopeNs->list;
5505 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
5506 } else {
5507 xpctxt->namespaces = NULL;
5508 xpctxt->nsNr = 0;
5509 }
5510#else
5511 xpctxt->namespaces = comp->nsList;
5512 xpctxt->nsNr = comp->nsNr;
5513#endif
5514
5515 /*
5516 * Evaluate the 'select' expression.
5517 */
5518 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
5519
5520 if (res != NULL) {
5521 if (res->type == XPATH_NODESET)
5522 list = res->nodesetval;
5523 else {
5524 xsltTransformError(ctxt, NULL, inst,
5525 "The 'select' expression does not evaluate to a node set.\n");
5526
5527#ifdef WITH_XSLT_DEBUG_PROCESS
5528 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5529 "xsltForEach: select didn't evaluate to a node list\n"));
5530#endif
5531 goto error;
5532 }
5533 } else {
5534 xsltTransformError(ctxt, NULL, inst,
5535 "Failed to evaluate the 'select' expression.\n");
5536 ctxt->state = XSLT_STATE_STOPPED;
5537 goto error;
5538 }
5539
5540 if ((list == NULL) || (list->nodeNr <= 0))
5541 goto exit;
5542
5543#ifdef WITH_XSLT_DEBUG_PROCESS
5544 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5545 "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
5546#endif
5547
5548 /*
5549 * Restore XPath states for the "current node".
5550 */
5551 xpctxt->contextSize = oldXPContextSize;
5552 xpctxt->proximityPosition = oldXPProximityPosition;
5553 xpctxt->node = contextNode;
5554
5555 /*
5556 * Set the list; this has to be done already here for xsltDoSortFunction().
5557 */
5558 ctxt->nodeList = list;
5559 /*
5560 * Handle xsl:sort instructions and skip them for further processing.
5561 * BUG TODO: We are not using namespaced potentially defined on the
5562 * xsl:sort element; XPath expression might fail.
5563 */
5564 curInst = inst->children;
5565 if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5566 int nbsorts = 0;
5567 xmlNodePtr sorts[XSLT_MAX_SORT];
5568
5569 sorts[nbsorts++] = curInst;
5570
5571#ifdef WITH_DEBUGGER
5572 if (xslDebugStatus != XSLT_DEBUG_NONE)
5573 xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5574#endif
5575
5576 curInst = curInst->next;
5577 while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5578 if (nbsorts >= XSLT_MAX_SORT) {
5579 xsltTransformError(ctxt, NULL, curInst,
5580 "The number of xsl:sort instructions exceeds the "
5581 "maximum (%d) allowed by this processor.\n",
5582 XSLT_MAX_SORT);
5583 goto error;
5584 } else {
5585 sorts[nbsorts++] = curInst;
5586 }
5587
5588#ifdef WITH_DEBUGGER
5589 if (xslDebugStatus != XSLT_DEBUG_NONE)
5590 xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5591#endif
5592 curInst = curInst->next;
5593 }
5594 xsltDoSortFunction(ctxt, sorts, nbsorts);
5595 }
5596 xpctxt->contextSize = list->nodeNr;
5597 /*
5598 * Instantiate the sequence constructor for each selected node.
5599 */
5600 for (i = 0; i < list->nodeNr; i++) {
5601 cur = list->nodeTab[i];
5602 /*
5603 * The selected node becomes the "current node".
5604 */
5605 ctxt->node = cur;
5606 /*
5607 * An xsl:for-each can change the current context doc.
5608 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5609 */
5610 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5611 xpctxt->doc = cur->doc;
5612
5613 xpctxt->proximityPosition = i + 1;
5614
5615 xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
5616 }
5617
5618exit:
5619error:
5620 if (res != NULL)
5621 xmlXPathFreeObject(res);
5622 /*
5623 * Restore old states.
5624 */
5625 ctxt->document = oldDocInfo;
5626 ctxt->nodeList = oldList;
5627 ctxt->node = oldContextNode;
5628 ctxt->currentTemplateRule = oldCurTemplRule;
5629
5630 xpctxt->doc = oldXPDoc;
5631 xpctxt->contextSize = oldXPContextSize;
5632 xpctxt->proximityPosition = oldXPProximityPosition;
5633}
5634
5635/************************************************************************
5636 * *
5637 * Generic interface *
5638 * *
5639 ************************************************************************/
5640
5641#ifdef XSLT_GENERATE_HTML_DOCTYPE
5642typedef struct xsltHTMLVersion {
5643 const char *version;
5644 const char *public;
5645 const char *system;
5646} xsltHTMLVersion;
5647
5648static xsltHTMLVersion xsltHTMLVersions[] = {
5649 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5650 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5651 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5652 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5653 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5654 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5655 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5656 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5657 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5658 "http://www.w3.org/TR/html4/strict.dtd"},
5659 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5660 "http://www.w3.org/TR/html4/loose.dtd"},
5661 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5662 "http://www.w3.org/TR/html4/frameset.dtd"},
5663 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5664 "http://www.w3.org/TR/html4/loose.dtd"},
5665 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
5666};
5667
5668/**
5669 * xsltGetHTMLIDs:
5670 * @version: the version string
5671 * @publicID: used to return the public ID
5672 * @systemID: used to return the system ID
5673 *
5674 * Returns -1 if not found, 0 otherwise and the system and public
5675 * Identifier for this given verion of HTML
5676 */
5677static int
5678xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
5679 const xmlChar **systemID) {
5680 unsigned int i;
5681 if (version == NULL)
5682 return(-1);
5683 for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
5684 i++) {
5685 if (!xmlStrcasecmp(version,
5686 (const xmlChar *) xsltHTMLVersions[i].version)) {
5687 if (publicID != NULL)
5688 *publicID = (const xmlChar *) xsltHTMLVersions[i].public;
5689 if (systemID != NULL)
5690 *systemID = (const xmlChar *) xsltHTMLVersions[i].system;
5691 return(0);
5692 }
5693 }
5694 return(-1);
5695}
5696#endif
5697
5698/**
5699 * xsltApplyStripSpaces:
5700 * @ctxt: a XSLT process context
5701 * @node: the root of the XML tree
5702 *
5703 * Strip the unwanted ignorable spaces from the input tree
5704 */
5705void
5706xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
5707 xmlNodePtr current;
5708#ifdef WITH_XSLT_DEBUG_PROCESS
5709 int nb = 0;
5710#endif
5711
5712
5713 current = node;
5714 while (current != NULL) {
5715 /*
5716 * Cleanup children empty nodes if asked for
5717 */
5718 if ((IS_XSLT_REAL_NODE(current)) &&
5719 (current->children != NULL) &&
5720 (xsltFindElemSpaceHandling(ctxt, current))) {
5721 xmlNodePtr delete = NULL, cur = current->children;
5722
5723 while (cur != NULL) {
5724 if (IS_BLANK_NODE(cur))
5725 delete = cur;
5726
5727 cur = cur->next;
5728 if (delete != NULL) {
5729 xmlUnlinkNode(delete);
5730 xmlFreeNode(delete);
5731 delete = NULL;
5732#ifdef WITH_XSLT_DEBUG_PROCESS
5733 nb++;
5734#endif
5735 }
5736 }
5737 }
5738
5739 /*
5740 * Skip to next node in document order.
5741 */
5742 if (node->type == XML_ENTITY_REF_NODE) {
5743 /* process deep in entities */
5744 xsltApplyStripSpaces(ctxt, node->children);
5745 }
5746 if ((current->children != NULL) &&
5747 (current->type != XML_ENTITY_REF_NODE)) {
5748 current = current->children;
5749 } else if (current->next != NULL) {
5750 current = current->next;
5751 } else {
5752 do {
5753 current = current->parent;
5754 if (current == NULL)
5755 break;
5756 if (current == node)
5757 goto done;
5758 if (current->next != NULL) {
5759 current = current->next;
5760 break;
5761 }
5762 } while (current != NULL);
5763 }
5764 }
5765
5766done:
5767#ifdef WITH_XSLT_DEBUG_PROCESS
5768 XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
5769 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
5770#endif
5771 return;
5772}
5773
5774#ifdef XSLT_REFACTORED_KEYCOMP
5775static int
5776xsltCountKeys(xsltTransformContextPtr ctxt)
5777{
5778 xsltStylesheetPtr style;
5779 xsltKeyDefPtr keyd;
5780
5781 if (ctxt == NULL)
5782 return(-1);
5783
5784 /*
5785 * Do we have those nastly templates with a key() in the match pattern?
5786 */
5787 ctxt->hasTemplKeyPatterns = 0;
5788 style = ctxt->style;
5789 while (style != NULL) {
5790 if (style->keyMatch != NULL) {
5791 ctxt->hasTemplKeyPatterns = 1;
5792 break;
5793 }
5794 style = xsltNextImport(style);
5795 }
5796 /*
5797 * Count number of key declarations.
5798 */
5799 ctxt->nbKeys = 0;
5800 style = ctxt->style;
5801 while (style != NULL) {
5802 keyd = style->keys;
5803 while (keyd) {
5804 ctxt->nbKeys++;
5805 keyd = keyd->next;
5806 }
5807 style = xsltNextImport(style);
5808 }
5809 return(ctxt->nbKeys);
5810}
5811#endif /* XSLT_REFACTORED_KEYCOMP */
5812
5813/**
5814 * xsltApplyStylesheetInternal:
5815 * @style: a parsed XSLT stylesheet
5816 * @doc: a parsed XML document
5817 * @params: a NULL terminated array of parameters names/values tuples
5818 * @output: the targetted output
5819 * @profile: profile FILE * output or NULL
5820 * @user: user provided parameter
5821 *
5822 * Apply the stylesheet to the document
5823 * NOTE: This may lead to a non-wellformed output XML wise !
5824 *
5825 * Returns the result document or NULL in case of error
5826 */
5827static xmlDocPtr
5828xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
5829 const char **params, const char *output,
5830 FILE * profile, xsltTransformContextPtr userCtxt)
5831{
5832 xmlDocPtr res = NULL;
5833 xsltTransformContextPtr ctxt = NULL;
5834 xmlNodePtr root, node;
5835 const xmlChar *method;
5836 const xmlChar *doctypePublic;
5837 const xmlChar *doctypeSystem;
5838 const xmlChar *version;
5839 xsltStackElemPtr variables;
5840 xsltStackElemPtr vptr;
5841
5842 if ((style == NULL) || (doc == NULL))
5843 return (NULL);
5844
5845 if (style->internalized == 0) {
5846#ifdef WITH_XSLT_DEBUG
5847 xsltGenericDebug(xsltGenericDebugContext,
5848 "Stylesheet was not fully internalized !\n");
5849#endif
5850 }
5851 if (doc->intSubset != NULL) {
5852 /*
5853 * Avoid hitting the DTD when scanning nodes
5854 * but keep it linked as doc->intSubset
5855 */
5856 xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
5857 if (cur->next != NULL)
5858 cur->next->prev = cur->prev;
5859 if (cur->prev != NULL)
5860 cur->prev->next = cur->next;
5861 if (doc->children == cur)
5862 doc->children = cur->next;
5863 if (doc->last == cur)
5864 doc->last = cur->prev;
5865 cur->prev = cur->next = NULL;
5866 }
5867
5868 /*
5869 * Check for XPath document order availability
5870 */
5871 root = xmlDocGetRootElement(doc);
5872 if (root != NULL) {
5873 if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE))
5874 xmlXPathOrderDocElems(doc);
5875 }
5876
5877 if (userCtxt != NULL)
5878 ctxt = userCtxt;
5879 else
5880 ctxt = xsltNewTransformContext(style, doc);
5881
5882 if (ctxt == NULL)
5883 return (NULL);
5884
5885 ctxt->initialContextDoc = doc;
5886 ctxt->initialContextNode = (xmlNodePtr) doc;
5887
5888 if (profile != NULL)
5889 ctxt->profile = 1;
5890
5891 if (output != NULL)
5892 ctxt->outputFile = output;
5893 else
5894 ctxt->outputFile = NULL;
5895
5896 /*
5897 * internalize the modes if needed
5898 */
5899 if (ctxt->dict != NULL) {
5900 if (ctxt->mode != NULL)
5901 ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
5902 if (ctxt->modeURI != NULL)
5903 ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
5904 }
5905
5906 XSLT_GET_IMPORT_PTR(method, style, method)
5907 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
5908 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
5909 XSLT_GET_IMPORT_PTR(version, style, version)
5910
5911 if ((method != NULL) &&
5912 (!xmlStrEqual(method, (const xmlChar *) "xml")))
5913 {
5914 if (xmlStrEqual(method, (const xmlChar *) "html")) {
5915 ctxt->type = XSLT_OUTPUT_HTML;
5916 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
5917 res = htmlNewDoc(doctypeSystem, doctypePublic);
5918 } else {
5919 if (version == NULL) {
5920 xmlDtdPtr dtd;
5921
5922 res = htmlNewDoc(NULL, NULL);
5923 /*
5924 * Make sure no DTD node is generated in this case
5925 */
5926 if (res != NULL) {
5927 dtd = xmlGetIntSubset(res);
5928 if (dtd != NULL) {
5929 xmlUnlinkNode((xmlNodePtr) dtd);
5930 xmlFreeDtd(dtd);
5931 }
5932 res->intSubset = NULL;
5933 res->extSubset = NULL;
5934 }
5935 } else {
5936
5937#ifdef XSLT_GENERATE_HTML_DOCTYPE
5938 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
5939#endif
5940 res = htmlNewDoc(doctypeSystem, doctypePublic);
5941 }
5942 }
5943 if (res == NULL)
5944 goto error;
5945 res->dict = ctxt->dict;
5946 xmlDictReference(res->dict);
5947
5948#ifdef WITH_XSLT_DEBUG
5949 xsltGenericDebug(xsltGenericDebugContext,
5950 "reusing transformation dict for output\n");
5951#endif
5952 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
5953 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5954 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n",
5955 style->method);
5956 ctxt->type = XSLT_OUTPUT_HTML;
5957 res = htmlNewDoc(doctypeSystem, doctypePublic);
5958 if (res == NULL)
5959 goto error;
5960 res->dict = ctxt->dict;
5961 xmlDictReference(res->dict);
5962
5963#ifdef WITH_XSLT_DEBUG
5964 xsltGenericDebug(xsltGenericDebugContext,
5965 "reusing transformation dict for output\n");
5966#endif
5967 } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
5968 ctxt->type = XSLT_OUTPUT_TEXT;
5969 res = xmlNewDoc(style->version);
5970 if (res == NULL)
5971 goto error;
5972 res->dict = ctxt->dict;
5973 xmlDictReference(res->dict);
5974
5975#ifdef WITH_XSLT_DEBUG
5976 xsltGenericDebug(xsltGenericDebugContext,
5977 "reusing transformation dict for output\n");
5978#endif
5979 } else {
5980 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5981 "xsltApplyStylesheetInternal: unsupported method %s\n",
5982 style->method);
5983 goto error;
5984 }
5985 } else {
5986 ctxt->type = XSLT_OUTPUT_XML;
5987 res = xmlNewDoc(style->version);
5988 if (res == NULL)
5989 goto error;
5990 res->dict = ctxt->dict;
5991 xmlDictReference(ctxt->dict);
5992#ifdef WITH_XSLT_DEBUG
5993 xsltGenericDebug(xsltGenericDebugContext,
5994 "reusing transformation dict for output\n");
5995#endif
5996 }
5997 res->charset = XML_CHAR_ENCODING_UTF8;
5998 if (style->encoding != NULL)
5999 res->encoding = xmlStrdup(style->encoding);
6000 variables = style->variables;
6001
6002 /*
6003 * Start the evaluation, evaluate the params, the stylesheets globals
6004 * and start by processing the top node.
6005 */
6006 if (xsltNeedElemSpaceHandling(ctxt))
6007 xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
6008 /*
6009 * Evaluate global params and user-provided params.
6010 */
6011 ctxt->node = (xmlNodePtr) doc;
6012 if (ctxt->globalVars == NULL)
6013 ctxt->globalVars = xmlHashCreate(20);
6014 if (params != NULL) {
6015 xsltEvalUserParams(ctxt, params);
6016 }
6017 xsltEvalGlobalVariables(ctxt);
6018
6019#ifdef XSLT_REFACTORED_KEYCOMP
6020 xsltCountKeys(ctxt);
6021#endif
6022
6023 ctxt->node = (xmlNodePtr) doc;
6024 ctxt->output = res;
6025 ctxt->insert = (xmlNodePtr) res;
6026 ctxt->varsBase = ctxt->varsNr - 1;
6027
6028 ctxt->xpathCtxt->contextSize = 1;
6029 ctxt->xpathCtxt->proximityPosition = 1;
6030 ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
6031 /*
6032 * Start processing the source tree -----------------------------------
6033 */
6034 xsltProcessOneNode(ctxt, ctxt->node, NULL);
6035 /*
6036 * Remove all remaining vars from the stack.
6037 */
6038 xsltLocalVariablePop(ctxt, 0, -2);
6039 xsltShutdownCtxtExts(ctxt);
6040
6041 xsltCleanupTemplates(style); /* TODO: <- style should be read only */
6042
6043 /*
6044 * Now cleanup our variables so stylesheet can be re-used
6045 *
6046 * TODO: this is not needed anymore global variables are copied
6047 * and not evaluated directly anymore, keep this as a check
6048 */
6049 if (style->variables != variables) {
6050 vptr = style->variables;
6051 while (vptr->next != variables)
6052 vptr = vptr->next;
6053 vptr->next = NULL;
6054 xsltFreeStackElemList(style->variables);
6055 style->variables = variables;
6056 }
6057 vptr = style->variables;
6058 while (vptr != NULL) {
6059 if (vptr->computed) {
6060 if (vptr->value != NULL) {
6061 xmlXPathFreeObject(vptr->value);
6062 vptr->value = NULL;
6063 vptr->computed = 0;
6064 }
6065 }
6066 vptr = vptr->next;
6067 }
6068#if 0
6069 /*
6070 * code disabled by wmb; awaiting kb's review
6071 * problem is that global variable(s) may contain xpath objects
6072 * from doc associated with RVT, so can't be freed at this point.
6073 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6074 * I assume this shouldn't be required at this point.
6075 */
6076 /*
6077 * Free all remaining tree fragments.
6078 */
6079 xsltFreeRVTs(ctxt);
6080#endif
6081 /*
6082 * Do some post processing work depending on the generated output
6083 */
6084 root = xmlDocGetRootElement(res);
6085 if (root != NULL) {
6086 const xmlChar *doctype = NULL;
6087
6088 if ((root->ns != NULL) && (root->ns->prefix != NULL))
6089 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
6090 if (doctype == NULL)
6091 doctype = root->name;
6092
6093 /*
6094 * Apply the default selection of the method
6095 */
6096 if ((method == NULL) &&
6097 (root->ns == NULL) &&
6098 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
6099 xmlNodePtr tmp;
6100
6101 tmp = res->children;
6102 while ((tmp != NULL) && (tmp != root)) {
6103 if (tmp->type == XML_ELEMENT_NODE)
6104 break;
6105 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
6106 break;
6107 tmp = tmp->next;
6108 }
6109 if (tmp == root) {
6110 ctxt->type = XSLT_OUTPUT_HTML;
6111 /*
6112 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6113 * transformation on the doc, but functions like
6114 */
6115 res->type = XML_HTML_DOCUMENT_NODE;
6116 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6117 res->intSubset = xmlCreateIntSubset(res, doctype,
6118 doctypePublic,
6119 doctypeSystem);
6120#ifdef XSLT_GENERATE_HTML_DOCTYPE
6121 } else if (version != NULL) {
6122 xsltGetHTMLIDs(version, &doctypePublic,
6123 &doctypeSystem);
6124 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
6125 res->intSubset =
6126 xmlCreateIntSubset(res, doctype,
6127 doctypePublic,
6128 doctypeSystem);
6129#endif
6130 }
6131 }
6132
6133 }
6134 if (ctxt->type == XSLT_OUTPUT_XML) {
6135 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
6136 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
6137 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6138 xmlNodePtr last;
6139 /* Need a small "hack" here to assure DTD comes before
6140 possible comment nodes */
6141 node = res->children;
6142 last = res->last;
6143 res->children = NULL;
6144 res->last = NULL;
6145 res->intSubset = xmlCreateIntSubset(res, doctype,
6146 doctypePublic,
6147 doctypeSystem);
6148 if (res->children != NULL) {
6149 res->children->next = node;
6150 node->prev = res->children;
6151 res->last = last;
6152 } else {
6153 res->children = node;
6154 res->last = last;
6155 }
6156 }
6157 }
6158 }
6159 xmlXPathFreeNodeSet(ctxt->nodeList);
6160 if (profile != NULL) {
6161 xsltSaveProfiling(ctxt, profile);
6162 }
6163
6164 /*
6165 * Be pedantic.
6166 */
6167 if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) {
6168 xmlFreeDoc(res);
6169 res = NULL;
6170 }
6171 if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
6172 int ret;
6173
6174 ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
6175 if (ret == 0) {
6176 xsltTransformError(ctxt, NULL, NULL,
6177 "xsltApplyStylesheet: forbidden to save to %s\n",
6178 output);
6179 } else if (ret < 0) {
6180 xsltTransformError(ctxt, NULL, NULL,
6181 "xsltApplyStylesheet: saving to %s may not be possible\n",
6182 output);
6183 }
6184 }
6185
6186#ifdef XSLT_DEBUG_PROFILE_CACHE
6187 printf("# Cache:\n");
6188 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6189 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);
6190#endif
6191
6192 if ((ctxt != NULL) && (userCtxt == NULL))
6193 xsltFreeTransformContext(ctxt);
6194
6195 return (res);
6196
6197error:
6198 if (res != NULL)
6199 xmlFreeDoc(res);
6200
6201#ifdef XSLT_DEBUG_PROFILE_CACHE
6202 printf("# Cache:\n");
6203 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6204 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);
6205#endif
6206
6207 if ((ctxt != NULL) && (userCtxt == NULL))
6208 xsltFreeTransformContext(ctxt);
6209 return (NULL);
6210}
6211
6212/**
6213 * xsltApplyStylesheet:
6214 * @style: a parsed XSLT stylesheet
6215 * @doc: a parsed XML document
6216 * @params: a NULL terminated arry of parameters names/values tuples
6217 *
6218 * Apply the stylesheet to the document
6219 * NOTE: This may lead to a non-wellformed output XML wise !
6220 *
6221 * Returns the result document or NULL in case of error
6222 */
6223xmlDocPtr
6224xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6225 const char **params)
6226{
6227 return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
6228}
6229
6230/**
6231 * xsltProfileStylesheet:
6232 * @style: a parsed XSLT stylesheet
6233 * @doc: a parsed XML document
6234 * @params: a NULL terminated arry of parameters names/values tuples
6235 * @output: a FILE * for the profiling output
6236 *
6237 * Apply the stylesheet to the document and dump the profiling to
6238 * the given output.
6239 *
6240 * Returns the result document or NULL in case of error
6241 */
6242xmlDocPtr
6243xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6244 const char **params, FILE * output)
6245{
6246 xmlDocPtr res;
6247
6248 res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
6249 return (res);
6250}
6251
6252/**
6253 * xsltApplyStylesheetUser:
6254 * @style: a parsed XSLT stylesheet
6255 * @doc: a parsed XML document
6256 * @params: a NULL terminated array of parameters names/values tuples
6257 * @output: the targetted output
6258 * @profile: profile FILE * output or NULL
6259 * @userCtxt: user provided transform context
6260 *
6261 * Apply the stylesheet to the document and allow the user to provide
6262 * its own transformation context.
6263 *
6264 * Returns the result document or NULL in case of error
6265 */
6266xmlDocPtr
6267xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6268 const char **params, const char *output,
6269 FILE * profile, xsltTransformContextPtr userCtxt)
6270{
6271 xmlDocPtr res;
6272
6273 res = xsltApplyStylesheetInternal(style, doc, params, output,
6274 profile, userCtxt);
6275 return (res);
6276}
6277
6278/**
6279 * xsltRunStylesheetUser:
6280 * @style: a parsed XSLT stylesheet
6281 * @doc: a parsed XML document
6282 * @params: a NULL terminated array of parameters names/values tuples
6283 * @output: the URL/filename ot the generated resource if available
6284 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6285 * @IObuf: an output buffer for progressive output (not implemented yet)
6286 * @profile: profile FILE * output or NULL
6287 * @userCtxt: user provided transform context
6288 *
6289 * Apply the stylesheet to the document and generate the output according
6290 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6291 *
6292 * NOTE: This may lead to a non-wellformed output XML wise !
6293 * NOTE: This may also result in multiple files being generated
6294 * NOTE: using IObuf, the result encoding used will be the one used for
6295 * creating the output buffer, use the following macro to read it
6296 * from the stylesheet
6297 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6298 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6299 * since the interface uses only UTF8
6300 *
6301 * Returns the number of by written to the main resource or -1 in case of
6302 * error.
6303 */
6304int
6305xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6306 const char **params, const char *output,
6307 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
6308 FILE * profile, xsltTransformContextPtr userCtxt)
6309{
6310 xmlDocPtr tmp;
6311 int ret;
6312
6313 if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
6314 return (-1);
6315 if ((SAX != NULL) && (IObuf != NULL))
6316 return (-1);
6317
6318 /* unsupported yet */
6319 if (SAX != NULL) {
6320 XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6321 return (-1);
6322 }
6323
6324 tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
6325 userCtxt);
6326 if (tmp == NULL) {
6327 xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
6328 "xsltRunStylesheet : run failed\n");
6329 return (-1);
6330 }
6331 if (IObuf != NULL) {
6332 /* TODO: incomplete, IObuf output not progressive */
6333 ret = xsltSaveResultTo(IObuf, tmp, style);
6334 } else {
6335 ret = xsltSaveResultToFilename(output, tmp, style, 0);
6336 }
6337 xmlFreeDoc(tmp);
6338 return (ret);
6339}
6340
6341/**
6342 * xsltRunStylesheet:
6343 * @style: a parsed XSLT stylesheet
6344 * @doc: a parsed XML document
6345 * @params: a NULL terminated array of parameters names/values tuples
6346 * @output: the URL/filename ot the generated resource if available
6347 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6348 * @IObuf: an output buffer for progressive output (not implemented yet)
6349 *
6350 * Apply the stylesheet to the document and generate the output according
6351 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6352 *
6353 * NOTE: This may lead to a non-wellformed output XML wise !
6354 * NOTE: This may also result in multiple files being generated
6355 * NOTE: using IObuf, the result encoding used will be the one used for
6356 * creating the output buffer, use the following macro to read it
6357 * from the stylesheet
6358 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6359 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6360 * since the interface uses only UTF8
6361 *
6362 * Returns the number of bytes written to the main resource or -1 in case of
6363 * error.
6364 */
6365int
6366xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6367 const char **params, const char *output,
6368 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
6369{
6370 return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
6371 NULL, NULL));
6372}
6373
6374/**
6375 * xsltRegisterAllElement:
6376 * @ctxt: the XPath context
6377 *
6378 * Registers all default XSLT elements in this context
6379 */
6380void
6381xsltRegisterAllElement(xsltTransformContextPtr ctxt)
6382{
6383 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
6384 XSLT_NAMESPACE,
6385 (xsltTransformFunction) xsltApplyTemplates);
6386 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
6387 XSLT_NAMESPACE,
6388 (xsltTransformFunction) xsltApplyImports);
6389 xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
6390 XSLT_NAMESPACE,
6391 (xsltTransformFunction) xsltCallTemplate);
6392 xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
6393 XSLT_NAMESPACE,
6394 (xsltTransformFunction) xsltElement);
6395 xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
6396 XSLT_NAMESPACE,
6397 (xsltTransformFunction) xsltAttribute);
6398 xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
6399 XSLT_NAMESPACE,
6400 (xsltTransformFunction) xsltText);
6401 xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
6402 XSLT_NAMESPACE,
6403 (xsltTransformFunction) xsltProcessingInstruction);
6404 xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
6405 XSLT_NAMESPACE,
6406 (xsltTransformFunction) xsltComment);
6407 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
6408 XSLT_NAMESPACE,
6409 (xsltTransformFunction) xsltCopy);
6410 xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
6411 XSLT_NAMESPACE,
6412 (xsltTransformFunction) xsltValueOf);
6413 xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
6414 XSLT_NAMESPACE,
6415 (xsltTransformFunction) xsltNumber);
6416 xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
6417 XSLT_NAMESPACE,
6418 (xsltTransformFunction) xsltForEach);
6419 xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
6420 XSLT_NAMESPACE,
6421 (xsltTransformFunction) xsltIf);
6422 xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
6423 XSLT_NAMESPACE,
6424 (xsltTransformFunction) xsltChoose);
6425 xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
6426 XSLT_NAMESPACE,
6427 (xsltTransformFunction) xsltSort);
6428 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
6429 XSLT_NAMESPACE,
6430 (xsltTransformFunction) xsltCopyOf);
6431 xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
6432 XSLT_NAMESPACE,
6433 (xsltTransformFunction) xsltMessage);
6434
6435 /*
6436 * Those don't have callable entry points but are registered anyway
6437 */
6438 xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
6439 XSLT_NAMESPACE,
6440 (xsltTransformFunction) xsltDebug);
6441 xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
6442 XSLT_NAMESPACE,
6443 (xsltTransformFunction) xsltDebug);
6444 xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
6445 XSLT_NAMESPACE,
6446 (xsltTransformFunction) xsltDebug);
6447 xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
6448 XSLT_NAMESPACE,
6449 (xsltTransformFunction) xsltDebug);
6450 xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
6451 XSLT_NAMESPACE,
6452 (xsltTransformFunction) xsltDebug);
6453 xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
6454 XSLT_NAMESPACE,
6455 (xsltTransformFunction) xsltDebug);
6456 xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
6457 XSLT_NAMESPACE,
6458 (xsltTransformFunction) xsltDebug);
6459
6460}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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