ReactOS 0.4.15-dev-5666-gc548b97
transform.c
Go to the documentation of this file.
1/*
2 * transform.c: Implementation of the XSL Transformation 1.0 engine
3 * transform part, i.e. applying a Stylesheet to a document
4 *
5 * References:
6 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 *
8 * Michael Kay "XSLT Programmer's Reference" pp 637-643
9 * Writing Multiple Output Files
10 *
11 * XSLT-1.1 Working Draft
12 * http://www.w3.org/TR/xslt11#multiple-output
13 *
14 * See Copyright for the status of this software.
15 *
16 * daniel@veillard.com
17 */
18
19#include "precomp.h"
20
21#include <libxml/debugXML.h>
22
23#ifdef WITH_XSLT_DEBUG
24#define WITH_XSLT_DEBUG_EXTRA
25#define WITH_XSLT_DEBUG_PROCESS
26#define WITH_XSLT_DEBUG_VARIABLE
27#endif
28
29#define XSLT_GENERATE_HTML_DOCTYPE
30#ifdef XSLT_GENERATE_HTML_DOCTYPE
31static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
32 const xmlChar **systemID);
33#endif
34
35int xsltMaxDepth = 3000;
36int xsltMaxVars = 15000;
37
38/*
39 * Useful macros
40 */
41
42#ifndef FALSE
43# define FALSE (0 == 1)
44# define TRUE (!FALSE)
45#endif
46
47#define IS_BLANK_NODE(n) \
48 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
49
50
51/*
52* Forward declarations
53*/
54
55static xmlNsPtr
57
58static xmlNodePtr
60 xmlNodePtr node, xmlNodePtr insert, int isLRE,
61 int topElemVisited);
62
63static void
65 xmlNodePtr contextNode, xmlNodePtr list,
66 xsltTemplatePtr templ);
67
68static void
70 xmlNodePtr contextNode,
72 xsltTemplatePtr templ,
73 xsltStackElemPtr withParams);
74
84static int
86{
87 if (ctxt->templMax == 0) {
88 ctxt->templMax = 4;
89 ctxt->templTab =
91 sizeof(ctxt->templTab[0]));
92 if (ctxt->templTab == NULL) {
93 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
94 return (0);
95 }
96 }
97 else if (ctxt->templNr >= ctxt->templMax) {
98 ctxt->templMax *= 2;
99 ctxt->templTab =
101 ctxt->templMax *
102 sizeof(ctxt->templTab[0]));
103 if (ctxt->templTab == NULL) {
104 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
105 return (0);
106 }
107 }
108 ctxt->templTab[ctxt->templNr] = value;
109 ctxt->templ = value;
110 return (ctxt->templNr++);
111}
120static xsltTemplatePtr
122{
124
125 if (ctxt->templNr <= 0)
126 return (0);
127 ctxt->templNr--;
128 if (ctxt->templNr > 0)
129 ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
130 else
131 ctxt->templ = (xsltTemplatePtr) 0;
132 ret = ctxt->templTab[ctxt->templNr];
133 ctxt->templTab[ctxt->templNr] = 0;
134 return (ret);
135}
136
149void
151{
153
154 if (ctxt->varsNr <= 0)
155 return;
156
157 do {
158 if (ctxt->varsNr <= limitNr)
159 break;
160 variable = ctxt->varsTab[ctxt->varsNr - 1];
161 if (variable->level <= level)
162 break;
163 if (variable->level >= 0)
165 ctxt->varsNr--;
166 } while (ctxt->varsNr != 0);
167 if (ctxt->varsNr > 0)
168 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
169 else
170 ctxt->vars = NULL;
171}
172
179static void
181{
183
184 for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
185 param = ctxt->varsTab[ctxt->varsNr -1];
186 /*
187 * Free xsl:param items.
188 * xsl:with-param items will have a level of -1 or -2.
189 */
190 if (param->level >= 0) {
192 }
193 }
194 if (ctxt->varsNr > 0)
195 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
196 else
197 ctxt->vars = NULL;
198}
199
200#ifdef WITH_PROFILER
201
211static int
212profPush(xsltTransformContextPtr ctxt, long value)
213{
214 if (ctxt->profMax == 0) {
215 ctxt->profMax = 4;
216 ctxt->profTab =
217 (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
218 if (ctxt->profTab == NULL) {
219 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
220 return (0);
221 }
222 }
223 else if (ctxt->profNr >= ctxt->profMax) {
224 ctxt->profMax *= 2;
225 ctxt->profTab =
226 (long *) xmlRealloc(ctxt->profTab,
227 ctxt->profMax * sizeof(ctxt->profTab[0]));
228 if (ctxt->profTab == NULL) {
229 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
230 return (0);
231 }
232 }
233 ctxt->profTab[ctxt->profNr] = value;
234 ctxt->prof = value;
235 return (ctxt->profNr++);
236}
245static long
246profPop(xsltTransformContextPtr ctxt)
247{
248 long ret;
249
250 if (ctxt->profNr <= 0)
251 return (0);
252 ctxt->profNr--;
253 if (ctxt->profNr > 0)
254 ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
255 else
256 ctxt->prof = (long) 0;
257 ret = ctxt->profTab[ctxt->profNr];
258 ctxt->profTab[ctxt->profNr] = 0;
259 return (ret);
260}
261
262static void
263profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
264{
265 int i;
266
267 if (templ->templMax == 0) {
268 templ->templMax = 4;
269 templ->templCalledTab =
271 sizeof(templ->templCalledTab[0]));
272 templ->templCountTab =
273 (int *) xmlMalloc(templ->templMax *
274 sizeof(templ->templCountTab[0]));
275 if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
276 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
277 return;
278 }
279 }
280 else if (templ->templNr >= templ->templMax) {
281 templ->templMax *= 2;
282 templ->templCalledTab =
284 templ->templMax *
285 sizeof(templ->templCalledTab[0]));
286 templ->templCountTab =
287 (int *) xmlRealloc(templ->templCountTab,
288 templ->templMax *
289 sizeof(templ->templCountTab[0]));
290 if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
291 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
292 return;
293 }
294 }
295
296 for (i = 0; i < templ->templNr; i++) {
297 if (templ->templCalledTab[i] == parent) {
298 templ->templCountTab[i]++;
299 break;
300 }
301 }
302 if (i == templ->templNr) {
303 /* not found, add new one */
304 templ->templCalledTab[templ->templNr] = parent;
305 templ->templCountTab[templ->templNr] = 1;
306 templ->templNr++;
307 }
308}
309
310#endif /* WITH_PROFILER */
311
320static xmlXPathObjectPtr
322 xsltStylePreCompPtr comp) {
323 xmlXPathObjectPtr res;
324 xmlXPathContextPtr xpctxt;
325 xmlNodePtr oldXPContextNode;
326 xmlNsPtr *oldXPNamespaces;
327 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
328
329 xpctxt = ctxt->xpathCtxt;
330 oldXPContextNode = xpctxt->node;
331 oldXPProximityPosition = xpctxt->proximityPosition;
332 oldXPContextSize = xpctxt->contextSize;
333 oldXPNsNr = xpctxt->nsNr;
334 oldXPNamespaces = xpctxt->namespaces;
335
336 xpctxt->node = node;
337#ifdef XSLT_REFACTORED
338 if (comp->inScopeNs != NULL) {
339 xpctxt->namespaces = comp->inScopeNs->list;
340 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
341 } else {
342 xpctxt->namespaces = NULL;
343 xpctxt->nsNr = 0;
344 }
345#else
346 xpctxt->namespaces = comp->nsList;
347 xpctxt->nsNr = comp->nsNr;
348#endif
349
350 res = xmlXPathCompiledEval(comp->comp, xpctxt);
351
352 xpctxt->node = oldXPContextNode;
353 xpctxt->proximityPosition = oldXPProximityPosition;
354 xpctxt->contextSize = oldXPContextSize;
355 xpctxt->nsNr = oldXPNsNr;
356 xpctxt->namespaces = oldXPNamespaces;
357
358 return(res);
359}
360
369static int
371 xsltStylePreCompPtr comp) {
372 int res;
373 xmlXPathContextPtr xpctxt;
374 xmlNodePtr oldXPContextNode;
375 xmlNsPtr *oldXPNamespaces;
376 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
377
378 xpctxt = ctxt->xpathCtxt;
379 oldXPContextNode = xpctxt->node;
380 oldXPProximityPosition = xpctxt->proximityPosition;
381 oldXPContextSize = xpctxt->contextSize;
382 oldXPNsNr = xpctxt->nsNr;
383 oldXPNamespaces = xpctxt->namespaces;
384
385 xpctxt->node = node;
386#ifdef XSLT_REFACTORED
387 if (comp->inScopeNs != NULL) {
388 xpctxt->namespaces = comp->inScopeNs->list;
389 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
390 } else {
391 xpctxt->namespaces = NULL;
392 xpctxt->nsNr = 0;
393 }
394#else
395 xpctxt->namespaces = comp->nsList;
396 xpctxt->nsNr = comp->nsNr;
397#endif
398
399 res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
400
401 xpctxt->node = oldXPContextNode;
402 xpctxt->proximityPosition = oldXPProximityPosition;
403 xpctxt->contextSize = oldXPContextSize;
404 xpctxt->nsNr = oldXPNsNr;
405 xpctxt->namespaces = oldXPNamespaces;
406
407 return(res);
408}
409
410/************************************************************************
411 * *
412 * XInclude default settings *
413 * *
414 ************************************************************************/
415
417
424void
426 xsltDoXIncludeDefault = (xinclude != 0);
427}
428
436int
438 return(xsltDoXIncludeDefault);
439}
440
441static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
442
451}
452
461 return xsltDefaultTrace;
462}
463
464/************************************************************************
465 * *
466 * Handling of Transformation Contexts *
467 * *
468 ************************************************************************/
469
472{
474
476 if (ret == NULL) {
478 "xsltTransformCacheCreate : malloc failed\n");
479 return(NULL);
480 }
481 memset(ret, 0, sizeof(xsltTransformCache));
482 return(ret);
483}
484
485static void
487{
488 if (cache == NULL)
489 return;
490 /*
491 * Free tree fragments.
492 */
493 if (cache->RVT) {
494 xmlDocPtr tmp, cur = cache->RVT;
495 while (cur) {
496 tmp = cur;
497 cur = (xmlDocPtr) cur->next;
498 if (tmp->_private != NULL) {
499 /*
500 * Tree the document info.
501 */
503 xmlFree(tmp->_private);
504 }
505 xmlFreeDoc(tmp);
506 }
507 }
508 /*
509 * Free vars/params.
510 */
511 if (cache->stackItems) {
512 xsltStackElemPtr tmp, cur = cache->stackItems;
513 while (cur) {
514 tmp = cur;
515 cur = cur->next;
516 /*
517 * REVISIT TODO: Should be call a destruction-function
518 * instead?
519 */
520 xmlFree(tmp);
521 }
522 }
523 xmlFree(cache);
524}
525
538 xsltDocumentPtr docu;
539 int i;
540
542
544 if (cur == NULL) {
546 "xsltNewTransformContext : malloc failed\n");
547 return(NULL);
548 }
549 memset(cur, 0, sizeof(xsltTransformContext));
550
551 cur->cache = xsltTransformCacheCreate();
552 if (cur->cache == NULL)
553 goto internal_err;
554 /*
555 * setup of the dictionary must be done early as some of the
556 * processing later like key handling may need it.
557 */
558 cur->dict = xmlDictCreateSub(style->dict);
559 cur->internalized = ((style->internalized) && (cur->dict != NULL));
560#ifdef WITH_XSLT_DEBUG
562 "Creating sub-dictionary from stylesheet for transformation\n");
563#endif
564
565 /*
566 * initialize the template stack
567 */
568 cur->templTab = (xsltTemplatePtr *)
569 xmlMalloc(10 * sizeof(xsltTemplatePtr));
570 if (cur->templTab == NULL) {
572 "xsltNewTransformContext: out of memory\n");
573 goto internal_err;
574 }
575 cur->templNr = 0;
576 cur->templMax = 5;
577 cur->templ = NULL;
578 cur->maxTemplateDepth = xsltMaxDepth;
579
580 /*
581 * initialize the variables stack
582 */
583 cur->varsTab = (xsltStackElemPtr *)
584 xmlMalloc(10 * sizeof(xsltStackElemPtr));
585 if (cur->varsTab == NULL) {
587 "xsltNewTransformContext: out of memory\n");
588 goto internal_err;
589 }
590 cur->varsNr = 0;
591 cur->varsMax = 10;
592 cur->vars = NULL;
593 cur->varsBase = 0;
594 cur->maxTemplateVars = xsltMaxVars;
595
596 /*
597 * the profiling stack is not initialized by default
598 */
599 cur->profTab = NULL;
600 cur->profNr = 0;
601 cur->profMax = 0;
602 cur->prof = 0;
603
604 cur->style = style;
605 cur->xpathCtxt = xmlXPathNewContext(doc);
606 if (cur->xpathCtxt == NULL) {
608 "xsltNewTransformContext : xmlXPathNewContext failed\n");
609 goto internal_err;
610 }
611 /*
612 * Create an XPath cache.
613 */
614 if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
615 goto internal_err;
616 /*
617 * Initialize the extras array
618 */
619 if (style->extrasNr != 0) {
620 cur->extrasMax = style->extrasNr + 20;
621 cur->extras = (xsltRuntimeExtraPtr)
622 xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
623 if (cur->extras == NULL) {
625 "xsltNewTransformContext: out of memory\n");
626 goto internal_err;
627 }
628 cur->extrasNr = style->extrasNr;
629 for (i = 0;i < cur->extrasMax;i++) {
630 cur->extras[i].info = NULL;
631 cur->extras[i].deallocate = NULL;
632 cur->extras[i].val.ptr = NULL;
633 }
634 } else {
635 cur->extras = NULL;
636 cur->extrasNr = 0;
637 cur->extrasMax = 0;
638 }
639
642 cur->xpathCtxt->nsHash = style->nsHash;
643 /*
644 * Initialize the registered external modules
645 */
647 /*
648 * Setup document element ordering for later efficiencies
649 * (bug 133289)
650 */
652 xmlXPathOrderDocElems(doc);
653 /*
654 * Must set parserOptions before calling xsltNewDocument
655 * (bug 164530)
656 */
657 cur->parserOptions = XSLT_PARSE_OPTIONS;
658 docu = xsltNewDocument(cur, doc);
659 if (docu == NULL) {
661 "xsltNewTransformContext : xsltNewDocument failed\n");
662 goto internal_err;
663 }
664 docu->main = 1;
665 cur->document = docu;
666 cur->inst = NULL;
667 cur->outputFile = NULL;
669 cur->debugStatus = xslDebugStatus;
670 cur->traceCode = (unsigned long*) &xsltDefaultTrace;
671 cur->xinclude = xsltGetXIncludeDefault();
672 cur->keyInitLevel = 0;
673
674 return(cur);
675
676internal_err:
677 if (cur != NULL)
679 return(NULL);
680}
681
688void
690 if (ctxt == NULL)
691 return;
692
693 /*
694 * Shutdown the extension modules associated to the stylesheet
695 * used if needed.
696 */
698
699 if (ctxt->xpathCtxt != NULL) {
700 ctxt->xpathCtxt->nsHash = NULL;
701 xmlXPathFreeContext(ctxt->xpathCtxt);
702 }
703 if (ctxt->templTab != NULL)
704 xmlFree(ctxt->templTab);
705 if (ctxt->varsTab != NULL)
706 xmlFree(ctxt->varsTab);
707 if (ctxt->profTab != NULL)
708 xmlFree(ctxt->profTab);
709 if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
710 int i;
711
712 for (i = 0;i < ctxt->extrasNr;i++) {
713 if ((ctxt->extras[i].deallocate != NULL) &&
714 (ctxt->extras[i].info != NULL))
715 ctxt->extras[i].deallocate(ctxt->extras[i].info);
716 }
717 xmlFree(ctxt->extras);
718 }
720 xsltFreeDocuments(ctxt);
721 xsltFreeCtxtExts(ctxt);
722 xsltFreeRVTs(ctxt);
724 xmlDictFree(ctxt->dict);
725#ifdef WITH_XSLT_DEBUG
727 "freeing transformation dictionary\n");
728#endif
729 memset(ctxt, -1, sizeof(xsltTransformContext));
730 xmlFree(ctxt);
731}
732
733/************************************************************************
734 * *
735 * Copy of Nodes in an XSLT fashion *
736 * *
737 ************************************************************************/
738
750static xmlNodePtr
753
754 if (cur == NULL)
755 return(NULL);
756 if (parent == NULL) {
758 return(NULL);
759 }
761
762 return(ret);
763}
764
776static xmlNodePtr
778 const xmlChar *string, int len) {
779 /*
780 * optimization
781 */
782 if ((len <= 0) || (string == NULL) || (target == NULL))
783 return(target);
784
785 if (ctxt->lasttext == target->content) {
786 int minSize;
787
788 /* Check for integer overflow accounting for NUL terminator. */
789 if (len >= INT_MAX - ctxt->lasttuse) {
791 "xsltCopyText: text allocation failed\n");
792 return(NULL);
793 }
794 minSize = ctxt->lasttuse + len + 1;
795
796 if (ctxt->lasttsize < minSize) {
797 xmlChar *newbuf;
798 int size;
799 int extra;
800
801 /* Double buffer size but increase by at least 100 bytes. */
802 extra = minSize < 100 ? 100 : minSize;
803
804 /* Check for integer overflow. */
805 if (extra > INT_MAX - ctxt->lasttsize) {
806 size = INT_MAX;
807 }
808 else {
809 size = ctxt->lasttsize + extra;
810 }
811
812 newbuf = (xmlChar *) xmlRealloc(target->content,size);
813 if (newbuf == NULL) {
815 "xsltCopyText: text allocation failed\n");
816 return(NULL);
817 }
818 ctxt->lasttsize = size;
819 ctxt->lasttext = newbuf;
820 target->content = newbuf;
821 }
822 memcpy(&(target->content[ctxt->lasttuse]), string, len);
823 ctxt->lasttuse += len;
824 target->content[ctxt->lasttuse] = 0;
825 } else {
826 xmlNodeAddContent(target, string);
827 ctxt->lasttext = target->content;
828 len = xmlStrlen(target->content);
829 ctxt->lasttsize = len;
830 ctxt->lasttuse = len;
831 }
832 return(target);
833}
834
850 const xmlChar *string, int noescape)
851{
853 int len;
854
855 if (string == NULL)
856 return(NULL);
857
858#ifdef WITH_XSLT_DEBUG_PROCESS
860 "xsltCopyTextString: copy text %s\n",
861 string));
862#endif
863
864 /*
865 * Play safe and reset the merging mechanism for every new
866 * target node.
867 */
868 if ((target == NULL) || (target->children == NULL)) {
869 ctxt->lasttext = NULL;
870 }
871
872 /* handle coalescing of text nodes here */
873 len = xmlStrlen(string);
874 if ((ctxt->type == XSLT_OUTPUT_XML) &&
875 (ctxt->style->cdataSection != NULL) &&
876 (target != NULL) &&
877 (target->type == XML_ELEMENT_NODE) &&
878 (((target->ns == NULL) &&
880 target->name, NULL) != NULL)) ||
881 ((target->ns != NULL) &&
883 target->name, target->ns->href) != NULL))))
884 {
885 /*
886 * Process "cdata-section-elements".
887 */
888 if ((target->last != NULL) &&
889 (target->last->type == XML_CDATA_SECTION_NODE))
890 {
891 return(xsltAddTextString(ctxt, target->last, string, len));
892 }
893 copy = xmlNewCDataBlock(ctxt->output, string, len);
894 } else if (noescape) {
895 /*
896 * Process "disable-output-escaping".
897 */
898 if ((target != NULL) && (target->last != NULL) &&
899 (target->last->type == XML_TEXT_NODE) &&
900 (target->last->name == xmlStringTextNoenc))
901 {
902 return(xsltAddTextString(ctxt, target->last, string, len));
903 }
904 copy = xmlNewTextLen(string, len);
905 if (copy != NULL)
906 copy->name = xmlStringTextNoenc;
907 } else {
908 /*
909 * Default processing.
910 */
911 if ((target != NULL) && (target->last != NULL) &&
912 (target->last->type == XML_TEXT_NODE) &&
913 (target->last->name == xmlStringText)) {
914 return(xsltAddTextString(ctxt, target->last, string, len));
915 }
916 copy = xmlNewTextLen(string, len);
917 }
918 if (copy != NULL && target != NULL)
920 if (copy != NULL) {
921 ctxt->lasttext = copy->content;
922 ctxt->lasttsize = len;
923 ctxt->lasttuse = len;
924 } else {
926 "xsltCopyTextString: text copy failed\n");
927 ctxt->lasttext = NULL;
928 }
929 return(copy);
930}
931
944static xmlNodePtr
946 xmlNodePtr cur, int interned)
947{
949
950 if ((cur->type != XML_TEXT_NODE) &&
951 (cur->type != XML_CDATA_SECTION_NODE))
952 return(NULL);
953 if (cur->content == NULL)
954 return(NULL);
955
956#ifdef WITH_XSLT_DEBUG_PROCESS
957 if (cur->type == XML_CDATA_SECTION_NODE) {
959 "xsltCopyText: copy CDATA text %s\n",
960 cur->content));
961 } else if (cur->name == xmlStringTextNoenc) {
963 "xsltCopyText: copy unescaped text %s\n",
964 cur->content));
965 } else {
967 "xsltCopyText: copy text %s\n",
968 cur->content));
969 }
970#endif
971
972 /*
973 * Play save and reset the merging mechanism for every new
974 * target node.
975 */
976 if ((target == NULL) || (target->children == NULL)) {
977 ctxt->lasttext = NULL;
978 }
979
980 if ((ctxt->style->cdataSection != NULL) &&
981 (ctxt->type == XSLT_OUTPUT_XML) &&
982 (target != NULL) &&
983 (target->type == XML_ELEMENT_NODE) &&
984 (((target->ns == NULL) &&
986 target->name, NULL) != NULL)) ||
987 ((target->ns != NULL) &&
989 target->name, target->ns->href) != NULL))))
990 {
991 /*
992 * Process "cdata-section-elements".
993 */
994 /*
995 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
996 */
997 /*
998 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
999 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
1000 * TODO: Reported in #321505.
1001 */
1002 if ((target->last != NULL) &&
1003 (target->last->type == XML_CDATA_SECTION_NODE))
1004 {
1005 /*
1006 * Append to existing CDATA-section node.
1007 */
1008 copy = xsltAddTextString(ctxt, target->last, cur->content,
1009 xmlStrlen(cur->content));
1010 goto exit;
1011 } else {
1012 unsigned int len;
1013
1014 len = xmlStrlen(cur->content);
1015 copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
1016 if (copy == NULL)
1017 goto exit;
1018 ctxt->lasttext = copy->content;
1019 ctxt->lasttsize = len;
1020 ctxt->lasttuse = len;
1021 }
1022 } else if ((target != NULL) &&
1023 (target->last != NULL) &&
1024 /* both escaped or both non-escaped text-nodes */
1025 (((target->last->type == XML_TEXT_NODE) &&
1026 (target->last->name == cur->name)) ||
1027 /* non-escaped text nodes and CDATA-section nodes */
1028 (((target->last->type == XML_CDATA_SECTION_NODE) &&
1029 (cur->name == xmlStringTextNoenc)))))
1030 {
1031 /*
1032 * we are appending to an existing text node
1033 */
1034 copy = xsltAddTextString(ctxt, target->last, cur->content,
1035 xmlStrlen(cur->content));
1036 goto exit;
1037 } else if ((interned) && (target != NULL) &&
1038 (target->doc != NULL) &&
1039 (target->doc->dict == ctxt->dict))
1040 {
1041 /*
1042 * TODO: DO we want to use this also for "text" output?
1043 */
1044 copy = xmlNewTextLen(NULL, 0);
1045 if (copy == NULL)
1046 goto exit;
1047 if (cur->name == xmlStringTextNoenc)
1048 copy->name = xmlStringTextNoenc;
1049
1050 /*
1051 * Must confirm that content is in dict (bug 302821)
1052 * TODO: This check should be not needed for text coming
1053 * from the stylesheets
1054 */
1055 if (xmlDictOwns(ctxt->dict, cur->content))
1056 copy->content = cur->content;
1057 else {
1058 if ((copy->content = xmlStrdup(cur->content)) == NULL)
1059 return NULL;
1060 }
1061
1062 ctxt->lasttext = NULL;
1063 } else {
1064 /*
1065 * normal processing. keep counters to extend the text node
1066 * in xsltAddTextString if needed.
1067 */
1068 unsigned int len;
1069
1070 len = xmlStrlen(cur->content);
1071 copy = xmlNewTextLen(cur->content, len);
1072 if (copy == NULL)
1073 goto exit;
1074 if (cur->name == xmlStringTextNoenc)
1075 copy->name = xmlStringTextNoenc;
1076 ctxt->lasttext = copy->content;
1077 ctxt->lasttsize = len;
1078 ctxt->lasttuse = len;
1079 }
1080 if (copy != NULL) {
1081 if (target != NULL) {
1082 copy->doc = target->doc;
1083 /*
1084 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1085 * to ensure that the optimized text-merging mechanism
1086 * won't interfere with normal node-merging in any case.
1087 */
1089 }
1090 } else {
1092 "xsltCopyText: text copy failed\n");
1093 }
1094
1095exit:
1096 if ((copy == NULL) || (copy->content == NULL)) {
1098 "Internal error in xsltCopyText(): "
1099 "Failed to copy the string.\n");
1100 ctxt->state = XSLT_STATE_STOPPED;
1101 }
1102 return(copy);
1103}
1104
1120static xmlAttrPtr
1123{
1125 xmlChar *value;
1126
1127 if (attr == NULL)
1128 return(NULL);
1129
1130 if (target->type != XML_ELEMENT_NODE) {
1131 xsltTransformError(ctxt, NULL, invocNode,
1132 "Cannot add an attribute node to a non-element node.\n");
1133 return(NULL);
1134 }
1135
1136 if (target->children != NULL) {
1137 xsltTransformError(ctxt, NULL, invocNode,
1138 "Attribute nodes must be added before "
1139 "any child nodes to an element.\n");
1140 return(NULL);
1141 }
1142
1143 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1144 if (attr->ns != NULL) {
1145 xmlNsPtr ns;
1146
1147 ns = xsltGetSpecialNamespace(ctxt, invocNode,
1148 attr->ns->href, attr->ns->prefix, target);
1149 if (ns == NULL) {
1150 xsltTransformError(ctxt, NULL, invocNode,
1151 "Namespace fixup error: Failed to acquire an in-scope "
1152 "namespace binding of the copied attribute '{%s}%s'.\n",
1153 attr->ns->href, attr->name);
1154 /*
1155 * TODO: Should we just stop here?
1156 */
1157 }
1158 /*
1159 * Note that xmlSetNsProp() will take care of duplicates
1160 * and assigns the new namespace even to a duplicate.
1161 */
1162 copy = xmlSetNsProp(target, ns, attr->name, value);
1163 } else {
1164 copy = xmlSetNsProp(target, NULL, attr->name, value);
1165 }
1166 if (value != NULL)
1167 xmlFree(value);
1168
1169 if (copy == NULL)
1170 return(NULL);
1171
1172#if 0
1173 /*
1174 * NOTE: This was optimized according to bug #342695.
1175 * TODO: Can this further be optimized, if source and target
1176 * share the same dict and attr->children is just 1 text node
1177 * which is in the dict? How probable is such a case?
1178 */
1179 /*
1180 * TODO: Do we need to create an empty text node if the value
1181 * is the empty string?
1182 */
1183 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1184 if (value != NULL) {
1185 txtNode = xmlNewDocText(target->doc, NULL);
1186 if (txtNode == NULL)
1187 return(NULL);
1188 if ((target->doc != NULL) &&
1189 (target->doc->dict != NULL))
1190 {
1191 txtNode->content =
1192 (xmlChar *) xmlDictLookup(target->doc->dict,
1193 BAD_CAST value, -1);
1194 xmlFree(value);
1195 } else
1196 txtNode->content = value;
1197 copy->children = txtNode;
1198 }
1199#endif
1200
1201 return(copy);
1202}
1203
1219static int
1221 xmlNodePtr invocNode,
1223{
1225 xmlNsPtr origNs = NULL, copyNs = NULL;
1226 xmlChar *value;
1227
1228 /*
1229 * Don't use xmlCopyProp() here, since it will try to
1230 * reconciliate namespaces.
1231 */
1232 while (attr != NULL) {
1233 /*
1234 * Find a namespace node in the tree of @target.
1235 * Avoid searching for the same ns.
1236 */
1237 if (attr->ns != origNs) {
1238 origNs = attr->ns;
1239 if (attr->ns != NULL) {
1240 copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
1241 attr->ns->href, attr->ns->prefix, target);
1242 if (copyNs == NULL)
1243 return(-1);
1244 } else
1245 copyNs = NULL;
1246 }
1247 /*
1248 * If attribute has a value, we need to copy it (watching out
1249 * for possible entities)
1250 */
1251 if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
1252 (attr->children->next == NULL)) {
1253 copy = xmlNewNsProp(target, copyNs, attr->name,
1254 attr->children->content);
1255 } else if (attr->children != NULL) {
1256 value = xmlNodeListGetString(attr->doc, attr->children, 1);
1258 xmlFree(value);
1259 } else {
1260 copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
1261 }
1262
1263 if (copy == NULL)
1264 return(-1);
1265
1266 attr = attr->next;
1267 }
1268 return(0);
1269}
1270
1295static xmlNodePtr
1297 xmlNodePtr insert, int isLRE)
1298{
1300
1301 if ((node->type == XML_DTD_NODE) || (insert == NULL))
1302 return(NULL);
1303 if ((node->type == XML_TEXT_NODE) ||
1304 (node->type == XML_CDATA_SECTION_NODE))
1305 return(xsltCopyText(ctxt, insert, node, 0));
1306
1307 copy = xmlDocCopyNode(node, insert->doc, 0);
1308 if (copy != NULL) {
1309 copy->doc = ctxt->output;
1311 if (copy == NULL) {
1313 "xsltShallowCopyElem: copy failed\n");
1314 return (copy);
1315 }
1316
1317 if (node->type == XML_ELEMENT_NODE) {
1318 /*
1319 * Add namespaces as they are needed
1320 */
1321 if (node->nsDef != NULL) {
1322 /*
1323 * TODO: Remove the LRE case in the refactored code
1324 * gets enabled.
1325 */
1326 if (isLRE)
1327 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1328 else
1330 }
1331
1332 /*
1333 * URGENT TODO: The problem with this is that it does not
1334 * copy over all namespace nodes in scope.
1335 * The damn thing about this is, that we would need to
1336 * use the xmlGetNsList(), for every single node; this is
1337 * also done in xsltCopyTree(), but only for the top node.
1338 */
1339 if (node->ns != NULL) {
1340 if (isLRE) {
1341 /*
1342 * REVISIT TODO: Since the non-refactored code still does
1343 * ns-aliasing, we need to call xsltGetNamespace() here.
1344 * Remove this when ready.
1345 */
1346 copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
1347 } else {
1348 copy->ns = xsltGetSpecialNamespace(ctxt,
1349 node, node->ns->href, node->ns->prefix, copy);
1350
1351 }
1352 } else if ((insert->type == XML_ELEMENT_NODE) &&
1353 (insert->ns != NULL))
1354 {
1355 /*
1356 * "Undeclare" the default namespace.
1357 */
1359 }
1360 }
1361 } else {
1363 "xsltShallowCopyElem: copy %s failed\n", node->name);
1364 }
1365 return(copy);
1366}
1367
1387static xmlNodePtr
1390 xmlNodePtr insert, int isLRE, int topElemVisited)
1391{
1393
1394 while (list != NULL) {
1395 copy = xsltCopyTree(ctxt, invocNode,
1396 list, insert, isLRE, topElemVisited);
1397 if (copy != NULL) {
1398 if (ret == NULL) {
1399 ret = copy;
1400 }
1401 }
1402 list = list->next;
1403 }
1404 return(ret);
1405}
1406
1423static xmlNsPtr
1425 xmlNsPtr ret = NULL;
1426 xmlNsPtr p = NULL, q, luNs;
1427
1428 if (ns == NULL)
1429 return(NULL);
1430 /*
1431 * One can add namespaces only on element nodes
1432 */
1433 if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
1434 elem = NULL;
1435
1436 do {
1437 if (ns->type != XML_NAMESPACE_DECL)
1438 break;
1439 /*
1440 * Avoid duplicating namespace declarations on the tree.
1441 */
1442 if (elem != NULL) {
1443 if ((elem->ns != NULL) &&
1444 xmlStrEqual(elem->ns->prefix, ns->prefix) &&
1445 xmlStrEqual(elem->ns->href, ns->href))
1446 {
1447 ns = ns->next;
1448 continue;
1449 }
1450 luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
1451 if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
1452 {
1453 ns = ns->next;
1454 continue;
1455 }
1456 }
1457 q = xmlNewNs(elem, ns->href, ns->prefix);
1458 if (p == NULL) {
1459 ret = p = q;
1460 } else if (q != NULL) {
1461 p->next = q;
1462 p = q;
1463 }
1464 ns = ns->next;
1465 } while (ns != NULL);
1466 return(ret);
1467}
1468
1480static xmlNsPtr
1482 xmlNodePtr invocNode,
1484 xmlNsPtr ns)
1485{
1486 /*
1487 * TODO: Contrary to header comments, this is declared as int.
1488 * be modified to return a node pointer, or NULL if any error
1489 */
1490 xmlNsPtr tmpns;
1491
1492 if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
1493 return(NULL);
1494
1495 if (insert->children != NULL) {
1496 xsltTransformError(ctxt, NULL, invocNode,
1497 "Namespace nodes must be added before "
1498 "any child nodes are added to an element.\n");
1499 return(NULL);
1500 }
1501 /*
1502 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1503 * an equal prefix. We definitively won't do that.
1504 *
1505 * MSXML 4.0 and the .NET ignores ns-decls for which an
1506 * equal prefix is already in use.
1507 *
1508 * Saxon raises an error like:
1509 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1510 * nodes with the same name".
1511 *
1512 * NOTE: We'll currently follow MSXML here.
1513 * REVISIT TODO: Check if it's better to follow Saxon here.
1514 */
1515 if (ns->prefix == NULL) {
1516 /*
1517 * If we are adding ns-nodes to an element using e.g.
1518 * <xsl:copy-of select="/foo/namespace::*">, then we need
1519 * to ensure that we don't incorrectly declare a default
1520 * namespace on an element in no namespace, which otherwise
1521 * would move the element incorrectly into a namespace, if
1522 * the node tree is serialized.
1523 */
1524 if (insert->ns == NULL)
1525 goto occupied;
1526 } else if ((ns->prefix[0] == 'x') &&
1527 xmlStrEqual(ns->prefix, BAD_CAST "xml"))
1528 {
1529 /*
1530 * The XML namespace is built in.
1531 */
1532 return(NULL);
1533 }
1534
1535 if (insert->nsDef != NULL) {
1536 tmpns = insert->nsDef;
1537 do {
1538 if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
1539 if ((tmpns->prefix == ns->prefix) ||
1540 xmlStrEqual(tmpns->prefix, ns->prefix))
1541 {
1542 /*
1543 * Same prefix.
1544 */
1545 if (xmlStrEqual(tmpns->href, ns->href))
1546 return(NULL);
1547 goto occupied;
1548 }
1549 }
1550 tmpns = tmpns->next;
1551 } while (tmpns != NULL);
1552 }
1553 tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
1554 if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
1555 return(NULL);
1556 /*
1557 * Declare a new namespace.
1558 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1559 * that it will again search the already declared namespaces
1560 * for a duplicate :-/
1561 */
1562 return(xmlNewNs(insert, ns->href, ns->prefix));
1563
1564occupied:
1565 /*
1566 * TODO: We could as well raise an error here (like Saxon does),
1567 * or at least generate a warning.
1568 */
1569 return(NULL);
1570}
1571
1591static xmlNodePtr
1593 xmlNodePtr node, xmlNodePtr insert, int isLRE,
1594 int topElemVisited)
1595{
1597
1598 if (node == NULL)
1599 return(NULL);
1600 switch (node->type) {
1601 case XML_ELEMENT_NODE:
1603 case XML_ENTITY_NODE:
1604 case XML_PI_NODE:
1605 case XML_COMMENT_NODE:
1606 case XML_DOCUMENT_NODE:
1608#ifdef LIBXML_DOCB_ENABLED
1610#endif
1611 break;
1612 case XML_TEXT_NODE: {
1613 int noenc = (node->name == xmlStringTextNoenc);
1614 return(xsltCopyTextString(ctxt, insert, node->content, noenc));
1615 }
1617 return(xsltCopyTextString(ctxt, insert, node->content, 0));
1618 case XML_ATTRIBUTE_NODE:
1619 return((xmlNodePtr)
1620 xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
1621 case XML_NAMESPACE_DECL:
1622 return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
1623 insert, (xmlNsPtr) node));
1624
1627 case XML_NOTATION_NODE:
1628 case XML_DTD_NODE:
1629 case XML_ELEMENT_DECL:
1630 case XML_ATTRIBUTE_DECL:
1631 case XML_ENTITY_DECL:
1632 case XML_XINCLUDE_START:
1633 case XML_XINCLUDE_END:
1634 return(NULL);
1635 }
1637 if (node->children != NULL)
1638 copy = xsltCopyTreeList(ctxt, invocNode,
1639 node->children, insert, 0, 0);
1640 else
1641 copy = NULL;
1642 return(copy);
1643 }
1644 copy = xmlDocCopyNode(node, insert->doc, 0);
1645 if (copy != NULL) {
1646 copy->doc = ctxt->output;
1648 if (copy == NULL) {
1649 xsltTransformError(ctxt, NULL, invocNode,
1650 "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1651 return (copy);
1652 }
1653 /*
1654 * The node may have been coalesced into another text node.
1655 */
1656 if (insert->last != copy)
1657 return(insert->last);
1658 copy->next = NULL;
1659
1660 if (node->type == XML_ELEMENT_NODE) {
1661 /*
1662 * Copy in-scope namespace nodes.
1663 *
1664 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1665 * using xmlSearchNsByHref(), this will eventually change
1666 * the prefix of an original ns-binding; thus it might
1667 * break QNames in element/attribute content.
1668 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1669 * context, plus a ns-lookup function, which writes directly
1670 * to a given list, then we wouldn't need to create/free the
1671 * nsList every time.
1672 */
1673 if ((topElemVisited == 0) &&
1674 (node->parent != NULL) &&
1675 (node->parent->type != XML_DOCUMENT_NODE) &&
1676 (node->parent->type != XML_HTML_DOCUMENT_NODE))
1677 {
1678 xmlNsPtr *nsList, *curns, ns;
1679
1680 /*
1681 * If this is a top-most element in a tree to be
1682 * copied, then we need to ensure that all in-scope
1683 * namespaces are copied over. For nodes deeper in the
1684 * tree, it is sufficient to reconcile only the ns-decls
1685 * (node->nsDef entries).
1686 */
1687
1688 nsList = xmlGetNsList(node->doc, node);
1689 if (nsList != NULL) {
1690 curns = nsList;
1691 do {
1692 /*
1693 * Search by prefix first in order to break as less
1694 * QNames in element/attribute content as possible.
1695 */
1696 ns = xmlSearchNs(insert->doc, insert,
1697 (*curns)->prefix);
1698
1699 if ((ns == NULL) ||
1700 (! xmlStrEqual(ns->href, (*curns)->href)))
1701 {
1702 ns = NULL;
1703 /*
1704 * Search by namespace name.
1705 * REVISIT TODO: Currently disabled.
1706 */
1707#if 0
1709 insert, (*curns)->href);
1710#endif
1711 }
1712 if (ns == NULL) {
1713 /*
1714 * Declare a new namespace on the copied element.
1715 */
1716 ns = xmlNewNs(copy, (*curns)->href,
1717 (*curns)->prefix);
1718 /* TODO: Handle errors */
1719 }
1720 if (node->ns == *curns) {
1721 /*
1722 * If this was the original's namespace then set
1723 * the generated counterpart on the copy.
1724 */
1725 copy->ns = ns;
1726 }
1727 curns++;
1728 } while (*curns != NULL);
1729 xmlFree(nsList);
1730 }
1731 } else if (node->nsDef != NULL) {
1732 /*
1733 * Copy over all namespace declaration attributes.
1734 */
1735 if (node->nsDef != NULL) {
1736 if (isLRE)
1737 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1738 else
1740 }
1741 }
1742 /*
1743 * Set the namespace.
1744 */
1745 if (node->ns != NULL) {
1746 if (copy->ns == NULL) {
1747 /*
1748 * This will map copy->ns to one of the newly created
1749 * in-scope ns-decls, OR create a new ns-decl on @copy.
1750 */
1751 copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
1752 node->ns->href, node->ns->prefix, copy);
1753 }
1754 } else if ((insert->type == XML_ELEMENT_NODE) &&
1755 (insert->ns != NULL))
1756 {
1757 /*
1758 * "Undeclare" the default namespace on @copy with xmlns="".
1759 */
1760 xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
1761 }
1762 /*
1763 * Copy attribute nodes.
1764 */
1765 if (node->properties != NULL) {
1766 xsltCopyAttrListNoOverwrite(ctxt, invocNode,
1767 copy, node->properties);
1768 }
1769 if (topElemVisited == 0)
1770 topElemVisited = 1;
1771 }
1772 /*
1773 * Copy the subtree.
1774 */
1775 if (node->children != NULL) {
1776 xsltCopyTreeList(ctxt, invocNode,
1777 node->children, copy, isLRE, topElemVisited);
1778 }
1779 } else {
1780 xsltTransformError(ctxt, NULL, invocNode,
1781 "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1782 }
1783 return(copy);
1784}
1785
1786/************************************************************************
1787 * *
1788 * Error/fallback processing *
1789 * *
1790 ************************************************************************/
1791
1802static int
1804 xmlNodePtr inst) {
1805
1807 int ret = 0;
1808
1809 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
1810 (inst->children == NULL))
1811 return(0);
1812
1813 child = inst->children;
1814 while (child != NULL) {
1815 if ((IS_XSLT_ELEM(child)) &&
1816 (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
1817#ifdef WITH_XSLT_DEBUG_PARSING
1819 "applying xsl:fallback\n");
1820#endif
1821 ret++;
1822 xsltApplySequenceConstructor(ctxt, node, child->children,
1823 NULL);
1824 }
1825 child = child->next;
1826 }
1827 return(ret);
1828}
1829
1830/************************************************************************
1831 * *
1832 * Default processing *
1833 * *
1834 ************************************************************************/
1835
1858static void
1863 int nbchild = 0, oldSize;
1864 int childno = 0, oldPos;
1865 xsltTemplatePtr template;
1866
1868 /*
1869 * Handling of leaves
1870 */
1871 switch (node->type) {
1872 case XML_DOCUMENT_NODE:
1874 case XML_ELEMENT_NODE:
1875 break;
1877#ifdef WITH_XSLT_DEBUG_PROCESS
1879 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1880 node->content));
1881#endif
1882 copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1883 if (copy == NULL) {
1885 "xsltDefaultProcessOneNode: cdata copy failed\n");
1886 }
1887 return;
1888 case XML_TEXT_NODE:
1889#ifdef WITH_XSLT_DEBUG_PROCESS
1890 if (node->content == NULL) {
1892 "xsltDefaultProcessOneNode: copy empty text\n"));
1893 return;
1894 } else {
1896 "xsltDefaultProcessOneNode: copy text %s\n",
1897 node->content));
1898 }
1899#endif
1900 copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1901 if (copy == NULL) {
1903 "xsltDefaultProcessOneNode: text copy failed\n");
1904 }
1905 return;
1906 case XML_ATTRIBUTE_NODE:
1907 cur = node->children;
1908 while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
1909 cur = cur->next;
1910 if (cur == NULL) {
1912 "xsltDefaultProcessOneNode: no text for attribute\n");
1913 } else {
1914#ifdef WITH_XSLT_DEBUG_PROCESS
1915 if (cur->content == NULL) {
1917 "xsltDefaultProcessOneNode: copy empty text\n"));
1918 } else {
1920 "xsltDefaultProcessOneNode: copy text %s\n",
1921 cur->content));
1922 }
1923#endif
1924 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1925 if (copy == NULL) {
1927 "xsltDefaultProcessOneNode: text copy failed\n");
1928 }
1929 }
1930 return;
1931 default:
1932 return;
1933 }
1934 /*
1935 * Handling of Elements: first pass, counting
1936 */
1937 cur = node->children;
1938 while (cur != NULL) {
1940 nbchild++;
1941 cur = cur->next;
1942 }
1943
1944 /*
1945 * Handling of Elements: second pass, actual processing
1946 *
1947 * Note that params are passed to the next template. This matches
1948 * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1949 */
1950 oldSize = ctxt->xpathCtxt->contextSize;
1951 oldPos = ctxt->xpathCtxt->proximityPosition;
1952 cur = node->children;
1953 while (cur != NULL) {
1954 childno++;
1955 switch (cur->type) {
1956 case XML_DOCUMENT_NODE:
1958 case XML_ELEMENT_NODE:
1959 ctxt->xpathCtxt->contextSize = nbchild;
1960 ctxt->xpathCtxt->proximityPosition = childno;
1962 break;
1964 template = xsltGetTemplate(ctxt, cur, NULL);
1965 if (template) {
1966#ifdef WITH_XSLT_DEBUG_PROCESS
1968 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
1969 cur->content));
1970#endif
1971 /*
1972 * Instantiate the xsl:template.
1973 */
1974 xsltApplyXSLTTemplate(ctxt, cur, template->content,
1975 template, params);
1976 } else /* if (ctxt->mode == NULL) */ {
1977#ifdef WITH_XSLT_DEBUG_PROCESS
1979 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1980 cur->content));
1981#endif
1982 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1983 if (copy == NULL) {
1985 "xsltDefaultProcessOneNode: cdata copy failed\n");
1986 }
1987 }
1988 break;
1989 case XML_TEXT_NODE:
1990 template = xsltGetTemplate(ctxt, cur, NULL);
1991 if (template) {
1992#ifdef WITH_XSLT_DEBUG_PROCESS
1994 "xsltDefaultProcessOneNode: applying template for text %s\n",
1995 cur->content));
1996#endif
1997 ctxt->xpathCtxt->contextSize = nbchild;
1998 ctxt->xpathCtxt->proximityPosition = childno;
1999 /*
2000 * Instantiate the xsl:template.
2001 */
2002 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2003 template, params);
2004 } else /* if (ctxt->mode == NULL) */ {
2005#ifdef WITH_XSLT_DEBUG_PROCESS
2006 if (cur->content == NULL) {
2008 "xsltDefaultProcessOneNode: copy empty text\n"));
2009 } else {
2011 "xsltDefaultProcessOneNode: copy text %s\n",
2012 cur->content));
2013 }
2014#endif
2015 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2016 if (copy == NULL) {
2018 "xsltDefaultProcessOneNode: text copy failed\n");
2019 }
2020 }
2021 break;
2022 case XML_PI_NODE:
2023 case XML_COMMENT_NODE:
2024 template = xsltGetTemplate(ctxt, cur, NULL);
2025 if (template) {
2026#ifdef WITH_XSLT_DEBUG_PROCESS
2027 if (cur->type == XML_PI_NODE) {
2029 "xsltDefaultProcessOneNode: template found for PI %s\n",
2030 cur->name));
2031 } else if (cur->type == XML_COMMENT_NODE) {
2033 "xsltDefaultProcessOneNode: template found for comment\n"));
2034 }
2035#endif
2036 ctxt->xpathCtxt->contextSize = nbchild;
2037 ctxt->xpathCtxt->proximityPosition = childno;
2038 /*
2039 * Instantiate the xsl:template.
2040 */
2041 xsltApplyXSLTTemplate(ctxt, cur, template->content,
2042 template, params);
2043 }
2044 break;
2045 default:
2046 break;
2047 }
2048 cur = cur->next;
2049 }
2050 ctxt->xpathCtxt->contextSize = oldSize;
2051 ctxt->xpathCtxt->proximityPosition = oldPos;
2052}
2053
2063void
2065 xsltStackElemPtr withParams)
2066{
2067 xsltTemplatePtr templ;
2068 xmlNodePtr oldNode;
2069
2070 templ = xsltGetTemplate(ctxt, contextNode, NULL);
2071 /*
2072 * If no template is found, apply the default rule.
2073 */
2074 if (templ == NULL) {
2075#ifdef WITH_XSLT_DEBUG_PROCESS
2076 if (contextNode->type == XML_DOCUMENT_NODE) {
2078 "xsltProcessOneNode: no template found for /\n"));
2079 } else if (contextNode->type == XML_CDATA_SECTION_NODE) {
2081 "xsltProcessOneNode: no template found for CDATA\n"));
2082 } else if (contextNode->type == XML_ATTRIBUTE_NODE) {
2084 "xsltProcessOneNode: no template found for attribute %s\n",
2085 ((xmlAttrPtr) contextNode)->name));
2086 } else {
2088 "xsltProcessOneNode: no template found for %s\n", contextNode->name));
2089 }
2090#endif
2091 oldNode = ctxt->node;
2092 ctxt->node = contextNode;
2093 xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
2094 ctxt->node = oldNode;
2095 return;
2096 }
2097
2098 if (contextNode->type == XML_ATTRIBUTE_NODE) {
2099 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2100 /*
2101 * Set the "current template rule".
2102 */
2103 ctxt->currentTemplateRule = templ;
2104
2105#ifdef WITH_XSLT_DEBUG_PROCESS
2107 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2108 templ->match, contextNode->name));
2109#endif
2110 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2111
2112 ctxt->currentTemplateRule = oldCurTempRule;
2113 } else {
2114 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2115 /*
2116 * Set the "current template rule".
2117 */
2118 ctxt->currentTemplateRule = templ;
2119
2120#ifdef WITH_XSLT_DEBUG_PROCESS
2121 if (contextNode->type == XML_DOCUMENT_NODE) {
2123 "xsltProcessOneNode: applying template '%s' for /\n",
2124 templ->match));
2125 } else {
2127 "xsltProcessOneNode: applying template '%s' for %s\n",
2128 templ->match, contextNode->name));
2129 }
2130#endif
2131 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2132
2133 ctxt->currentTemplateRule = oldCurTempRule;
2134 }
2135}
2136
2137#ifdef WITH_DEBUGGER
2138static xmlNodePtr
2139xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2140 xmlNodePtr contextNode,
2142 xsltTemplatePtr templ,
2143 int *addCallResult)
2144{
2145 xmlNodePtr debugedNode = NULL;
2146
2147 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2148 if (templ) {
2149 *addCallResult = xslAddCall(templ, templ->elem);
2150 } else {
2151 *addCallResult = xslAddCall(NULL, list);
2152 }
2153 switch (ctxt->debugStatus) {
2155 case XSLT_DEBUG_QUIT:
2156 if (*addCallResult)
2157 xslDropCall();
2158 return(NULL);
2159 }
2160 if (templ) {
2161 xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2162 debugedNode = templ->elem;
2163 } else if (list) {
2164 xslHandleDebugger(list, contextNode, templ, ctxt);
2165 debugedNode = list;
2166 } else if (ctxt->inst) {
2167 xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2168 debugedNode = ctxt->inst;
2169 }
2170 }
2171 return(debugedNode);
2172}
2173#endif /* WITH_DEBUGGER */
2174
2187int
2190 int level)
2191{
2192 if (ctxt->varsMax == 0) {
2193 ctxt->varsMax = 10;
2194 ctxt->varsTab =
2196 sizeof(ctxt->varsTab[0]));
2197 if (ctxt->varsTab == NULL) {
2198 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
2199 return (-1);
2200 }
2201 }
2202 if (ctxt->varsNr >= ctxt->varsMax) {
2203 ctxt->varsMax *= 2;
2204 ctxt->varsTab =
2206 ctxt->varsMax *
2207 sizeof(ctxt->varsTab[0]));
2208 if (ctxt->varsTab == NULL) {
2209 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2210 return (-1);
2211 }
2212 }
2213 ctxt->varsTab[ctxt->varsNr++] = variable;
2214 ctxt->vars = variable;
2215 variable->level = level;
2216 return(0);
2217}
2218
2225static void
2227{
2228 xmlDocPtr cur = ctxt->localRVT, tmp;
2229
2230 if (cur == base)
2231 return;
2232 if (cur->prev != NULL)
2233 xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
2234
2235 /* Reset localRVT early because some RVTs might be registered again. */
2236 ctxt->localRVT = base;
2237 if (base != NULL)
2238 base->prev = NULL;
2239
2240 do {
2241 tmp = cur;
2242 cur = (xmlDocPtr) cur->next;
2243 if (tmp->psvi == XSLT_RVT_LOCAL) {
2244 xsltReleaseRVT(ctxt, tmp);
2245 } else if (tmp->psvi == XSLT_RVT_GLOBAL) {
2246 xsltRegisterPersistRVT(ctxt, tmp);
2247 } else if (tmp->psvi == XSLT_RVT_FUNC_RESULT) {
2248 /*
2249 * This will either register the RVT again or move it to the
2250 * context variable.
2251 */
2252 xsltRegisterLocalRVT(ctxt, tmp);
2253 tmp->psvi = XSLT_RVT_FUNC_RESULT;
2254 } else {
2256 "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2257 tmp->psvi);
2258 }
2259 } while (cur != base);
2260}
2261
2277static void
2279 xmlNodePtr contextNode, xmlNodePtr list,
2280 xsltTemplatePtr templ)
2281{
2282 xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2284 int level = 0, oldVarsNr;
2285 xmlDocPtr oldLocalFragmentTop;
2286
2287#ifdef XSLT_REFACTORED
2289#endif
2290
2291#ifdef WITH_DEBUGGER
2292 int addCallResult = 0;
2293 xmlNodePtr debuggedNode = NULL;
2294#endif
2295
2296 if (ctxt == NULL)
2297 return;
2298
2299#ifdef WITH_DEBUGGER
2300 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2301 debuggedNode =
2302 xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2303 list, templ, &addCallResult);
2304 if (debuggedNode == NULL)
2305 return;
2306 }
2307#endif
2308
2309 if (list == NULL)
2310 return;
2312
2313 /*
2314 * Check for infinite recursion: stop if the maximum of nested templates
2315 * is excceeded. Adjust xsltMaxDepth if you need more.
2316 */
2317 if (ctxt->depth >= ctxt->maxTemplateDepth) {
2319 "xsltApplySequenceConstructor: A potential infinite template "
2320 "recursion was detected.\n"
2321 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2322 "raise the maximum number of nested template calls and "
2323 "variables/params (currently set to %d).\n",
2324 ctxt->maxTemplateDepth);
2325 xsltDebug(ctxt, contextNode, list, NULL);
2326 ctxt->state = XSLT_STATE_STOPPED;
2327 return;
2328 }
2329 ctxt->depth++;
2330
2331 oldLocalFragmentTop = ctxt->localRVT;
2332 oldInsert = insert = ctxt->insert;
2333 oldInst = oldCurInst = ctxt->inst;
2334 oldContextNode = ctxt->node;
2335 /*
2336 * Save current number of variables on the stack; new vars are popped when
2337 * exiting.
2338 */
2339 oldVarsNr = ctxt->varsNr;
2340 /*
2341 * Process the sequence constructor.
2342 */
2343 cur = list;
2344 while (cur != NULL) {
2345 if (ctxt->opLimit != 0) {
2346 if (ctxt->opCount >= ctxt->opLimit) {
2348 "xsltApplySequenceConstructor: "
2349 "Operation limit exceeded\n");
2350 ctxt->state = XSLT_STATE_STOPPED;
2351 goto error;
2352 }
2353 ctxt->opCount += 1;
2354 }
2355
2356 ctxt->inst = cur;
2357
2358#ifdef WITH_DEBUGGER
2359 switch (ctxt->debugStatus) {
2361 case XSLT_DEBUG_QUIT:
2362 break;
2363
2364 }
2365#endif
2366 /*
2367 * Test; we must have a valid insertion point.
2368 */
2369 if (insert == NULL) {
2370
2371#ifdef WITH_XSLT_DEBUG_PROCESS
2373 "xsltApplySequenceConstructor: insert == NULL !\n"));
2374#endif
2375 goto error;
2376 }
2377
2378#ifdef WITH_DEBUGGER
2379 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2380 xslHandleDebugger(cur, contextNode, templ, ctxt);
2381#endif
2382
2383#ifdef XSLT_REFACTORED
2384 if (cur->type == XML_ELEMENT_NODE) {
2385 info = (xsltStylePreCompPtr) cur->psvi;
2386 /*
2387 * We expect a compiled representation on:
2388 * 1) XSLT instructions of this XSLT version (1.0)
2389 * (with a few exceptions)
2390 * 2) Literal result elements
2391 * 3) Extension instructions
2392 * 4) XSLT instructions of future XSLT versions
2393 * (forwards-compatible mode).
2394 */
2395 if (info == NULL) {
2396 /*
2397 * Handle the rare cases where we don't expect a compiled
2398 * representation on an XSLT element.
2399 */
2400 if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2401 xsltMessage(ctxt, contextNode, cur);
2402 goto skip_children;
2403 }
2404 /*
2405 * Something really went wrong:
2406 */
2408 "Internal error in xsltApplySequenceConstructor(): "
2409 "The element '%s' in the stylesheet has no compiled "
2410 "representation.\n",
2411 cur->name);
2412 goto skip_children;
2413 }
2414
2415 if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2416 xsltStyleItemLRElementInfoPtr lrInfo =
2417 (xsltStyleItemLRElementInfoPtr) info;
2418 /*
2419 * Literal result elements
2420 * --------------------------------------------------------
2421 */
2422#ifdef WITH_XSLT_DEBUG_PROCESS
2425 "xsltApplySequenceConstructor: copy literal result "
2426 "element '%s'\n", cur->name));
2427#endif
2428 /*
2429 * Copy the raw element-node.
2430 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2431 * == NULL)
2432 * goto error;
2433 */
2434 copy = xmlDocCopyNode(cur, insert->doc, 0);
2435 if (copy == NULL) {
2437 "Internal error in xsltApplySequenceConstructor(): "
2438 "Failed to copy literal result element '%s'.\n",
2439 cur->name);
2440 goto error;
2441 } else {
2442 /*
2443 * Add the element-node to the result tree.
2444 */
2445 copy->doc = ctxt->output;
2447 /*
2448 * Create effective namespaces declarations.
2449 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2450 */
2451 if (lrInfo->effectiveNs != NULL) {
2452 xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2453 xmlNsPtr ns, lastns = NULL;
2454
2455 while (effNs != NULL) {
2456 /*
2457 * Avoid generating redundant namespace
2458 * declarations; thus lookup if there is already
2459 * such a ns-decl in the result.
2460 */
2461 ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2462 if ((ns != NULL) &&
2463 (xmlStrEqual(ns->href, effNs->nsName)))
2464 {
2465 effNs = effNs->next;
2466 continue;
2467 }
2468 ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2469 if (ns == NULL) {
2471 "Internal error in "
2472 "xsltApplySequenceConstructor(): "
2473 "Failed to copy a namespace "
2474 "declaration.\n");
2475 goto error;
2476 }
2477
2478 if (lastns == NULL)
2479 copy->nsDef = ns;
2480 else
2481 lastns->next =ns;
2482 lastns = ns;
2483
2484 effNs = effNs->next;
2485 }
2486
2487 }
2488 /*
2489 * NOTE that we don't need to apply ns-alising: this was
2490 * already done at compile-time.
2491 */
2492 if (cur->ns != NULL) {
2493 /*
2494 * If there's no such ns-decl in the result tree,
2495 * then xsltGetSpecialNamespace() will
2496 * create a ns-decl on the copied node.
2497 */
2498 copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2499 cur->ns->href, cur->ns->prefix, copy);
2500 } else {
2501 /*
2502 * Undeclare the default namespace if needed.
2503 * This can be skipped, if the result element has
2504 * no ns-decls, in which case the result element
2505 * obviously does not declare a default namespace;
2506 * AND there's either no parent, or the parent
2507 * element is in no namespace; this means there's no
2508 * default namespace is scope to care about.
2509 *
2510 * REVISIT: This might result in massive
2511 * generation of ns-decls if nodes in a default
2512 * namespaces are mixed with nodes in no namespace.
2513 *
2514 */
2515 if (copy->nsDef ||
2516 ((insert != NULL) &&
2517 (insert->type == XML_ELEMENT_NODE) &&
2518 (insert->ns != NULL)))
2519 {
2521 NULL, NULL, copy);
2522 }
2523 }
2524 }
2525 /*
2526 * SPEC XSLT 2.0 "Each attribute of the literal result
2527 * element, other than an attribute in the XSLT namespace,
2528 * is processed to produce an attribute for the element in
2529 * the result tree."
2530 * NOTE: See bug #341325.
2531 */
2532 if (cur->properties != NULL) {
2533 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2534 }
2535 } else if (IS_XSLT_ELEM_FAST(cur)) {
2536 /*
2537 * XSLT instructions
2538 * --------------------------------------------------------
2539 */
2540 if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2541 /*
2542 * We hit an unknown XSLT element.
2543 * Try to apply one of the fallback cases.
2544 */
2545 ctxt->insert = insert;
2546 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2548 "The is no fallback behaviour defined for "
2549 "the unknown XSLT element '%s'.\n",
2550 cur->name);
2551 }
2552 ctxt->insert = oldInsert;
2553 } else if (info->func != NULL) {
2554 /*
2555 * Execute the XSLT instruction.
2556 */
2557 ctxt->insert = insert;
2558
2559 info->func(ctxt, contextNode, cur,
2561
2562 /*
2563 * Cleanup temporary tree fragments.
2564 */
2565 if (oldLocalFragmentTop != ctxt->localRVT)
2566 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2567
2568 ctxt->insert = oldInsert;
2569 } else if (info->type == XSLT_FUNC_VARIABLE) {
2570 xsltStackElemPtr tmpvar = ctxt->vars;
2571
2573
2574 if (tmpvar != ctxt->vars) {
2575 /*
2576 * TODO: Using a @tmpvar is an annoying workaround, but
2577 * the current mechanisms do not provide any other way
2578 * of knowing if the var was really pushed onto the
2579 * stack.
2580 */
2581 ctxt->vars->level = level;
2582 }
2583 } else if (info->type == XSLT_FUNC_MESSAGE) {
2584 /*
2585 * TODO: Won't be hit, since we don't compile xsl:message.
2586 */
2587 xsltMessage(ctxt, contextNode, cur);
2588 } else {
2590 "Unexpected XSLT element '%s'.\n", cur->name);
2591 }
2592 goto skip_children;
2593
2594 } else {
2596 /*
2597 * Extension intructions (elements)
2598 * --------------------------------------------------------
2599 */
2600 if (cur->psvi == xsltExtMarker) {
2601 /*
2602 * The xsltExtMarker was set during the compilation
2603 * of extension instructions if there was no registered
2604 * handler for this specific extension function at
2605 * compile-time.
2606 * Libxslt will now lookup if a handler is
2607 * registered in the context of this transformation.
2608 */
2609 func = xsltExtElementLookup(ctxt, cur->name,
2610 cur->ns->href);
2611 } else
2612 func = ((xsltElemPreCompPtr) cur->psvi)->func;
2613
2614 if (func == NULL) {
2615 /*
2616 * No handler available.
2617 * Try to execute fallback behaviour via xsl:fallback.
2618 */
2619#ifdef WITH_XSLT_DEBUG_PROCESS
2622 "xsltApplySequenceConstructor: unknown extension %s\n",
2623 cur->name));
2624#endif
2625 ctxt->insert = insert;
2626 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2628 "Unknown extension instruction '{%s}%s'.\n",
2629 cur->ns->href, cur->name);
2630 }
2631 ctxt->insert = oldInsert;
2632 } else {
2633 /*
2634 * Execute the handler-callback.
2635 */
2636#ifdef WITH_XSLT_DEBUG_PROCESS
2638 "xsltApplySequenceConstructor: extension construct %s\n",
2639 cur->name));
2640#endif
2641 /*
2642 * Disable the xsltCopyTextString optimization for
2643 * extension elements. Extensions could append text using
2644 * xmlAddChild which will free the buffer pointed to by
2645 * 'lasttext'. This buffer could later be reallocated with
2646 * a different size than recorded in 'lasttsize'. See bug
2647 * #777432.
2648 */
2649 if (cur->psvi == xsltExtMarker) {
2650 ctxt->lasttext = NULL;
2651 }
2652
2653 ctxt->insert = insert;
2654
2655 func(ctxt, contextNode, cur, cur->psvi);
2656
2657 /*
2658 * Cleanup temporary tree fragments.
2659 */
2660 if (oldLocalFragmentTop != ctxt->localRVT)
2661 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2662
2663 ctxt->insert = oldInsert;
2664 }
2665 goto skip_children;
2666 }
2667
2668 } else if (XSLT_IS_TEXT_NODE(cur)) {
2669 /*
2670 * Text
2671 * ------------------------------------------------------------
2672 */
2673#ifdef WITH_XSLT_DEBUG_PROCESS
2674 if (cur->name == xmlStringTextNoenc) {
2677 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2678 cur->content));
2679 } else {
2682 "xsltApplySequenceConstructor: copy text '%s'\n",
2683 cur->content));
2684 }
2685#endif
2686 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2687 goto error;
2688 }
2689
2690#else /* XSLT_REFACTORED */
2691
2692 if (IS_XSLT_ELEM(cur)) {
2693 /*
2694 * This is an XSLT node
2695 */
2697
2698 if (info == NULL) {
2699 if (IS_XSLT_NAME(cur, "message")) {
2700 xsltMessage(ctxt, contextNode, cur);
2701 } else {
2702 /*
2703 * That's an error try to apply one of the fallback cases
2704 */
2705 ctxt->insert = insert;
2706 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2708 "xsltApplySequenceConstructor: %s was not compiled\n",
2709 cur->name);
2710 }
2711 ctxt->insert = oldInsert;
2712 }
2713 goto skip_children;
2714 }
2715
2716 if (info->func != NULL) {
2717 oldCurInst = ctxt->inst;
2718 ctxt->inst = cur;
2719 ctxt->insert = insert;
2720
2721 info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2722
2723 /*
2724 * Cleanup temporary tree fragments.
2725 */
2726 if (oldLocalFragmentTop != ctxt->localRVT)
2727 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2728
2729 ctxt->insert = oldInsert;
2730 ctxt->inst = oldCurInst;
2731 goto skip_children;
2732 }
2733
2734 if (IS_XSLT_NAME(cur, "variable")) {
2735 xsltStackElemPtr tmpvar = ctxt->vars;
2736
2737 oldCurInst = ctxt->inst;
2738 ctxt->inst = cur;
2739
2741
2742 ctxt->inst = oldCurInst;
2743
2744 if (tmpvar != ctxt->vars) {
2745 /*
2746 * TODO: Using a @tmpvar is an annoying workaround, but
2747 * the current mechanisms do not provide any other way
2748 * of knowing if the var was really pushed onto the
2749 * stack.
2750 */
2751 ctxt->vars->level = level;
2752 }
2753 } else if (IS_XSLT_NAME(cur, "message")) {
2754 xsltMessage(ctxt, contextNode, cur);
2755 } else {
2757 "Unexpected XSLT element '%s'.\n", cur->name);
2758 }
2759 goto skip_children;
2760 } else if ((cur->type == XML_TEXT_NODE) ||
2761 (cur->type == XML_CDATA_SECTION_NODE)) {
2762
2763 /*
2764 * This text comes from the stylesheet
2765 * For stylesheets, the set of whitespace-preserving
2766 * element names consists of just xsl:text.
2767 */
2768#ifdef WITH_XSLT_DEBUG_PROCESS
2769 if (cur->type == XML_CDATA_SECTION_NODE) {
2771 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2772 cur->content));
2773 } else if (cur->name == xmlStringTextNoenc) {
2775 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2776 cur->content));
2777 } else {
2779 "xsltApplySequenceConstructor: copy text %s\n",
2780 cur->content));
2781 }
2782#endif
2783 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2784 goto error;
2785 } else if ((cur->type == XML_ELEMENT_NODE) &&
2786 (cur->ns != NULL) && (cur->psvi != NULL)) {
2787 xsltTransformFunction function;
2788
2789 oldCurInst = ctxt->inst;
2790 ctxt->inst = cur;
2791 /*
2792 * Flagged as an extension element
2793 */
2794 if (cur->psvi == xsltExtMarker)
2795 function = xsltExtElementLookup(ctxt, cur->name,
2796 cur->ns->href);
2797 else
2798 function = ((xsltElemPreCompPtr) cur->psvi)->func;
2799
2800 if (function == NULL) {
2802 int found = 0;
2803
2804#ifdef WITH_XSLT_DEBUG_PROCESS
2806 "xsltApplySequenceConstructor: unknown extension %s\n",
2807 cur->name));
2808#endif
2809 /*
2810 * Search if there are fallbacks
2811 */
2812 ctxt->insert = insert;
2813 child = cur->children;
2814 while (child != NULL) {
2815 if ((IS_XSLT_ELEM(child)) &&
2816 (IS_XSLT_NAME(child, "fallback")))
2817 {
2818 found = 1;
2819 xsltApplySequenceConstructor(ctxt, contextNode,
2820 child->children, NULL);
2821 }
2822 child = child->next;
2823 }
2824 ctxt->insert = oldInsert;
2825
2826 if (!found) {
2828 "xsltApplySequenceConstructor: failed to find extension %s\n",
2829 cur->name);
2830 }
2831 } else {
2832#ifdef WITH_XSLT_DEBUG_PROCESS
2834 "xsltApplySequenceConstructor: extension construct %s\n",
2835 cur->name));
2836#endif
2837
2838 /*
2839 * Disable the xsltCopyTextString optimization for
2840 * extension elements. Extensions could append text using
2841 * xmlAddChild which will free the buffer pointed to by
2842 * 'lasttext'. This buffer could later be reallocated with
2843 * a different size than recorded in 'lasttsize'. See bug
2844 * #777432.
2845 */
2846 if (cur->psvi == xsltExtMarker) {
2847 ctxt->lasttext = NULL;
2848 }
2849
2850 ctxt->insert = insert;
2851
2852 function(ctxt, contextNode, cur, cur->psvi);
2853 /*
2854 * Cleanup temporary tree fragments.
2855 */
2856 if (oldLocalFragmentTop != ctxt->localRVT)
2857 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2858
2859 ctxt->insert = oldInsert;
2860
2861 }
2862 ctxt->inst = oldCurInst;
2863 goto skip_children;
2864 } else if (cur->type == XML_ELEMENT_NODE) {
2865#ifdef WITH_XSLT_DEBUG_PROCESS
2867 "xsltApplySequenceConstructor: copy node %s\n",
2868 cur->name));
2869#endif
2870 oldCurInst = ctxt->inst;
2871 ctxt->inst = cur;
2872
2873 if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2874 goto error;
2875 /*
2876 * Add extra namespaces inherited from the current template
2877 * if we are in the first level children and this is a
2878 * "real" template.
2879 */
2880 if ((templ != NULL) && (oldInsert == insert) &&
2881 (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2882 int i;
2883 xmlNsPtr ns, ret;
2884
2885 for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2886 const xmlChar *URI = NULL;
2888 ns = ctxt->templ->inheritedNs[i];
2889
2890 /* Note that the XSLT namespace was already excluded
2891 * in xsltGetInheritedNsList().
2892 */
2893#if 0
2894 if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2895 continue;
2896#endif
2897 style = ctxt->style;
2898 while (style != NULL) {
2899 if (style->nsAliases != NULL)
2900 URI = (const xmlChar *)
2901 xmlHashLookup(style->nsAliases, ns->href);
2902 if (URI != NULL)
2903 break;
2904
2906 }
2907 if (URI == UNDEFINED_DEFAULT_NS)
2908 continue;
2909 if (URI == NULL)
2910 URI = ns->href;
2911 /*
2912 * TODO: The following will still be buggy for the
2913 * non-refactored code.
2914 */
2915 ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2916 if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2917 {
2918 xmlNewNs(copy, URI, ns->prefix);
2919 }
2920 }
2921 if (copy->ns != NULL) {
2922 /*
2923 * Fix the node namespace if needed
2924 */
2925 copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2926 }
2927 }
2928 /*
2929 * all the attributes are directly inherited
2930 */
2931 if (cur->properties != NULL) {
2932 xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2933 }
2934 ctxt->inst = oldCurInst;
2935 }
2936#endif /* else of XSLT_REFACTORED */
2937
2938 /*
2939 * Descend into content in document order.
2940 */
2941 if (cur->children != NULL) {
2942 if (cur->children->type != XML_ENTITY_DECL) {
2943 cur = cur->children;
2944 level++;
2945 if (copy != NULL)
2946 insert = copy;
2947 continue;
2948 }
2949 }
2950
2951skip_children:
2952 /*
2953 * If xslt:message was just processed, we might have hit a
2954 * terminate='yes'; if so, then break the loop and clean up.
2955 * TODO: Do we need to check this also before trying to descend
2956 * into the content?
2957 */
2958 if (ctxt->state == XSLT_STATE_STOPPED)
2959 break;
2960 if (cur->next != NULL) {
2961 cur = cur->next;
2962 continue;
2963 }
2964
2965 do {
2966 cur = cur->parent;
2967 level--;
2968 /*
2969 * Pop variables/params (xsl:variable and xsl:param).
2970 */
2971 if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
2972 xsltLocalVariablePop(ctxt, oldVarsNr, level);
2973 }
2974
2975 insert = insert->parent;
2976 if (cur == NULL)
2977 break;
2978 if (cur == list->parent) {
2979 cur = NULL;
2980 break;
2981 }
2982 if (cur->next != NULL) {
2983 cur = cur->next;
2984 break;
2985 }
2986 } while (cur != NULL);
2987 }
2988
2989error:
2990 /*
2991 * In case of errors: pop remaining variables.
2992 */
2993 if (ctxt->varsNr > oldVarsNr)
2994 xsltLocalVariablePop(ctxt, oldVarsNr, -1);
2995
2996 ctxt->node = oldContextNode;
2997 ctxt->inst = oldInst;
2998 ctxt->insert = oldInsert;
2999
3000 ctxt->depth--;
3001
3002#ifdef WITH_DEBUGGER
3003 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3004 xslDropCall();
3005 }
3006#endif
3007}
3008
3009/*
3010* xsltApplyXSLTTemplate:
3011* @ctxt: a XSLT transformation context
3012* @contextNode: the node in the source tree.
3013* @list: the nodes of a sequence constructor;
3014* (plus leading xsl:param elements)
3015* @templ: the compiled xsl:template declaration;
3016* NULL if a sequence constructor
3017* @withParams: a set of caller-parameters (xsl:with-param) or NULL
3018*
3019* Called by:
3020* - xsltApplyImports()
3021* - xsltCallTemplate()
3022* - xsltDefaultProcessOneNode()
3023* - xsltProcessOneNode()
3024*/
3025static void
3027 xmlNodePtr contextNode,
3029 xsltTemplatePtr templ,
3030 xsltStackElemPtr withParams)
3031{
3032 int oldVarsBase = 0;
3034 xsltStackElemPtr tmpParam = NULL;
3035 xmlDocPtr oldUserFragmentTop;
3036#ifdef WITH_PROFILER
3037 long start = 0;
3038#endif
3039
3040#ifdef XSLT_REFACTORED
3041 xsltStyleItemParamPtr iparam;
3042#else
3043 xsltStylePreCompPtr iparam;
3044#endif
3045
3046#ifdef WITH_DEBUGGER
3047 int addCallResult = 0;
3048#endif
3049
3050 if (ctxt == NULL)
3051 return;
3052 if (templ == NULL) {
3054 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3055 return;
3056 }
3057
3058#ifdef WITH_DEBUGGER
3059 if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
3060 if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
3061 list, templ, &addCallResult) == NULL)
3062 return;
3063 }
3064#endif
3065
3066 if (list == NULL)
3067 return;
3069
3070 if (ctxt->varsNr >= ctxt->maxTemplateVars)
3071 {
3073 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3074 "was detected.\n"
3075 "You can adjust maxTemplateVars (--maxvars) in order to "
3076 "raise the maximum number of variables/params (currently set to %d).\n",
3077 ctxt->maxTemplateVars);
3078 xsltDebug(ctxt, contextNode, list, NULL);
3079 ctxt->state = XSLT_STATE_STOPPED;
3080 return;
3081 }
3082
3083 oldUserFragmentTop = ctxt->tmpRVT;
3084 ctxt->tmpRVT = NULL;
3085
3086 /*
3087 * Initiate a distinct scope of local params/variables.
3088 */
3089 oldVarsBase = ctxt->varsBase;
3090 ctxt->varsBase = ctxt->varsNr;
3091
3092 ctxt->node = contextNode;
3093
3094#ifdef WITH_PROFILER
3095 if (ctxt->profile) {
3096 templ->nbCalls++;
3097 start = xsltTimestamp();
3098 profPush(ctxt, 0);
3099 profCallgraphAdd(templ, ctxt->templ);
3100 }
3101#endif
3102
3103 /*
3104 * Push the xsl:template declaration onto the stack.
3105 */
3106 templPush(ctxt, templ);
3107
3108#ifdef WITH_XSLT_DEBUG_PROCESS
3109 if (templ->name != NULL)
3111 "applying xsl:template '%s'\n", templ->name));
3112#endif
3113 /*
3114 * Process xsl:param instructions and skip those elements for
3115 * further processing.
3116 */
3117 cur = list;
3118 do {
3119 if (cur->type == XML_TEXT_NODE) {
3120 cur = cur->next;
3121 continue;
3122 }
3123 if ((cur->type != XML_ELEMENT_NODE) ||
3124 (cur->name[0] != 'p') ||
3125 (cur->psvi == NULL) ||
3126 (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
3127 (! IS_XSLT_ELEM(cur)))
3128 {
3129 break;
3130 }
3131
3132 list = cur->next;
3133
3134#ifdef XSLT_REFACTORED
3135 iparam = (xsltStyleItemParamPtr) cur->psvi;
3136#else
3137 iparam = (xsltStylePreCompPtr) cur->psvi;
3138#endif
3139
3140 /*
3141 * Substitute xsl:param for a given xsl:with-param.
3142 * Since the XPath expression will reference the params/vars
3143 * by index, we need to slot the xsl:with-params in the
3144 * order of encountered xsl:params to keep the sequence of
3145 * params/variables in the stack exactly as it was at
3146 * compile time,
3147 */
3148 tmpParam = NULL;
3149 if (withParams) {
3150 tmpParam = withParams;
3151 do {
3152 if ((tmpParam->name == (iparam->name)) &&
3153 (tmpParam->nameURI == (iparam->ns)))
3154 {
3155 /*
3156 * Push the caller-parameter.
3157 */
3158 xsltLocalVariablePush(ctxt, tmpParam, -1);
3159 break;
3160 }
3161 tmpParam = tmpParam->next;
3162 } while (tmpParam != NULL);
3163 }
3164 /*
3165 * Push the xsl:param.
3166 */
3167 if (tmpParam == NULL) {
3168 /*
3169 * Note that we must assume that the added parameter
3170 * has a @depth of 0.
3171 */
3173 }
3174 cur = cur->next;
3175 } while (cur != NULL);
3176 /*
3177 * Process the sequence constructor.
3178 */
3179 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3180
3181 /*
3182 * Remove remaining xsl:param and xsl:with-param items from
3183 * the stack. Don't free xsl:with-param items.
3184 */
3185 if (ctxt->varsNr > ctxt->varsBase)
3187 ctxt->varsBase = oldVarsBase;
3188
3189 /*
3190 * Release user-created fragments stored in the scope
3191 * of xsl:template. Note that this mechanism is deprecated:
3192 * user code should now use xsltRegisterLocalRVT() instead
3193 * of the obsolete xsltRegisterTmpRVT().
3194 */
3195 if (ctxt->tmpRVT) {
3196 xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3197
3198 while (curdoc != NULL) {
3199 tmp = curdoc;
3200 curdoc = (xmlDocPtr) curdoc->next;
3201 xsltReleaseRVT(ctxt, tmp);
3202 }
3203 }
3204 ctxt->tmpRVT = oldUserFragmentTop;
3205
3206 /*
3207 * Pop the xsl:template declaration from the stack.
3208 */
3209 templPop(ctxt);
3210
3211#ifdef WITH_PROFILER
3212 if (ctxt->profile) {
3213 long spent, child, total, end;
3214
3215 end = xsltTimestamp();
3216 child = profPop(ctxt);
3217 total = end - start;
3218 spent = total - child;
3219 if (spent <= 0) {
3220 /*
3221 * Not possible unless the original calibration failed
3222 * we can try to correct it on the fly.
3223 */
3224 xsltCalibrateAdjust(spent);
3225 spent = 0;
3226 }
3227
3228 templ->time += spent;
3229 if (ctxt->profNr > 0)
3230 ctxt->profTab[ctxt->profNr - 1] += total;
3231 }
3232#endif
3233
3234#ifdef WITH_DEBUGGER
3235 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3236 xslDropCall();
3237 }
3238#endif
3239}
3240
3241
3272void
3274 xmlNodePtr contextNode,
3278{
3279 if ((ctxt == NULL) || (list == NULL))
3280 return;
3282
3283 if (params) {
3284 /*
3285 * This code should be obsolete - was previously used
3286 * by libexslt/functions.c, but due to bug 381319 the
3287 * logic there was changed.
3288 */
3289 int oldVarsNr = ctxt->varsNr;
3290
3291 /*
3292 * Push the given xsl:param(s) onto the variable stack.
3293 */
3294 while (params != NULL) {
3295 xsltLocalVariablePush(ctxt, params, -1);
3296 params = params->next;
3297 }
3298 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3299 /*
3300 * Pop the given xsl:param(s) from the stack but don't free them.
3301 */
3302 xsltLocalVariablePop(ctxt, oldVarsNr, -2);
3303 } else
3304 xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3305}
3306
3307/************************************************************************
3308 * *
3309 * XSLT-1.1 extensions *
3310 * *
3311 ************************************************************************/
3312
3322void
3324 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3325{
3326#ifdef XSLT_REFACTORED
3327 xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
3328#else
3329 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3330#endif
3332 int ret;
3333 xmlChar *filename = NULL, *prop, *elements;
3334 xmlChar *element, *end;
3335 xmlDocPtr res = NULL;
3336 xmlDocPtr oldOutput;
3337 xmlNodePtr oldInsert, root;
3338 const char *oldOutputFile;
3339 xsltOutputType oldType;
3340 xmlChar *URL = NULL;
3341 const xmlChar *method;
3342 const xmlChar *doctypePublic;
3343 const xmlChar *doctypeSystem;
3344 const xmlChar *version;
3345 const xmlChar *encoding;
3346 int redirect_write_append = 0;
3347
3348 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
3349 return;
3350
3351 if (comp->filename == NULL) {
3352
3353 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
3354 /*
3355 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3356 * (http://icl.com/saxon)
3357 * The @file is in no namespace.
3358 */
3359#ifdef WITH_XSLT_DEBUG_EXTRA
3361 "Found saxon:output extension\n");
3362#endif
3363 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3364 (const xmlChar *) "file",
3366
3367 if (URL == NULL)
3368 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3369 (const xmlChar *) "href",
3371 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
3372#ifdef WITH_XSLT_DEBUG_EXTRA
3374 "Found xalan:write extension\n");
3375#endif
3376 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3377 (const xmlChar *)
3378 "select",
3380 if (URL != NULL) {
3381 xmlXPathCompExprPtr cmp;
3382 xmlChar *val;
3383
3384 /*
3385 * Trying to handle bug #59212
3386 * The value of the "select" attribute is an
3387 * XPath expression.
3388 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3389 */
3390 cmp = xmlXPathCtxtCompile(ctxt->xpathCtxt, URL);
3391 val = xsltEvalXPathString(ctxt, cmp);
3392 xmlXPathFreeCompExpr(cmp);
3393 xmlFree(URL);
3394 URL = val;
3395 }
3396 if (URL == NULL)
3397 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3398 (const xmlChar *)
3399 "file",
3401 if (URL == NULL)
3402 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3403 (const xmlChar *)
3404 "href",
3406 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
3407 URL = xsltEvalAttrValueTemplate(ctxt, inst,
3408 (const xmlChar *) "href",
3409 NULL);
3410 }
3411
3412 } else {
3413 URL = xmlStrdup(comp->filename);
3414 }
3415
3416 if (URL == NULL) {
3417 xsltTransformError(ctxt, NULL, inst,
3418 "xsltDocumentElem: href/URI-Reference not found\n");
3419 return;
3420 }
3421
3422 /*
3423 * If the computation failed, it's likely that the URL wasn't escaped
3424 */
3425 filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
3426 if (filename == NULL) {
3427 xmlChar *escURL;
3428
3429 escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
3430 if (escURL != NULL) {
3431 filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
3432 xmlFree(escURL);
3433 }
3434 }
3435
3436 if (filename == NULL) {
3437 xsltTransformError(ctxt, NULL, inst,
3438 "xsltDocumentElem: URL computation failed for %s\n",
3439 URL);
3440 xmlFree(URL);
3441 return;
3442 }
3443
3444 /*
3445 * Security checking: can we write to this resource
3446 */
3447 if (ctxt->sec != NULL) {
3448 ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
3449 if (ret <= 0) {
3450 if (ret == 0)
3451 xsltTransformError(ctxt, NULL, inst,
3452 "xsltDocumentElem: write rights for %s denied\n",
3453 filename);
3454 xmlFree(URL);
3456 return;
3457 }
3458 }
3459
3460 oldOutputFile = ctxt->outputFile;
3461 oldOutput = ctxt->output;
3462 oldInsert = ctxt->insert;
3463 oldType = ctxt->type;
3464 ctxt->outputFile = (const char *) filename;
3465
3467 if (style == NULL) {
3468 xsltTransformError(ctxt, NULL, inst,
3469 "xsltDocumentElem: out of memory\n");
3470 goto error;
3471 }
3472
3473 /*
3474 * Version described in 1.1 draft allows full parameterization
3475 * of the output.
3476 */
3477 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3478 (const xmlChar *) "version",
3479 NULL);
3480 if (prop != NULL) {
3481 if (style->version != NULL)
3482 xmlFree(style->version);
3483 style->version = prop;
3484 }
3485 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3486 (const xmlChar *) "encoding",
3487 NULL);
3488 if (prop != NULL) {
3489 if (style->encoding != NULL)
3490 xmlFree(style->encoding);
3491 style->encoding = prop;
3492 }
3493 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3494 (const xmlChar *) "method",
3495 NULL);
3496 if (prop != NULL) {
3497 const xmlChar *URI;
3498
3499 if (style->method != NULL)
3500 xmlFree(style->method);
3501 style->method = NULL;
3502 if (style->methodURI != NULL)
3503 xmlFree(style->methodURI);
3504 style->methodURI = NULL;
3505
3506 URI = xsltGetQNameURI(inst, &prop);
3507 if (prop == NULL) {
3508 if (style != NULL) style->errors++;
3509 } else if (URI == NULL) {
3510 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3511 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
3512 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
3513 style->method = prop;
3514 } else {
3515 xsltTransformError(ctxt, NULL, inst,
3516 "invalid value for method: %s\n", prop);
3517 if (style != NULL) style->warnings++;
3518 }
3519 } else {
3520 style->method = prop;
3521 style->methodURI = xmlStrdup(URI);
3522 }
3523 }
3524 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3525 (const xmlChar *)
3526 "doctype-system", NULL);
3527 if (prop != NULL) {
3528 if (style->doctypeSystem != NULL)
3529 xmlFree(style->doctypeSystem);
3530 style->doctypeSystem = prop;
3531 }
3532 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3533 (const xmlChar *)
3534 "doctype-public", NULL);
3535 if (prop != NULL) {
3536 if (style->doctypePublic != NULL)
3537 xmlFree(style->doctypePublic);
3538 style->doctypePublic = prop;
3539 }
3540 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3541 (const xmlChar *) "standalone",
3542 NULL);
3543 if (prop != NULL) {
3544 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3545 style->standalone = 1;
3546 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3547 style->standalone = 0;
3548 } else {
3549 xsltTransformError(ctxt, NULL, inst,
3550 "invalid value for standalone: %s\n",
3551 prop);
3552 if (style != NULL) style->warnings++;
3553 }
3554 xmlFree(prop);
3555 }
3556
3557 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3558 (const xmlChar *) "indent",
3559 NULL);
3560 if (prop != NULL) {
3561 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3562 style->indent = 1;
3563 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3564 style->indent = 0;
3565 } else {
3566 xsltTransformError(ctxt, NULL, inst,
3567 "invalid value for indent: %s\n", prop);
3568 if (style != NULL) style->warnings++;
3569 }
3570 xmlFree(prop);
3571 }
3572
3573 prop = xsltEvalAttrValueTemplate(ctxt, inst,
3574 (const xmlChar *)
3575 "omit-xml-declaration",
3576 NULL);
3577 if (prop != NULL) {
3578 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3579 style->omitXmlDeclaration = 1;
3580 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3581 style->omitXmlDeclaration = 0;
3582 } else {
3583 xsltTransformError(ctxt, NULL, inst,
3584 "invalid value for omit-xml-declaration: %s\n",
3585 prop);
3586 if (style != NULL) style->warnings++;
3587 }
3588 xmlFree(prop);
3589 }
3590
3591 elements = xsltEvalAttrValueTemplate(ctxt, inst,
3592 (const xmlChar *)
3593 "cdata-section-elements",
3594 NULL);
3595 if (elements != NULL) {
3596 if (style->stripSpaces == NULL)
3597 style->stripSpaces = xmlHashCreate(10);
3598 if (style->stripSpaces == NULL) {
3599 xmlFree(elements);
3600 return;
3601 }
3602
3603 element = elements;
3604 while (*element != 0) {
3605 while (xmlIsBlank_ch(*element))
3606 element++;
3607 if (*element == 0)
3608 break;
3609 end = element;
3610 while ((*end != 0) && (!xmlIsBlank_ch(*end)))
3611 end++;
3613 if (element) {
3614 const xmlChar *URI;
3615
3616#ifdef WITH_XSLT_DEBUG_PARSING
3618 "add cdata section output element %s\n",
3619 element);
3620#endif
3621 URI = xsltGetQNameURI(inst, &element);
3622
3623 xmlHashAddEntry2(style->stripSpaces, element, URI,
3624 (xmlChar *) "cdata");
3626 }
3627 element = end;
3628 }
3629 xmlFree(elements);
3630 }
3631
3632 /*
3633 * Create a new document tree and process the element template
3634 */
3636 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3637 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3640
3641 if ((method != NULL) &&
3642 (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3643 if (xmlStrEqual(method, (const xmlChar *) "html")) {
3644 ctxt->type = XSLT_OUTPUT_HTML;
3645 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3646 res = htmlNewDoc(doctypeSystem, doctypePublic);
3647 else {
3648 if (version != NULL) {
3649#ifdef XSLT_GENERATE_HTML_DOCTYPE
3650 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3651#endif
3652 }
3653 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3654 }
3655 if (res == NULL)
3656 goto error;
3657 res->dict = ctxt->dict;
3658 xmlDictReference(res->dict);
3659 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3660 xsltTransformError(ctxt, NULL, inst,
3661 "xsltDocumentElem: unsupported method xhtml\n");
3662 ctxt->type = XSLT_OUTPUT_HTML;
3663 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3664 if (res == NULL)
3665 goto error;
3666 res->dict = ctxt->dict;
3667 xmlDictReference(res->dict);
3668 } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3669 ctxt->type = XSLT_OUTPUT_TEXT;
3670 res = xmlNewDoc(style->version);
3671 if (res == NULL)
3672 goto error;
3673 res->dict = ctxt->dict;
3674 xmlDictReference(res->dict);
3675#ifdef WITH_XSLT_DEBUG
3677 "reusing transformation dict for output\n");
3678#endif
3679 } else {
3680 xsltTransformError(ctxt, NULL, inst,
3681 "xsltDocumentElem: unsupported method (%s)\n",
3682 method);
3683 goto error;
3684 }
3685 } else {
3686 ctxt->type = XSLT_OUTPUT_XML;
3687 res = xmlNewDoc(style->version);
3688 if (res == NULL)
3689 goto error;
3690 res->dict = ctxt->dict;
3691 xmlDictReference(res->dict);
3692#ifdef WITH_XSLT_DEBUG
3694 "reusing transformation dict for output\n");
3695#endif
3696 }
3697 res->charset = XML_CHAR_ENCODING_UTF8;
3698 if (encoding != NULL)
3699 res->encoding = xmlStrdup(encoding);
3700 ctxt->output = res;
3701 ctxt->insert = (xmlNodePtr) res;
3703
3704 /*
3705 * Do some post processing work depending on the generated output
3706 */
3708 if (root != NULL) {
3709 const xmlChar *doctype = NULL;
3710
3711 if ((root->ns != NULL) && (root->ns->prefix != NULL))
3712 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3713 if (doctype == NULL)
3714 doctype = root->name;
3715
3716 /*
3717 * Apply the default selection of the method
3718 */
3719 if ((method == NULL) &&
3720 (root->ns == NULL) &&
3721 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3722 xmlNodePtr tmp;
3723
3724 tmp = res->children;
3725 while ((tmp != NULL) && (tmp != root)) {
3726 if (tmp->type == XML_ELEMENT_NODE)
3727 break;
3728 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3729 break;
3730 tmp = tmp->next;
3731 }
3732 if (tmp == root) {
3733 ctxt->type = XSLT_OUTPUT_HTML;
3735 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3736 res->intSubset = xmlCreateIntSubset(res, doctype,
3737 doctypePublic,
3738 doctypeSystem);
3739#ifdef XSLT_GENERATE_HTML_DOCTYPE
3740 } else if (version != NULL) {
3741 xsltGetHTMLIDs(version, &doctypePublic,
3742 &doctypeSystem);
3743 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3744 res->intSubset =
3745 xmlCreateIntSubset(res, doctype,
3746 doctypePublic,
3747 doctypeSystem);
3748#endif
3749 }
3750 }
3751
3752 }
3753 if (ctxt->type == XSLT_OUTPUT_XML) {
3754 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3755 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3756 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3757 res->intSubset = xmlCreateIntSubset(res, doctype,
3758 doctypePublic,
3759 doctypeSystem);
3760 }
3761 }
3762
3763 /*
3764 * Calls to redirect:write also take an optional attribute append.
3765 * Attribute append="true|yes" which will attempt to simply append
3766 * to an existing file instead of always opening a new file. The
3767 * default behavior of always overwriting the file still happens
3768 * if we do not specify append.
3769 * Note that append use will forbid use of remote URI target.
3770 */
3771 prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
3772 NULL);
3773 if (prop != NULL) {
3774 if (xmlStrEqual(prop, (const xmlChar *) "true") ||
3775 xmlStrEqual(prop, (const xmlChar *) "yes")) {
3776 style->omitXmlDeclaration = 1;
3777 redirect_write_append = 1;
3778 } else
3779 style->omitXmlDeclaration = 0;
3780 xmlFree(prop);
3781 }
3782
3783 if (redirect_write_append) {
3784 FILE *f;
3785
3786 f = fopen((const char *) filename, "ab");
3787 if (f == NULL) {
3788 ret = -1;
3789 } else {
3791 fclose(f);
3792 }
3793 } else {
3794 ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
3795 }
3796 if (ret < 0) {
3797 xsltTransformError(ctxt, NULL, inst,
3798 "xsltDocumentElem: unable to save to %s\n",
3799 filename);
3800#ifdef WITH_XSLT_DEBUG_EXTRA
3801 } else {
3803 "Wrote %d bytes to %s\n", ret, filename);
3804#endif
3805 }
3806
3807 error:
3808 ctxt->output = oldOutput;
3809 ctxt->insert = oldInsert;
3810 ctxt->type = oldType;
3811 ctxt->outputFile = oldOutputFile;
3812 if (URL != NULL)
3813 xmlFree(URL);
3814 if (filename != NULL)
3816 if (style != NULL)
3818 if (res != NULL)
3819 xmlFreeDoc(res);
3820}
3821
3822/************************************************************************
3823 * *
3824 * Most of the XSLT-1.0 transformations *
3825 * *
3826 ************************************************************************/
3827
3838void
3841 xsltElemPreCompPtr comp) {
3842 if (comp == NULL) {
3843 xsltTransformError(ctxt, NULL, inst,
3844 "xsl:sort : compilation failed\n");
3845 return;
3846 }
3847 xsltTransformError(ctxt, NULL, inst,
3848 "xsl:sort : improper use this should not be reached\n");
3849}
3850
3860void
3862 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3863{
3864#ifdef XSLT_REFACTORED
3865 xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3866#else
3867 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3868#endif
3869 xmlNodePtr copy, oldInsert;
3870
3871 oldInsert = ctxt->insert;
3872 if (ctxt->insert != NULL) {
3873 switch (node->type) {
3874 case XML_TEXT_NODE:
3876 /*
3877 * This text comes from the stylesheet
3878 * For stylesheets, the set of whitespace-preserving
3879 * element names consists of just xsl:text.
3880 */
3881#ifdef WITH_XSLT_DEBUG_PROCESS
3882 if (node->type == XML_CDATA_SECTION_NODE) {
3884 "xsltCopy: CDATA text %s\n", node->content));
3885 } else {
3887 "xsltCopy: text %s\n", node->content));
3888 }
3889#endif
3890 xsltCopyText(ctxt, ctxt->insert, node, 0);
3891 break;
3892 case XML_DOCUMENT_NODE:
3894 break;
3895 case XML_ELEMENT_NODE:
3896 /*
3897 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3898 * REMOVED:
3899 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3900 * return;
3901 */
3902
3903#ifdef WITH_XSLT_DEBUG_PROCESS
3905 "xsltCopy: node %s\n", node->name));
3906#endif
3907 copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3908 ctxt->insert = copy;
3909 if (comp->use != NULL) {
3910 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3911 }
3912 break;
3913 case XML_ATTRIBUTE_NODE: {
3914#ifdef WITH_XSLT_DEBUG_PROCESS
3916 "xsltCopy: attribute %s\n", node->name));
3917#endif
3918 /*
3919 * REVISIT: We could also raise an error if the parent is not
3920 * an element node.
3921 * OPTIMIZE TODO: Can we set the value/children of the
3922 * attribute without an intermediate copy of the string value?
3923 */
3924 xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
3925 break;
3926 }
3927 case XML_PI_NODE:
3928#ifdef WITH_XSLT_DEBUG_PROCESS
3930 "xsltCopy: PI %s\n", node->name));
3931#endif
3932 copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3933 node->content);
3934 copy = xsltAddChild(ctxt->insert, copy);
3935 break;
3936 case XML_COMMENT_NODE:
3937#ifdef WITH_XSLT_DEBUG_PROCESS
3939 "xsltCopy: comment\n"));
3940#endif
3941 copy = xmlNewComment(node->content);
3942 copy = xsltAddChild(ctxt->insert, copy);
3943 break;
3944 case XML_NAMESPACE_DECL:
3945#ifdef WITH_XSLT_DEBUG_PROCESS
3947 "xsltCopy: namespace declaration\n"));
3948#endif
3949 xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3950 break;
3951 default:
3952 break;
3953
3954 }
3955 }
3956
3957 switch (node->type) {
3958 case XML_DOCUMENT_NODE:
3960 case XML_ELEMENT_NODE:
3961 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
3962 NULL);
3963 break;
3964 default:
3965 break;
3966 }
3967 ctxt->insert = oldInsert;
3968}
3969
3979void
3982 if ((inst->children != NULL) && (comp != NULL)) {
3983 xmlNodePtr text = inst->children;
3985
3986 while (text != NULL) {
3987 if ((text->type != XML_TEXT_NODE) &&
3988 (text->type != XML_CDATA_SECTION_NODE)) {
3989 xsltTransformError(ctxt, NULL, inst,
3990 "xsl:text content problem\n");
3991 break;
3992 }
3993 copy = xmlNewDocText(ctxt->output, text->content);
3994 if (text->type != XML_CDATA_SECTION_NODE) {
3995#ifdef WITH_XSLT_DEBUG_PARSING
3997 "Disable escaping: %s\n", text->content);
3998#endif
3999 copy->name = xmlStringTextNoenc;
4000 }
4001 copy = xsltAddChild(ctxt->insert, copy);
4002 text = text->next;
4003 }
4004 }
4005}
4006
4016void
4018 xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4019#ifdef XSLT_REFACTORED
4020 xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
4021#else
4022 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4023#endif
4024 xmlChar *prop = NULL;
4025 const xmlChar *name, *prefix = NULL, *nsName = NULL;
4027 xmlNodePtr oldInsert;
4028
4029 if (ctxt->insert == NULL)
4030 return;
4031
4032 /*
4033 * A comp->has_name == 0 indicates that we need to skip this instruction,
4034 * since it was evaluated to be invalid already during compilation.
4035 */
4036 if (!comp->has_name)
4037 return;
4038
4039 /*
4040 * stack and saves
4041 */
4042 oldInsert = ctxt->insert;
4043
4044 if (comp->name == NULL) {
4045 /* TODO: fix attr acquisition wrt to the XSLT namespace */
4046 prop = xsltEvalAttrValueTemplate(ctxt, inst,
4047 (const xmlChar *) "name", XSLT_NAMESPACE);
4048 if (prop == NULL) {
4049 xsltTransformError(ctxt, NULL, inst,
4050 "xsl:element: The attribute 'name' is missing.\n");
4051 goto error;
4052 }
4053 if (xmlValidateQName(prop, 0)) {
4054 xsltTransformError(ctxt, NULL, inst,
4055 "xsl:element: The effective name '%s' is not a "
4056 "valid QName.\n", prop);
4057 /* we fall through to catch any further errors, if possible */
4058 }
4059 name = xsltSplitQName(ctxt->dict, prop, &prefix);
4060 xmlFree(prop);
4061 } else {
4062 /*
4063 * The "name" value was static.
4064 */
4065#ifdef XSLT_REFACTORED
4066 prefix = comp->nsPrefix;
4067 name = comp->name;
4068#else
4069 name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
4070#endif
4071 }
4072
4073 /*
4074 * Create the new element
4075 */
4076 if (ctxt->output->dict == ctxt->dict) {
4078 } else {
4079 copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
4080 }
4081 if (copy == NULL) {
4082 xsltTransformError(ctxt, NULL, inst,
4083 "xsl:element : creation of %s failed\n", name);
4084 return;
4085 }
4086 copy = xsltAddChild(ctxt->insert, copy);
4087 if (copy == NULL) {
4088 xsltTransformError(ctxt, NULL, inst,
4089 "xsl:element : xsltAddChild failed\n");
4090 return;
4091 }
4092
4093 /*
4094 * Namespace
4095 * ---------
4096 */
4097 if (comp->has_ns) {
4098 if (comp->ns != NULL) {
4099 /*
4100 * No AVT; just plain text for the namespace name.
4101 */
4102 if (comp->ns[0] != 0)
4103 nsName = comp->ns;
4104 } else {
4105 xmlChar *tmpNsName;
4106 /*
4107 * Eval the AVT.
4108 */
4109 /* TODO: check attr acquisition wrt to the XSLT namespace */
4110 tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
4111 (const xmlChar *) "namespace", XSLT_NAMESPACE);
4112 /*
4113 * SPEC XSLT 1.0:
4114 * "If the string is empty, then the expanded-name of the
4115 * attribute has a null namespace URI."
4116 */
4117 if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
4118 nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
4119 xmlFree(tmpNsName);
4120 }
4121
4122 if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
4123 xsltTransformError(ctxt, NULL, inst,
4124 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4125 "forbidden.\n");
4126 goto error;
4127 }
4128 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
4129 prefix = BAD_CAST "xml";
4130 } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
4131 prefix = NULL;
4132 }
4133 } else {
4134 xmlNsPtr ns;
4135 /*
4136 * SPEC XSLT 1.0:
4137 * "If the namespace attribute is not present, then the QName is
4138 * expanded into an expanded-name using the namespace declarations
4139 * in effect for the xsl:element element, including any default
4140 * namespace declaration.
4141 */
4142 ns = xmlSearchNs(inst->doc, inst, prefix);
4143 if (ns == NULL) {
4144 /*
4145 * TODO: Check this in the compilation layer in case it's a
4146 * static value.
4147 */
4148 if (prefix != NULL) {
4149 xsltTransformError(ctxt, NULL, inst,
4150 "xsl:element: The QName '%s:%s' has no "
4151 "namespace binding in scope in the stylesheet; "
4152 "this is an error, since the namespace was not "
4153 "specified by the instruction itself.\n", prefix, name);
4154 }
4155 } else
4156 nsName = ns->href;
4157 }
4158 /*
4159 * Find/create a matching ns-decl in the result tree.
4160 */
4161 if (nsName != NULL) {
4162 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
4163 /* Don't use a prefix of "xmlns" */
4164 xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
4165
4166 copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
4167
4168 xmlFree(pref);
4169 } else {
4170 copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
4171 copy);
4172 }
4173 } else if ((copy->parent != NULL) &&
4174 (copy->parent->type == XML_ELEMENT_NODE) &&
4175 (copy->parent->ns != NULL))
4176 {
4177 /*
4178 * "Undeclare" the default namespace.
4179 */
4180 xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4181 }
4182
4183 ctxt->insert = copy;
4184
4185 if (comp->has_use) {
4186 if (comp->use != NULL) {
4187 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4188 } else {
4189 xmlChar *attrSets = NULL;
4190 /*
4191 * BUG TODO: use-attribute-sets is not a value template.
4192 * use-attribute-sets = qnames
4193 */
4194 attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4195 (const xmlChar *)"use-attribute-sets", NULL);
4196 if (attrSets != NULL) {
4197 xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4198 xmlFree(attrSets);
4199 }
4200 }
4201 }
4202 /*
4203 * Instantiate the sequence constructor.
4204 */
4205 if (inst->children != NULL)
4206 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4207 NULL);
4208
4209error:
4210 ctxt->insert = oldInsert;
4211 return;
4212}
4213
4214
4224void
4227 xmlChar *value = NULL;
4228 xmlNodePtr commentNode;
4229 int len;
4230
4231 value = xsltEvalTemplateString(ctxt, node, inst);
4232 /* TODO: use or generate the compiled form */
4233 len = xmlStrlen(value);
4234 if (len > 0) {
4235 if ((value[len-1] == '-') ||
4236 (xmlStrstr(value, BAD_CAST "--"))) {
4237 xsltTransformError(ctxt, NULL, inst,
4238 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4239 /* fall through to try to catch further errors */
4240 }
4241 }
4242#ifdef WITH_XSLT_DEBUG_PROCESS
4243 if (value == NULL) {
4245 "xsltComment: empty\n"));
4246 } else {
4248 "xsltComment: content %s\n", value));
4249 }
4250#endif
4251
4252 commentNode = xmlNewComment(value);
4253 commentNode = xsltAddChild(ctxt->insert, commentNode);
4254
4255 if (value != NULL)
4256 xmlFree(value);
4257}
4258
4268void
4270 xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4271#ifdef XSLT_REFACTORED
4272 xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4273#else
4274 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4275#endif
4276 const xmlChar *name;
4277 xmlChar *value = NULL;
4278 xmlNodePtr pi;
4279
4280
4281 if (ctxt->insert == NULL)
4282 return;
4283 if (comp->has_name == 0)
4284 return;
4285 if (comp->name == NULL) {
4286 name = xsltEvalAttrValueTemplate(ctxt, inst,
4287 (const xmlChar *)"name", NULL);
4288 if (name == NULL) {
4289 xsltTransformError(ctxt, NULL, inst,
4290 "xsl:processing-instruction : name is missing\n");
4291 goto error;
4292 }
4293 } else {
4294 name = comp->name;
4295 }
4296 /* TODO: check that it's both an an NCName and a PITarget. */
4297
4298
4299 value = xsltEvalTemplateString(ctxt, node, inst);
4300 if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4301 xsltTransformError(ctxt, NULL, inst,
4302 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4303 goto error;
4304 }
4305#ifdef WITH_XSLT_DEBUG_PROCESS
4306 if (value == NULL) {
4308 "xsltProcessingInstruction: %s empty\n", name));
4309 } else {
4311 "xsltProcessingInstruction: %s content %s\n", name, value));
4312 }
4313#endif
4314
4315 pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4316 pi = xsltAddChild(ctxt->insert, pi);
4317
4318error:
4319 if ((name != NULL) && (name != comp->name))
4320 xmlFree((xmlChar *) name);
4321 if (value != NULL)
4322 xmlFree(value);
4323}
4324
4334void
4336 xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4337#ifdef XSLT_REFACTORED
4338 xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4339#else
4340 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4341#endif
4342 xmlXPathObjectPtr res = NULL;
4343 xmlNodeSetPtr list = NULL;
4344 int i;
4345
4346 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4347 return;
4348 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4349 xsltTransformError(ctxt, NULL, inst,
4350 "xsl:copy-of : compilation failed\n");
4351 return;
4352 }
4353
4354 /*
4355 * SPEC XSLT 1.0:
4356 * "The xsl:copy-of element can be used to insert a result tree
4357 * fragment into the result tree, without first converting it to
4358 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4359 * xsl:value-of]). The required select attribute contains an
4360 * expression. When the result of evaluating the expression is a
4361 * result tree fragment, the complete fragment is copied into the
4362 * result tree. When the result is a node-set, all the nodes in the
4363 * set are copied in document order into the result tree; copying
4364 * an element node copies the attribute nodes, namespace nodes and
4365 * children of the element node as well as the element node itself;
4366 * a root node is copied by copying its children. When the result
4367 * is neither a node-set nor a result tree fragment, the result is
4368 * converted to a string and then inserted into the result tree,
4369 * as with xsl:value-of.
4370 */
4371
4372#ifdef WITH_XSLT_DEBUG_PROCESS
4374 "xsltCopyOf: select %s\n", comp->select));
4375#endif
4376
4377 /*
4378 * Evaluate the "select" expression.
4379 */
4380 res = xsltPreCompEval(ctxt, node, comp);
4381
4382 if (res != NULL) {
4383 if (res->type == XPATH_NODESET) {
4384 /*
4385 * Node-set
4386 * --------
4387 */
4388#ifdef WITH_XSLT_DEBUG_PROCESS
4390 "xsltCopyOf: result is a node set\n"));
4391#endif
4392 list = res->nodesetval;
4393 if (list != NULL) {
4395 /*
4396 * The list is already sorted in document order by XPath.
4397 * Append everything in this order under ctxt->insert.
4398 */
4399 for (i = 0;i < list->nodeNr;i++) {
4400 cur = list->nodeTab[i];
4401 if (cur == NULL)
4402 continue;
4403 if ((cur->type == XML_DOCUMENT_NODE) ||
4404 (cur->type == XML_HTML_DOCUMENT_NODE))
4405 {
4406 xsltCopyTreeList(ctxt, inst,
4407 cur->children, ctxt->insert, 0, 0);
4408 } else if (cur->type == XML_ATTRIBUTE_NODE) {
4409 xsltShallowCopyAttr(ctxt, inst,
4410 ctxt->insert, (xmlAttrPtr) cur);
4411 } else {
4412 xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
4413 }
4414 }
4415 }
4416 } else if (res->type == XPATH_XSLT_TREE) {
4417 /*
4418 * Result tree fragment
4419 * --------------------
4420 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4421 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4422 */
4423#ifdef WITH_XSLT_DEBUG_PROCESS
4425 "xsltCopyOf: result is a result tree fragment\n"));
4426#endif
4427 list = res->nodesetval;
4428 if ((list != NULL) && (list->nodeTab != NULL) &&
4429 (list->nodeTab[0] != NULL) &&
4430 (IS_XSLT_REAL_NODE(list->nodeTab[0])))
4431 {
4432 xsltCopyTreeList(ctxt, inst,
4433 list->nodeTab[0]->children, ctxt->insert, 0, 0);
4434 }
4435 } else {
4436 xmlChar *value = NULL;
4437 /*
4438 * Convert to a string.
4439 */
4440 value = xmlXPathCastToString(res);
4441 if (value == NULL) {
4442 xsltTransformError(ctxt, NULL, inst,
4443 "Internal error in xsltCopyOf(): "
4444 "failed to cast an XPath object to string.\n");
4445 ctxt->state = XSLT_STATE_STOPPED;
4446 } else {
4447 if (value[0] != 0) {
4448 /*
4449 * Append content as text node.
4450 */
4451 xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4452 }
4453 xmlFree(value);
4454
4455#ifdef WITH_XSLT_DEBUG_PROCESS
4457 "xsltCopyOf: result %s\n", res->stringval));
4458#endif
4459 }
4460 }
4461 } else {
4462 ctxt->state = XSLT_STATE_STOPPED;
4463 }
4464
4465 if (res != NULL)
4466 xmlXPathFreeObject(res);
4467}
4468
4478void
4480 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4481{
4482#ifdef XSLT_REFACTORED
4483 xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4484#else
4485 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4486#endif
4487 xmlXPathObjectPtr res = NULL;
4488 xmlChar *value = NULL;
4489
4490 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4491 return;
4492
4493 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4494 xsltTransformError(ctxt, NULL, inst,
4495 "Internal error in xsltValueOf(): "
4496 "The XSLT 'value-of' instruction was not compiled.\n");
4497 return;
4498 }
4499
4500#ifdef WITH_XSLT_DEBUG_PROCESS
4502 "xsltValueOf: select %s\n", comp->select));
4503#endif
4504
4505 res = xsltPreCompEval(ctxt, node, comp);
4506
4507 /*
4508 * Cast the XPath object to string.
4509 */
4510 if (res != NULL) {
4511 value = xmlXPathCastToString(res);
4512 if (value == NULL) {
4513 xsltTransformError(ctxt, NULL, inst,
4514 "Internal error in xsltValueOf(): "
4515 "failed to cast an XPath object to string.\n");
4516 ctxt->state = XSLT_STATE_STOPPED;
4517 goto error;
4518 }
4519 if (value[0] != 0) {
4520 xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
4521 }
4522 } else {
4523 xsltTransformError(ctxt, NULL, inst,
4524 "XPath evaluation returned no result.\n");
4525 ctxt->state = XSLT_STATE_STOPPED;
4526 goto error;
4527 }
4528
4529#ifdef WITH_XSLT_DEBUG_PROCESS
4530 if (value) {
4532 "xsltValueOf: result '%s'\n", value));
4533 }
4534#endif
4535
4536error:
4537 if (value != NULL)
4538 xmlFree(value);
4539 if (res != NULL)
4540 xmlXPathFreeObject(res);
4541}
4542
4552void
4554 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4555{
4556#ifdef XSLT_REFACTORED
4557 xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4558#else
4559 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4560#endif
4561 xmlXPathContextPtr xpctxt;
4562 xmlNsPtr *oldXPNamespaces;
4563 int oldXPNsNr;
4564
4565 if (comp == NULL) {
4566 xsltTransformError(ctxt, NULL, inst,
4567 "xsl:number : compilation failed\n");
4568 return;
4569 }
4570
4571 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4572 return;
4573
4574 comp->numdata.doc = inst->doc;
4575 comp->numdata.node = inst;
4576
4577 xpctxt = ctxt->xpathCtxt;
4578 oldXPNsNr = xpctxt->nsNr;
4579 oldXPNamespaces = xpctxt->namespaces;
4580
4581#ifdef XSLT_REFACTORED
4582 if (comp->inScopeNs != NULL) {
4583 xpctxt->namespaces = comp->inScopeNs->list;
4584 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4585 } else {
4586 xpctxt->namespaces = NULL;
4587 xpctxt->nsNr = 0;
4588 }
4589#else
4590 xpctxt->namespaces = comp->nsList;
4591 xpctxt->nsNr = comp->nsNr;
4592#endif
4593
4594 xsltNumberFormat(ctxt, &comp->numdata, node);
4595
4596 xpctxt->nsNr = oldXPNsNr;
4597 xpctxt->namespaces = oldXPNamespaces;
4598}
4599
4609void
4611 xmlNodePtr inst,
4613{
4614 xsltTemplatePtr templ;
4615
4616 if ((ctxt == NULL) || (inst == NULL))
4617 return;
4618
4619 if (comp == NULL) {
4620 xsltTransformError(ctxt, NULL, inst,
4621 "Internal error in xsltApplyImports(): "
4622 "The XSLT 'apply-imports' instruction was not compiled.\n");
4623 return;
4624 }
4625 /*
4626 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4627 * same; the former is the "Current Template Rule" as defined by the
4628 * XSLT spec, the latter is simply the template struct being
4629 * currently processed.
4630 */
4631 if (ctxt->currentTemplateRule == NULL) {
4632 /*
4633 * SPEC XSLT 2.0:
4634 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4635 * xsl:apply-imports or xsl:next-match is evaluated when the
4636 * current template rule is null."
4637 */
4638 xsltTransformError(ctxt, NULL, inst,
4639 "It is an error to call 'apply-imports' "
4640 "when there's no current template rule.\n");
4641 return;
4642 }
4643 /*
4644 * TODO: Check if this is correct.
4645 */
4646 templ = xsltGetTemplate(ctxt, contextNode,
4647 ctxt->currentTemplateRule->style);
4648
4649 if (templ != NULL) {
4650 xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4651 /*
4652 * Set the current template rule.
4653 */
4654 ctxt->currentTemplateRule = templ;
4655 /*
4656 * URGENT TODO: Need xsl:with-param be handled somehow here?
4657 */
4658 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4659 templ, NULL);
4660
4661 ctxt->currentTemplateRule = oldCurTemplRule;
4662 }
4663 else {
4664 /* Use built-in templates. */
4665 xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
4666 }
4667}
4668
4678void
4680 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4681{
4682#ifdef XSLT_REFACTORED
4683 xsltStyleItemCallTemplatePtr comp =
4684 (xsltStyleItemCallTemplatePtr) castedComp;
4685#else
4686 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4687#endif
4688 xsltStackElemPtr withParams = NULL;
4689
4690 if (ctxt->insert == NULL)
4691 return;
4692 if (comp == NULL) {
4693 xsltTransformError(ctxt, NULL, inst,
4694 "The XSLT 'call-template' instruction was not compiled.\n");
4695 return;
4696 }
4697
4698 /*
4699 * The template must have been precomputed
4700 */
4701 if (comp->templ == NULL) {
4702 comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4703 if (comp->templ == NULL) {
4704 if (comp->ns != NULL) {
4705 xsltTransformError(ctxt, NULL, inst,
4706 "The called template '{%s}%s' was not found.\n",
4707 comp->ns, comp->name);
4708 } else {
4709 xsltTransformError(ctxt, NULL, inst,
4710 "The called template '%s' was not found.\n",
4711 comp->name);
4712 }
4713 return;
4714 }
4715 }
4716
4717#ifdef WITH_XSLT_DEBUG_PROCESS
4718 if ((comp != NULL) && (comp->name != NULL))
4720 "call-template: name %s\n", comp->name));
4721#endif
4722
4723 if (inst->children) {
4726
4727 cur = inst->children;
4728 while (cur != NULL) {
4729#ifdef WITH_DEBUGGER
4730 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4731 xslHandleDebugger(cur, node, comp->templ, ctxt);
4732#endif
4733 if (ctxt->state == XSLT_STATE_STOPPED) break;
4734 /*
4735 * TODO: The "with-param"s could be part of the "call-template"
4736 * structure. Avoid to "search" for params dynamically
4737 * in the XML tree every time.
4738 */
4739 if (IS_XSLT_ELEM(cur)) {
4740 if (IS_XSLT_NAME(cur, "with-param")) {
4742 if (param != NULL) {
4743 param->next = withParams;
4744 withParams = param;
4745 }
4746 } else {
4748 "xsl:call-template: misplaced xsl:%s\n", cur->name);
4749 }
4750 } else {
4752 "xsl:call-template: misplaced %s element\n", cur->name);
4753 }
4754 cur = cur->next;
4755 }
4756 }
4757 /*
4758 * Create a new frame using the params first
4759 */
4760 xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4761 withParams);
4762 if (withParams != NULL)
4763 xsltFreeStackElemList(withParams);
4764
4765#ifdef WITH_XSLT_DEBUG_PROCESS
4766 if ((comp != NULL) && (comp->name != NULL))
4768 "call-template returned: name %s\n", comp->name));
4769#endif
4770}
4771
4781void
4783 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4784{
4785#ifdef XSLT_REFACTORED
4786 xsltStyleItemApplyTemplatesPtr comp =
4787 (xsltStyleItemApplyTemplatesPtr) castedComp;
4788#else
4789 xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4790#endif
4791 int i;
4792 xmlNodePtr cur, oldContextNode;
4793 xmlNodeSetPtr list = NULL, oldList;
4794 xsltStackElemPtr withParams = NULL;
4795 int oldXPProximityPosition, oldXPContextSize;
4796 const xmlChar *oldMode, *oldModeURI;
4797 xmlDocPtr oldXPDoc;
4798 xsltDocumentPtr oldDocInfo;
4799 xmlXPathContextPtr xpctxt;
4800
4801 if (comp == NULL) {
4802 xsltTransformError(ctxt, NULL, inst,
4803 "xsl:apply-templates : compilation failed\n");
4804 return;
4805 }
4806 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4807 return;
4808
4809#ifdef WITH_XSLT_DEBUG_PROCESS
4810 if ((node != NULL) && (node->name != NULL))
4