ReactOS  0.4.15-dev-1201-gb2cf5a4
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
31 static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
32  const xmlChar **systemID);
33 #endif
34 
35 int xsltMaxDepth = 3000;
36 int xsltMaxVars = 15000;
37 
38 /*
39  * Useful macros
40  */
41 
42 #ifndef FALSE
43 # define FALSE (0 == 1)
44 # define TRUE (!FALSE)
45 #endif
46 
47 #define IS_BLANK_NODE(n) \
48  (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
49 
50 
51 /*
52 * Forward declarations
53 */
54 
55 static xmlNsPtr
57 
58 static xmlNodePtr
60  xmlNodePtr node, xmlNodePtr insert, int isLRE,
61  int topElemVisited);
62 
63 static void
65  xmlNodePtr contextNode, xmlNodePtr list,
66  xsltTemplatePtr templ);
67 
68 static void
70  xmlNodePtr contextNode,
72  xsltTemplatePtr templ,
73  xsltStackElemPtr withParams);
74 
84 static 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 }
120 static 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 
149 void
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 
179 static 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 
211 static int
212 profPush(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 }
245 static long
246 profPop(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 
262 static void
263 profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
264 {
265  int i;
266 
267  if (templ->templMax == 0) {
268  templ->templMax = 4;
269  templ->templCalledTab =
270  (xsltTemplatePtr *) xmlMalloc(templ->templMax *
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 
320 static 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 
369 static 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 
416 static int xsltDoXIncludeDefault = 0;
417 
424 void
425 xsltSetXIncludeDefault(int xinclude) {
426  xsltDoXIncludeDefault = (xinclude != 0);
427 }
428 
436 int
438  return(xsltDoXIncludeDefault);
439 }
440 
441 static 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 
485 static 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 
541  xsltInitGlobals();
542 
544  if (cur == NULL) {
546  "xsltNewTransformContext : malloc failed\n");
547  return(NULL);
548  }
549  memset(cur, 0, sizeof(xsltTransformContext));
550 
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;
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;
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  xmlXPathInit();
606  cur->xpathCtxt = xmlXPathNewContext(doc);
607  if (cur->xpathCtxt == NULL) {
609  "xsltNewTransformContext : xmlXPathNewContext failed\n");
610  goto internal_err;
611  }
612  /*
613  * Create an XPath cache.
614  */
615  if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
616  goto internal_err;
617  /*
618  * Initialize the extras array
619  */
620  if (style->extrasNr != 0) {
621  cur->extrasMax = style->extrasNr + 20;
622  cur->extras = (xsltRuntimeExtraPtr)
623  xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
624  if (cur->extras == NULL) {
626  "xsltNewTransformContext: out of memory\n");
627  goto internal_err;
628  }
629  cur->extrasNr = style->extrasNr;
630  for (i = 0;i < cur->extrasMax;i++) {
631  cur->extras[i].info = NULL;
632  cur->extras[i].deallocate = NULL;
633  cur->extras[i].val.ptr = NULL;
634  }
635  } else {
636  cur->extras = NULL;
637  cur->extrasNr = 0;
638  cur->extrasMax = 0;
639  }
640 
643  cur->xpathCtxt->nsHash = style->nsHash;
644  /*
645  * Initialize the registered external modules
646  */
647  xsltInitCtxtExts(cur);
648  /*
649  * Setup document element ordering for later efficiencies
650  * (bug 133289)
651  */
653  xmlXPathOrderDocElems(doc);
654  /*
655  * Must set parserOptions before calling xsltNewDocument
656  * (bug 164530)
657  */
659  docu = xsltNewDocument(cur, doc);
660  if (docu == NULL) {
662  "xsltNewTransformContext : xsltNewDocument failed\n");
663  goto internal_err;
664  }
665  docu->main = 1;
666  cur->document = docu;
667  cur->inst = NULL;
668  cur->outputFile = NULL;
671  cur->traceCode = (unsigned long*) &xsltDefaultTrace;
673  cur->keyInitLevel = 0;
674 
675  return(cur);
676 
677 internal_err:
678  if (cur != NULL)
680  return(NULL);
681 }
682 
689 void
691  if (ctxt == NULL)
692  return;
693 
694  /*
695  * Shutdown the extension modules associated to the stylesheet
696  * used if needed.
697  */
698  xsltShutdownCtxtExts(ctxt);
699 
700  if (ctxt->xpathCtxt != NULL) {
701  ctxt->xpathCtxt->nsHash = NULL;
702  xmlXPathFreeContext(ctxt->xpathCtxt);
703  }
704  if (ctxt->templTab != NULL)
705  xmlFree(ctxt->templTab);
706  if (ctxt->varsTab != NULL)
707  xmlFree(ctxt->varsTab);
708  if (ctxt->profTab != NULL)
709  xmlFree(ctxt->profTab);
710  if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
711  int i;
712 
713  for (i = 0;i < ctxt->extrasNr;i++) {
714  if ((ctxt->extras[i].deallocate != NULL) &&
715  (ctxt->extras[i].info != NULL))
716  ctxt->extras[i].deallocate(ctxt->extras[i].info);
717  }
718  xmlFree(ctxt->extras);
719  }
721  xsltFreeDocuments(ctxt);
722  xsltFreeCtxtExts(ctxt);
723  xsltFreeRVTs(ctxt);
725  xmlDictFree(ctxt->dict);
726 #ifdef WITH_XSLT_DEBUG
728  "freeing transformation dictionary\n");
729 #endif
730  memset(ctxt, -1, sizeof(xsltTransformContext));
731  xmlFree(ctxt);
732 }
733 
734 /************************************************************************
735  * *
736  * Copy of Nodes in an XSLT fashion *
737  * *
738  ************************************************************************/
739 
751 static xmlNodePtr
753  xmlNodePtr ret;
754 
755  if (cur == NULL)
756  return(NULL);
757  if (parent == NULL) {
758  xmlFreeNode(cur);
759  return(NULL);
760  }
761  ret = xmlAddChild(parent, cur);
762 
763  return(ret);
764 }
765 
777 static xmlNodePtr
779  const xmlChar *string, int len) {
780  /*
781  * optimization
782  */
783  if ((len <= 0) || (string == NULL) || (target == NULL))
784  return(target);
785 
786  if (ctxt->lasttext == target->content) {
787  int minSize;
788 
789  /* Check for integer overflow accounting for NUL terminator. */
790  if (len >= INT_MAX - ctxt->lasttuse) {
792  "xsltCopyText: text allocation failed\n");
793  return(NULL);
794  }
795  minSize = ctxt->lasttuse + len + 1;
796 
797  if (ctxt->lasttsize < minSize) {
798  xmlChar *newbuf;
799  int size;
800  int extra;
801 
802  /* Double buffer size but increase by at least 100 bytes. */
803  extra = minSize < 100 ? 100 : minSize;
804 
805  /* Check for integer overflow. */
806  if (extra > INT_MAX - ctxt->lasttsize) {
807  size = INT_MAX;
808  }
809  else {
810  size = ctxt->lasttsize + extra;
811  }
812 
813  newbuf = (xmlChar *) xmlRealloc(target->content,size);
814  if (newbuf == NULL) {
816  "xsltCopyText: text allocation failed\n");
817  return(NULL);
818  }
819  ctxt->lasttsize = size;
820  ctxt->lasttext = newbuf;
821  target->content = newbuf;
822  }
823  memcpy(&(target->content[ctxt->lasttuse]), string, len);
824  ctxt->lasttuse += len;
825  target->content[ctxt->lasttuse] = 0;
826  } else {
827  xmlNodeAddContent(target, string);
828  ctxt->lasttext = target->content;
829  len = xmlStrlen(target->content);
830  ctxt->lasttsize = len;
831  ctxt->lasttuse = len;
832  }
833  return(target);
834 }
835 
851  const xmlChar *string, int noescape)
852 {
854  int len;
855 
856  if (string == NULL)
857  return(NULL);
858 
859 #ifdef WITH_XSLT_DEBUG_PROCESS
861  "xsltCopyTextString: copy text %s\n",
862  string));
863 #endif
864 
865  /*
866  * Play safe and reset the merging mechanism for every new
867  * target node.
868  */
869  if ((target == NULL) || (target->children == NULL)) {
870  ctxt->lasttext = NULL;
871  }
872 
873  /* handle coalescing of text nodes here */
874  len = xmlStrlen(string);
875  if ((ctxt->type == XSLT_OUTPUT_XML) &&
876  (ctxt->style->cdataSection != NULL) &&
877  (target != NULL) &&
878  (target->type == XML_ELEMENT_NODE) &&
879  (((target->ns == NULL) &&
881  target->name, NULL) != NULL)) ||
882  ((target->ns != NULL) &&
884  target->name, target->ns->href) != NULL))))
885  {
886  /*
887  * Process "cdata-section-elements".
888  */
889  if ((target->last != NULL) &&
890  (target->last->type == XML_CDATA_SECTION_NODE))
891  {
892  return(xsltAddTextString(ctxt, target->last, string, len));
893  }
894  copy = xmlNewCDataBlock(ctxt->output, string, len);
895  } else if (noescape) {
896  /*
897  * Process "disable-output-escaping".
898  */
899  if ((target != NULL) && (target->last != NULL) &&
900  (target->last->type == XML_TEXT_NODE) &&
901  (target->last->name == xmlStringTextNoenc))
902  {
903  return(xsltAddTextString(ctxt, target->last, string, len));
904  }
905  copy = xmlNewTextLen(string, len);
906  if (copy != NULL)
907  copy->name = xmlStringTextNoenc;
908  } else {
909  /*
910  * Default processing.
911  */
912  if ((target != NULL) && (target->last != NULL) &&
913  (target->last->type == XML_TEXT_NODE) &&
914  (target->last->name == xmlStringText)) {
915  return(xsltAddTextString(ctxt, target->last, string, len));
916  }
917  copy = xmlNewTextLen(string, len);
918  }
919  if (copy != NULL && target != NULL)
921  if (copy != NULL) {
922  ctxt->lasttext = copy->content;
923  ctxt->lasttsize = len;
924  ctxt->lasttuse = len;
925  } else {
927  "xsltCopyTextString: text copy failed\n");
928  ctxt->lasttext = NULL;
929  }
930  return(copy);
931 }
932 
945 static xmlNodePtr
947  xmlNodePtr cur, int interned)
948 {
950 
951  if ((cur->type != XML_TEXT_NODE) &&
952  (cur->type != XML_CDATA_SECTION_NODE))
953  return(NULL);
954  if (cur->content == NULL)
955  return(NULL);
956 
957 #ifdef WITH_XSLT_DEBUG_PROCESS
958  if (cur->type == XML_CDATA_SECTION_NODE) {
960  "xsltCopyText: copy CDATA text %s\n",
961  cur->content));
962  } else if (cur->name == xmlStringTextNoenc) {
964  "xsltCopyText: copy unescaped text %s\n",
965  cur->content));
966  } else {
968  "xsltCopyText: copy text %s\n",
969  cur->content));
970  }
971 #endif
972 
973  /*
974  * Play save and reset the merging mechanism for every new
975  * target node.
976  */
977  if ((target == NULL) || (target->children == NULL)) {
978  ctxt->lasttext = NULL;
979  }
980 
981  if ((ctxt->style->cdataSection != NULL) &&
982  (ctxt->type == XSLT_OUTPUT_XML) &&
983  (target != NULL) &&
984  (target->type == XML_ELEMENT_NODE) &&
985  (((target->ns == NULL) &&
987  target->name, NULL) != NULL)) ||
988  ((target->ns != NULL) &&
990  target->name, target->ns->href) != NULL))))
991  {
992  /*
993  * Process "cdata-section-elements".
994  */
995  /*
996  * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
997  */
998  /*
999  * TODO: Since this doesn't merge adjacent CDATA-section nodes,
1000  * we'll get: <![CDATA[x]]><!CDATA[y]]>.
1001  * TODO: Reported in #321505.
1002  */
1003  if ((target->last != NULL) &&
1004  (target->last->type == XML_CDATA_SECTION_NODE))
1005  {
1006  /*
1007  * Append to existing CDATA-section node.
1008  */
1009  copy = xsltAddTextString(ctxt, target->last, cur->content,
1010  xmlStrlen(cur->content));
1011  goto exit;
1012  } else {
1013  unsigned int len;
1014 
1015  len = xmlStrlen(cur->content);
1016  copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
1017  if (copy == NULL)
1018  goto exit;
1019  ctxt->lasttext = copy->content;
1020  ctxt->lasttsize = len;
1021  ctxt->lasttuse = len;
1022  }
1023  } else if ((target != NULL) &&
1024  (target->last != NULL) &&
1025  /* both escaped or both non-escaped text-nodes */
1026  (((target->last->type == XML_TEXT_NODE) &&
1027  (target->last->name == cur->name)) ||
1028  /* non-escaped text nodes and CDATA-section nodes */
1029  (((target->last->type == XML_CDATA_SECTION_NODE) &&
1030  (cur->name == xmlStringTextNoenc)))))
1031  {
1032  /*
1033  * we are appending to an existing text node
1034  */
1035  copy = xsltAddTextString(ctxt, target->last, cur->content,
1036  xmlStrlen(cur->content));
1037  goto exit;
1038  } else if ((interned) && (target != NULL) &&
1039  (target->doc != NULL) &&
1040  (target->doc->dict == ctxt->dict))
1041  {
1042  /*
1043  * TODO: DO we want to use this also for "text" output?
1044  */
1045  copy = xmlNewTextLen(NULL, 0);
1046  if (copy == NULL)
1047  goto exit;
1048  if (cur->name == xmlStringTextNoenc)
1049  copy->name = xmlStringTextNoenc;
1050 
1051  /*
1052  * Must confirm that content is in dict (bug 302821)
1053  * TODO: This check should be not needed for text coming
1054  * from the stylesheets
1055  */
1056  if (xmlDictOwns(ctxt->dict, cur->content))
1057  copy->content = cur->content;
1058  else {
1059  if ((copy->content = xmlStrdup(cur->content)) == NULL)
1060  return NULL;
1061  }
1062 
1063  ctxt->lasttext = NULL;
1064  } else {
1065  /*
1066  * normal processing. keep counters to extend the text node
1067  * in xsltAddTextString if needed.
1068  */
1069  unsigned int len;
1070 
1071  len = xmlStrlen(cur->content);
1072  copy = xmlNewTextLen(cur->content, len);
1073  if (copy == NULL)
1074  goto exit;
1075  if (cur->name == xmlStringTextNoenc)
1076  copy->name = xmlStringTextNoenc;
1077  ctxt->lasttext = copy->content;
1078  ctxt->lasttsize = len;
1079  ctxt->lasttuse = len;
1080  }
1081  if (copy != NULL) {
1082  if (target != NULL) {
1083  copy->doc = target->doc;
1084  /*
1085  * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1086  * to ensure that the optimized text-merging mechanism
1087  * won't interfere with normal node-merging in any case.
1088  */
1090  }
1091  } else {
1093  "xsltCopyText: text copy failed\n");
1094  }
1095 
1096 exit:
1097  if ((copy == NULL) || (copy->content == NULL)) {
1099  "Internal error in xsltCopyText(): "
1100  "Failed to copy the string.\n");
1101  ctxt->state = XSLT_STATE_STOPPED;
1102  }
1103  return(copy);
1104 }
1105 
1121 static xmlAttrPtr
1124 {
1125  xmlAttrPtr copy;
1126  xmlChar *value;
1127 
1128  if (attr == NULL)
1129  return(NULL);
1130 
1131  if (target->type != XML_ELEMENT_NODE) {
1132  xsltTransformError(ctxt, NULL, invocNode,
1133  "Cannot add an attribute node to a non-element node.\n");
1134  return(NULL);
1135  }
1136 
1137  if (target->children != NULL) {
1138  xsltTransformError(ctxt, NULL, invocNode,
1139  "Attribute nodes must be added before "
1140  "any child nodes to an element.\n");
1141  return(NULL);
1142  }
1143 
1144  value = xmlNodeListGetString(attr->doc, attr->children, 1);
1145  if (attr->ns != NULL) {
1146  xmlNsPtr ns;
1147 
1148  ns = xsltGetSpecialNamespace(ctxt, invocNode,
1149  attr->ns->href, attr->ns->prefix, target);
1150  if (ns == NULL) {
1151  xsltTransformError(ctxt, NULL, invocNode,
1152  "Namespace fixup error: Failed to acquire an in-scope "
1153  "namespace binding of the copied attribute '{%s}%s'.\n",
1154  attr->ns->href, attr->name);
1155  /*
1156  * TODO: Should we just stop here?
1157  */
1158  }
1159  /*
1160  * Note that xmlSetNsProp() will take care of duplicates
1161  * and assigns the new namespace even to a duplicate.
1162  */
1163  copy = xmlSetNsProp(target, ns, attr->name, value);
1164  } else {
1165  copy = xmlSetNsProp(target, NULL, attr->name, value);
1166  }
1167  if (value != NULL)
1168  xmlFree(value);
1169 
1170  if (copy == NULL)
1171  return(NULL);
1172 
1173 #if 0
1174  /*
1175  * NOTE: This was optimized according to bug #342695.
1176  * TODO: Can this further be optimized, if source and target
1177  * share the same dict and attr->children is just 1 text node
1178  * which is in the dict? How probable is such a case?
1179  */
1180  /*
1181  * TODO: Do we need to create an empty text node if the value
1182  * is the empty string?
1183  */
1184  value = xmlNodeListGetString(attr->doc, attr->children, 1);
1185  if (value != NULL) {
1186  txtNode = xmlNewDocText(target->doc, NULL);
1187  if (txtNode == NULL)
1188  return(NULL);
1189  if ((target->doc != NULL) &&
1190  (target->doc->dict != NULL))
1191  {
1192  txtNode->content =
1193  (xmlChar *) xmlDictLookup(target->doc->dict,
1194  BAD_CAST value, -1);
1195  xmlFree(value);
1196  } else
1197  txtNode->content = value;
1198  copy->children = txtNode;
1199  }
1200 #endif
1201 
1202  return(copy);
1203 }
1204 
1220 static int
1222  xmlNodePtr invocNode,
1224 {
1225  xmlAttrPtr copy;
1226  xmlNsPtr origNs = NULL, copyNs = NULL;
1227  xmlChar *value;
1228 
1229  /*
1230  * Don't use xmlCopyProp() here, since it will try to
1231  * reconciliate namespaces.
1232  */
1233  while (attr != NULL) {
1234  /*
1235  * Find a namespace node in the tree of @target.
1236  * Avoid searching for the same ns.
1237  */
1238  if (attr->ns != origNs) {
1239  origNs = attr->ns;
1240  if (attr->ns != NULL) {
1241  copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
1242  attr->ns->href, attr->ns->prefix, target);
1243  if (copyNs == NULL)
1244  return(-1);
1245  } else
1246  copyNs = NULL;
1247  }
1248  /*
1249  * If attribute has a value, we need to copy it (watching out
1250  * for possible entities)
1251  */
1252  if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
1253  (attr->children->next == NULL)) {
1254  copy = xmlNewNsProp(target, copyNs, attr->name,
1255  attr->children->content);
1256  } else if (attr->children != NULL) {
1257  value = xmlNodeListGetString(attr->doc, attr->children, 1);
1258  copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
1259  xmlFree(value);
1260  } else {
1261  copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
1262  }
1263 
1264  if (copy == NULL)
1265  return(-1);
1266 
1267  attr = attr->next;
1268  }
1269  return(0);
1270 }
1271 
1296 static xmlNodePtr
1298  xmlNodePtr insert, int isLRE)
1299 {
1300  xmlNodePtr copy;
1301 
1302  if ((node->type == XML_DTD_NODE) || (insert == NULL))
1303  return(NULL);
1304  if ((node->type == XML_TEXT_NODE) ||
1305  (node->type == XML_CDATA_SECTION_NODE))
1306  return(xsltCopyText(ctxt, insert, node, 0));
1307 
1308  copy = xmlDocCopyNode(node, insert->doc, 0);
1309  if (copy != NULL) {
1310  copy->doc = ctxt->output;
1312  if (copy == NULL) {
1313  xsltTransformError(ctxt, NULL, node,
1314  "xsltShallowCopyElem: copy failed\n");
1315  return (copy);
1316  }
1317 
1318  if (node->type == XML_ELEMENT_NODE) {
1319  /*
1320  * Add namespaces as they are needed
1321  */
1322  if (node->nsDef != NULL) {
1323  /*
1324  * TODO: Remove the LRE case in the refactored code
1325  * gets enabled.
1326  */
1327  if (isLRE)
1328  xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1329  else
1331  }
1332 
1333  /*
1334  * URGENT TODO: The problem with this is that it does not
1335  * copy over all namespace nodes in scope.
1336  * The damn thing about this is, that we would need to
1337  * use the xmlGetNsList(), for every single node; this is
1338  * also done in xsltCopyTree(), but only for the top node.
1339  */
1340  if (node->ns != NULL) {
1341  if (isLRE) {
1342  /*
1343  * REVISIT TODO: Since the non-refactored code still does
1344  * ns-aliasing, we need to call xsltGetNamespace() here.
1345  * Remove this when ready.
1346  */
1347  copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
1348  } else {
1349  copy->ns = xsltGetSpecialNamespace(ctxt,
1350  node, node->ns->href, node->ns->prefix, copy);
1351 
1352  }
1353  } else if ((insert->type == XML_ELEMENT_NODE) &&
1354  (insert->ns != NULL))
1355  {
1356  /*
1357  * "Undeclare" the default namespace.
1358  */
1360  }
1361  }
1362  } else {
1363  xsltTransformError(ctxt, NULL, node,
1364  "xsltShallowCopyElem: copy %s failed\n", node->name);
1365  }
1366  return(copy);
1367 }
1368 
1388 static xmlNodePtr
1390  xmlNodePtr list,
1391  xmlNodePtr insert, int isLRE, int topElemVisited)
1392 {
1393  xmlNodePtr copy, ret = NULL;
1394 
1395  while (list != NULL) {
1396  copy = xsltCopyTree(ctxt, invocNode,
1397  list, insert, isLRE, topElemVisited);
1398  if (copy != NULL) {
1399  if (ret == NULL) {
1400  ret = copy;
1401  }
1402  }
1403  list = list->next;
1404  }
1405  return(ret);
1406 }
1407 
1424 static xmlNsPtr
1426  xmlNsPtr ret = NULL;
1427  xmlNsPtr p = NULL, q, luNs;
1428 
1429  if (ns == NULL)
1430  return(NULL);
1431  /*
1432  * One can add namespaces only on element nodes
1433  */
1434  if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
1435  elem = NULL;
1436 
1437  do {
1438  if (ns->type != XML_NAMESPACE_DECL)
1439  break;
1440  /*
1441  * Avoid duplicating namespace declarations on the tree.
1442  */
1443  if (elem != NULL) {
1444  if ((elem->ns != NULL) &&
1445  xmlStrEqual(elem->ns->prefix, ns->prefix) &&
1446  xmlStrEqual(elem->ns->href, ns->href))
1447  {
1448  ns = ns->next;
1449  continue;
1450  }
1451  luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
1452  if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
1453  {
1454  ns = ns->next;
1455  continue;
1456  }
1457  }
1458  q = xmlNewNs(elem, ns->href, ns->prefix);
1459  if (p == NULL) {
1460  ret = p = q;
1461  } else if (q != NULL) {
1462  p->next = q;
1463  p = q;
1464  }
1465  ns = ns->next;
1466  } while (ns != NULL);
1467  return(ret);
1468 }
1469 
1481 static xmlNsPtr
1483  xmlNodePtr invocNode,
1485  xmlNsPtr ns)
1486 {
1487  /*
1488  * TODO: Contrary to header comments, this is declared as int.
1489  * be modified to return a node pointer, or NULL if any error
1490  */
1491  xmlNsPtr tmpns;
1492 
1493  if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
1494  return(NULL);
1495 
1496  if (insert->children != NULL) {
1497  xsltTransformError(ctxt, NULL, invocNode,
1498  "Namespace nodes must be added before "
1499  "any child nodes are added to an element.\n");
1500  return(NULL);
1501  }
1502  /*
1503  * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1504  * an equal prefix. We definitively won't do that.
1505  *
1506  * MSXML 4.0 and the .NET ignores ns-decls for which an
1507  * equal prefix is already in use.
1508  *
1509  * Saxon raises an error like:
1510  * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1511  * nodes with the same name".
1512  *
1513  * NOTE: We'll currently follow MSXML here.
1514  * REVISIT TODO: Check if it's better to follow Saxon here.
1515  */
1516  if (ns->prefix == NULL) {
1517  /*
1518  * If we are adding ns-nodes to an element using e.g.
1519  * <xsl:copy-of select="/foo/namespace::*">, then we need
1520  * to ensure that we don't incorrectly declare a default
1521  * namespace on an element in no namespace, which otherwise
1522  * would move the element incorrectly into a namespace, if
1523  * the node tree is serialized.
1524  */
1525  if (insert->ns == NULL)
1526  goto occupied;
1527  } else if ((ns->prefix[0] == 'x') &&
1528  xmlStrEqual(ns->prefix, BAD_CAST "xml"))
1529  {
1530  /*
1531  * The XML namespace is built in.
1532  */
1533  return(NULL);
1534  }
1535 
1536  if (insert->nsDef != NULL) {
1537  tmpns = insert->nsDef;
1538  do {
1539  if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
1540  if ((tmpns->prefix == ns->prefix) ||
1541  xmlStrEqual(tmpns->prefix, ns->prefix))
1542  {
1543  /*
1544  * Same prefix.
1545  */
1546  if (xmlStrEqual(tmpns->href, ns->href))
1547  return(NULL);
1548  goto occupied;
1549  }
1550  }
1551  tmpns = tmpns->next;
1552  } while (tmpns != NULL);
1553  }
1554  tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
1555  if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
1556  return(NULL);
1557  /*
1558  * Declare a new namespace.
1559  * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1560  * that it will again search the already declared namespaces
1561  * for a duplicate :-/
1562  */
1563  return(xmlNewNs(insert, ns->href, ns->prefix));
1564 
1565 occupied:
1566  /*
1567  * TODO: We could as well raise an error here (like Saxon does),
1568  * or at least generate a warning.
1569  */
1570  return(NULL);
1571 }
1572 
1592 static xmlNodePtr
1594  xmlNodePtr node, xmlNodePtr insert, int isLRE,
1595  int topElemVisited)
1596 {
1597  xmlNodePtr copy;
1598 
1599  if (node == NULL)
1600  return(NULL);
1601  switch (node->type) {
1602  case XML_ELEMENT_NODE:
1603  case XML_ENTITY_REF_NODE:
1604  case XML_ENTITY_NODE:
1605  case XML_PI_NODE:
1606  case XML_COMMENT_NODE:
1607  case XML_DOCUMENT_NODE:
1609 #ifdef LIBXML_DOCB_ENABLED
1610  case XML_DOCB_DOCUMENT_NODE:
1611 #endif
1612  break;
1613  case XML_TEXT_NODE: {
1614  int noenc = (node->name == xmlStringTextNoenc);
1615  return(xsltCopyTextString(ctxt, insert, node->content, noenc));
1616  }
1618  return(xsltCopyTextString(ctxt, insert, node->content, 0));
1619  case XML_ATTRIBUTE_NODE:
1620  return((xmlNodePtr)
1621  xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
1622  case XML_NAMESPACE_DECL:
1623  return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
1624  insert, (xmlNsPtr) node));
1625 
1628  case XML_NOTATION_NODE:
1629  case XML_DTD_NODE:
1630  case XML_ELEMENT_DECL:
1631  case XML_ATTRIBUTE_DECL:
1632  case XML_ENTITY_DECL:
1633  case XML_XINCLUDE_START:
1634  case XML_XINCLUDE_END:
1635  return(NULL);
1636  }
1637  if (XSLT_IS_RES_TREE_FRAG(node)) {
1638  if (node->children != NULL)
1639  copy = xsltCopyTreeList(ctxt, invocNode,
1640  node->children, insert, 0, 0);
1641  else
1642  copy = NULL;
1643  return(copy);
1644  }
1645  copy = xmlDocCopyNode(node, insert->doc, 0);
1646  if (copy != NULL) {
1647  copy->doc = ctxt->output;
1649  if (copy == NULL) {
1650  xsltTransformError(ctxt, NULL, invocNode,
1651  "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1652  return (copy);
1653  }
1654  /*
1655  * The node may have been coalesced into another text node.
1656  */
1657  if (insert->last != copy)
1658  return(insert->last);
1659  copy->next = NULL;
1660 
1661  if (node->type == XML_ELEMENT_NODE) {
1662  /*
1663  * Copy in-scope namespace nodes.
1664  *
1665  * REVISIT: Since we try to reuse existing in-scope ns-decls by
1666  * using xmlSearchNsByHref(), this will eventually change
1667  * the prefix of an original ns-binding; thus it might
1668  * break QNames in element/attribute content.
1669  * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1670  * context, plus a ns-lookup function, which writes directly
1671  * to a given list, then we wouldn't need to create/free the
1672  * nsList every time.
1673  */
1674  if ((topElemVisited == 0) &&
1675  (node->parent != NULL) &&
1676  (node->parent->type != XML_DOCUMENT_NODE) &&
1677  (node->parent->type != XML_HTML_DOCUMENT_NODE))
1678  {
1679  xmlNsPtr *nsList, *curns, ns;
1680 
1681  /*
1682  * If this is a top-most element in a tree to be
1683  * copied, then we need to ensure that all in-scope
1684  * namespaces are copied over. For nodes deeper in the
1685  * tree, it is sufficient to reconcile only the ns-decls
1686  * (node->nsDef entries).
1687  */
1688 
1689  nsList = xmlGetNsList(node->doc, node);
1690  if (nsList != NULL) {
1691  curns = nsList;
1692  do {
1693  /*
1694  * Search by prefix first in order to break as less
1695  * QNames in element/attribute content as possible.
1696  */
1697  ns = xmlSearchNs(insert->doc, insert,
1698  (*curns)->prefix);
1699 
1700  if ((ns == NULL) ||
1701  (! xmlStrEqual(ns->href, (*curns)->href)))
1702  {
1703  ns = NULL;
1704  /*
1705  * Search by namespace name.
1706  * REVISIT TODO: Currently disabled.
1707  */
1708 #if 0
1709  ns = xmlSearchNsByHref(insert->doc,
1710  insert, (*curns)->href);
1711 #endif
1712  }
1713  if (ns == NULL) {
1714  /*
1715  * Declare a new namespace on the copied element.
1716  */
1717  ns = xmlNewNs(copy, (*curns)->href,
1718  (*curns)->prefix);
1719  /* TODO: Handle errors */
1720  }
1721  if (node->ns == *curns) {
1722  /*
1723  * If this was the original's namespace then set
1724  * the generated counterpart on the copy.
1725  */
1726  copy->ns = ns;
1727  }
1728  curns++;
1729  } while (*curns != NULL);
1730  xmlFree(nsList);
1731  }
1732  } else if (node->nsDef != NULL) {
1733  /*
1734  * Copy over all namespace declaration attributes.
1735  */
1736  if (node->nsDef != NULL) {
1737  if (isLRE)
1738  xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1739  else
1741  }
1742  }
1743  /*
1744  * Set the namespace.
1745  */
1746  if (node->ns != NULL) {
1747  if (copy->ns == NULL) {
1748  /*
1749  * This will map copy->ns to one of the newly created
1750  * in-scope ns-decls, OR create a new ns-decl on @copy.
1751  */
1752  copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
1753  node->ns->href, node->ns->prefix, copy);
1754  }
1755  } else if ((insert->type == XML_ELEMENT_NODE) &&
1756  (insert->ns != NULL))
1757  {
1758  /*
1759  * "Undeclare" the default namespace on @copy with xmlns="".
1760  */
1761  xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
1762  }
1763  /*
1764  * Copy attribute nodes.
1765  */
1766  if (node->properties != NULL) {
1767  xsltCopyAttrListNoOverwrite(ctxt, invocNode,
1768  copy, node->properties);
1769  }
1770  if (topElemVisited == 0)
1771  topElemVisited = 1;
1772  }
1773  /*
1774  * Copy the subtree.
1775  */
1776  if (node->children != NULL) {
1777  xsltCopyTreeList(ctxt, invocNode,
1778  node->children, copy, isLRE, topElemVisited);
1779  }
1780  } else {
1781  xsltTransformError(ctxt, NULL, invocNode,
1782  "xsltCopyTree: Copying of '%s' failed.\n", node->name);
1783  }
1784  return(copy);
1785 }
1786 
1787 /************************************************************************
1788  * *
1789  * Error/fallback processing *
1790  * *
1791  ************************************************************************/
1792 
1803 static int
1805  xmlNodePtr inst) {
1806 
1807  xmlNodePtr child;
1808  int ret = 0;
1809 
1810  if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
1811  (inst->children == NULL))
1812  return(0);
1813 
1814  child = inst->children;
1815  while (child != NULL) {
1816  if ((IS_XSLT_ELEM(child)) &&
1817  (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
1818 #ifdef WITH_XSLT_DEBUG_PARSING
1820  "applying xsl:fallback\n");
1821 #endif
1822  ret++;
1823  xsltApplySequenceConstructor(ctxt, node, child->children,
1824  NULL);
1825  }
1826  child = child->next;
1827  }
1828  return(ret);
1829 }
1830 
1831 /************************************************************************
1832  * *
1833  * Default processing *
1834  * *
1835  ************************************************************************/
1836 
1859 static void
1862  xmlNodePtr copy;
1863  xmlNodePtr delete = NULL, cur;
1864  int nbchild = 0, oldSize;
1865  int childno = 0, oldPos;
1866  xsltTemplatePtr template;
1867 
1868  CHECK_STOPPED;
1869  /*
1870  * Handling of leaves
1871  */
1872  switch (node->type) {
1873  case XML_DOCUMENT_NODE:
1875  case XML_ELEMENT_NODE:
1876  break;
1878 #ifdef WITH_XSLT_DEBUG_PROCESS
1880  "xsltDefaultProcessOneNode: copy CDATA %s\n",
1881  node->content));
1882 #endif
1883  copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1884  if (copy == NULL) {
1885  xsltTransformError(ctxt, NULL, node,
1886  "xsltDefaultProcessOneNode: cdata copy failed\n");
1887  }
1888  return;
1889  case XML_TEXT_NODE:
1890 #ifdef WITH_XSLT_DEBUG_PROCESS
1891  if (node->content == NULL) {
1893  "xsltDefaultProcessOneNode: copy empty text\n"));
1894  return;
1895  } else {
1897  "xsltDefaultProcessOneNode: copy text %s\n",
1898  node->content));
1899  }
1900 #endif
1901  copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1902  if (copy == NULL) {
1903  xsltTransformError(ctxt, NULL, node,
1904  "xsltDefaultProcessOneNode: text copy failed\n");
1905  }
1906  return;
1907  case XML_ATTRIBUTE_NODE:
1908  cur = node->children;
1909  while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
1910  cur = cur->next;
1911  if (cur == NULL) {
1912  xsltTransformError(ctxt, NULL, node,
1913  "xsltDefaultProcessOneNode: no text for attribute\n");
1914  } else {
1915 #ifdef WITH_XSLT_DEBUG_PROCESS
1916  if (cur->content == NULL) {
1918  "xsltDefaultProcessOneNode: copy empty text\n"));
1919  } else {
1921  "xsltDefaultProcessOneNode: copy text %s\n",
1922  cur->content));
1923  }
1924 #endif
1925  copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1926  if (copy == NULL) {
1927  xsltTransformError(ctxt, NULL, node,
1928  "xsltDefaultProcessOneNode: text copy failed\n");
1929  }
1930  }
1931  return;
1932  default:
1933  return;
1934  }
1935  /*
1936  * Handling of Elements: first pass, cleanup and counting
1937  */
1938  cur = node->children;
1939  while (cur != NULL) {
1940  switch (cur->type) {
1941  case XML_TEXT_NODE:
1943  case XML_DOCUMENT_NODE:
1945  case XML_ELEMENT_NODE:
1946  case XML_PI_NODE:
1947  case XML_COMMENT_NODE:
1948  nbchild++;
1949  break;
1950  case XML_DTD_NODE:
1951  /* Unlink the DTD, it's still reachable using doc->intSubset */
1952  if (cur->next != NULL)
1953  cur->next->prev = cur->prev;
1954  if (cur->prev != NULL)
1955  cur->prev->next = cur->next;
1956  break;
1957  default:
1958 #ifdef WITH_XSLT_DEBUG_PROCESS
1960  "xsltDefaultProcessOneNode: skipping node type %d\n",
1961  cur->type));
1962 #endif
1963  delete = cur;
1964  }
1965  cur = cur->next;
1966  if (delete != NULL) {
1967 #ifdef WITH_XSLT_DEBUG_PROCESS
1969  "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1970 #endif
1971  xmlUnlinkNode(delete);
1972  xmlFreeNode(delete);
1973  delete = NULL;
1974  }
1975  }
1976  if (delete != NULL) {
1977 #ifdef WITH_XSLT_DEBUG_PROCESS
1979  "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1980 #endif
1981  xmlUnlinkNode(delete);
1982  xmlFreeNode(delete);
1983  delete = NULL;
1984  }
1985 
1986  /*
1987  * Handling of Elements: second pass, actual processing
1988  *
1989  * Note that params are passed to the next template. This matches
1990  * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1991  */
1992  oldSize = ctxt->xpathCtxt->contextSize;
1993  oldPos = ctxt->xpathCtxt->proximityPosition;
1994  cur = node->children;
1995  while (cur != NULL) {
1996  childno++;
1997  switch (cur->type) {
1998  case XML_DOCUMENT_NODE:
2000  case XML_ELEMENT_NODE:
2001  ctxt->xpathCtxt->contextSize = nbchild;
2002  ctxt->xpathCtxt->proximityPosition = childno;
2003  xsltProcessOneNode(ctxt, cur, params);
2004  break;
2006  template = xsltGetTemplate(ctxt, cur, NULL);
2007  if (template) {
2008 #ifdef WITH_XSLT_DEBUG_PROCESS
2010  "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2011  cur->content));
2012 #endif
2013  /*
2014  * Instantiate the xsl:template.
2015  */
2016  xsltApplyXSLTTemplate(ctxt, cur, template->content,
2017  template, params);
2018  } else /* if (ctxt->mode == NULL) */ {
2019 #ifdef WITH_XSLT_DEBUG_PROCESS
2021  "xsltDefaultProcessOneNode: copy CDATA %s\n",
2022  cur->content));
2023 #endif
2024  copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2025  if (copy == NULL) {
2026  xsltTransformError(ctxt, NULL, cur,
2027  "xsltDefaultProcessOneNode: cdata copy failed\n");
2028  }
2029  }
2030  break;
2031  case XML_TEXT_NODE:
2032  template = xsltGetTemplate(ctxt, cur, NULL);
2033  if (template) {
2034 #ifdef WITH_XSLT_DEBUG_PROCESS
2036  "xsltDefaultProcessOneNode: applying template for text %s\n",
2037  cur->content));
2038 #endif
2039  ctxt->xpathCtxt->contextSize = nbchild;
2040  ctxt->xpathCtxt->proximityPosition = childno;
2041  /*
2042  * Instantiate the xsl:template.
2043  */
2044  xsltApplyXSLTTemplate(ctxt, cur, template->content,
2045  template, params);
2046  } else /* if (ctxt->mode == NULL) */ {
2047 #ifdef WITH_XSLT_DEBUG_PROCESS
2048  if (cur->content == NULL) {
2050  "xsltDefaultProcessOneNode: copy empty text\n"));
2051  } else {
2053  "xsltDefaultProcessOneNode: copy text %s\n",
2054  cur->content));
2055  }
2056 #endif
2057  copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
2058  if (copy == NULL) {
2059  xsltTransformError(ctxt, NULL, cur,
2060  "xsltDefaultProcessOneNode: text copy failed\n");
2061  }
2062  }
2063  break;
2064  case XML_PI_NODE:
2065  case XML_COMMENT_NODE:
2066  template = xsltGetTemplate(ctxt, cur, NULL);
2067  if (template) {
2068 #ifdef WITH_XSLT_DEBUG_PROCESS
2069  if (cur->type == XML_PI_NODE) {
2071  "xsltDefaultProcessOneNode: template found for PI %s\n",
2072  cur->name));
2073  } else if (cur->type == XML_COMMENT_NODE) {
2075  "xsltDefaultProcessOneNode: template found for comment\n"));
2076  }
2077 #endif
2078  ctxt->xpathCtxt->contextSize = nbchild;
2079  ctxt->xpathCtxt->proximityPosition = childno;
2080  /*
2081  * Instantiate the xsl:template.
2082  */
2083  xsltApplyXSLTTemplate(ctxt, cur, template->content,
2084  template, params);
2085  }
2086  break;
2087  default:
2088  break;
2089  }
2090  cur = cur->next;
2091  }
2092  ctxt->xpathCtxt->contextSize = oldSize;
2093  ctxt->xpathCtxt->proximityPosition = oldPos;
2094 }
2095 
2105 void
2107  xsltStackElemPtr withParams)
2108 {
2109  xsltTemplatePtr templ;
2110  xmlNodePtr oldNode;
2111 
2112  templ = xsltGetTemplate(ctxt, contextNode, NULL);
2113  /*
2114  * If no template is found, apply the default rule.
2115  */
2116  if (templ == NULL) {
2117 #ifdef WITH_XSLT_DEBUG_PROCESS
2118  if (contextNode->type == XML_DOCUMENT_NODE) {
2120  "xsltProcessOneNode: no template found for /\n"));
2121  } else if (contextNode->type == XML_CDATA_SECTION_NODE) {
2123  "xsltProcessOneNode: no template found for CDATA\n"));
2124  } else if (contextNode->type == XML_ATTRIBUTE_NODE) {
2126  "xsltProcessOneNode: no template found for attribute %s\n",
2127  ((xmlAttrPtr) contextNode)->name));
2128  } else {
2130  "xsltProcessOneNode: no template found for %s\n", contextNode->name));
2131  }
2132 #endif
2133  oldNode = ctxt->node;
2134  ctxt->node = contextNode;
2135  xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
2136  ctxt->node = oldNode;
2137  return;
2138  }
2139 
2140  if (contextNode->type == XML_ATTRIBUTE_NODE) {
2141  xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2142  /*
2143  * Set the "current template rule".
2144  */
2145  ctxt->currentTemplateRule = templ;
2146 
2147 #ifdef WITH_XSLT_DEBUG_PROCESS
2149  "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2150  templ->match, contextNode->name));
2151 #endif
2152  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2153 
2154  ctxt->currentTemplateRule = oldCurTempRule;
2155  } else {
2156  xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2157  /*
2158  * Set the "current template rule".
2159  */
2160  ctxt->currentTemplateRule = templ;
2161 
2162 #ifdef WITH_XSLT_DEBUG_PROCESS
2163  if (contextNode->type == XML_DOCUMENT_NODE) {
2165  "xsltProcessOneNode: applying template '%s' for /\n",
2166  templ->match));
2167  } else {
2169  "xsltProcessOneNode: applying template '%s' for %s\n",
2170  templ->match, contextNode->name));
2171  }
2172 #endif
2173  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2174 
2175  ctxt->currentTemplateRule = oldCurTempRule;
2176  }
2177 }
2178 
2179 #ifdef WITH_DEBUGGER
2180 static xmlNodePtr
2181 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2182  xmlNodePtr contextNode,
2183  xmlNodePtr list,
2184  xsltTemplatePtr templ,
2185  int *addCallResult)
2186 {
2187  xmlNodePtr debugedNode = NULL;
2188 
2189  if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2190  if (templ) {
2191  *addCallResult = xslAddCall(templ, templ->elem);
2192  } else {
2193  *addCallResult = xslAddCall(NULL, list);
2194  }
2195  switch (ctxt->debugStatus) {
2197  case XSLT_DEBUG_QUIT:
2198  if (*addCallResult)
2199  xslDropCall();
2200  return(NULL);
2201  }
2202  if (templ) {
2203  xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2204  debugedNode = templ->elem;
2205  } else if (list) {
2206  xslHandleDebugger(list, contextNode, templ, ctxt);
2207  debugedNode = list;
2208  } else if (ctxt->inst) {
2209  xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2210  debugedNode = ctxt->inst;
2211  }
2212  }
2213  return(debugedNode);
2214 }
2215 #endif /* WITH_DEBUGGER */
2216 
2229 int
2232  int level)
2233 {
2234  if (ctxt->varsMax == 0) {
2235  ctxt->varsMax = 10;
2236  ctxt->varsTab =
2237  (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
2238  sizeof(ctxt->varsTab[0]));
2239  if (ctxt->varsTab == NULL) {
2240  xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
2241  return (-1);
2242  }
2243  }
2244  if (ctxt->varsNr >= ctxt->varsMax) {
2245  ctxt->varsMax *= 2;
2246  ctxt->varsTab =
2248  ctxt->varsMax *
2249  sizeof(ctxt->varsTab[0]));
2250  if (ctxt->varsTab == NULL) {
2251  xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2252  return (-1);
2253  }
2254  }
2255  ctxt->varsTab[ctxt->varsNr++] = variable;
2256  ctxt->vars = variable;
2257  variable->level = level;
2258  return(0);
2259 }
2260 
2267 static void
2269 {
2270  xmlDocPtr cur = ctxt->localRVT, tmp;
2271 
2272  if (cur == base)
2273  return;
2274  if (cur->prev != NULL)
2275  xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
2276 
2277  /* Reset localRVT early because some RVTs might be registered again. */
2278  ctxt->localRVT = base;
2279  if (base != NULL)
2280  base->prev = NULL;
2281 
2282  do {
2283  tmp = cur;
2284  cur = (xmlDocPtr) cur->next;
2285  if (tmp->psvi == XSLT_RVT_LOCAL) {
2286  xsltReleaseRVT(ctxt, tmp);
2287  } else if (tmp->psvi == XSLT_RVT_GLOBAL) {
2288  xsltRegisterPersistRVT(ctxt, tmp);
2289  } else if (tmp->psvi == XSLT_RVT_FUNC_RESULT) {
2290  /*
2291  * This will either register the RVT again or move it to the
2292  * context variable.
2293  */
2294  xsltRegisterLocalRVT(ctxt, tmp);
2295  tmp->psvi = XSLT_RVT_FUNC_RESULT;
2296  } else {
2298  "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2299  tmp->psvi);
2300  }
2301  } while (cur != base);
2302 }
2303 
2319 static void
2321  xmlNodePtr contextNode, xmlNodePtr list,
2322  xsltTemplatePtr templ)
2323 {
2324  xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2325  xmlNodePtr cur, insert, copy = NULL;
2326  int level = 0, oldVarsNr;
2327  xmlDocPtr oldLocalFragmentTop;
2328 
2329 #ifdef XSLT_REFACTORED
2331 #endif
2332 
2333 #ifdef WITH_DEBUGGER
2334  int addCallResult = 0;
2335  xmlNodePtr debuggedNode = NULL;
2336 #endif
2337 
2338  if (ctxt == NULL)
2339  return;
2340 
2341 #ifdef WITH_DEBUGGER
2342  if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2343  debuggedNode =
2344  xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2345  list, templ, &addCallResult);
2346  if (debuggedNode == NULL)
2347  return;
2348  }
2349 #endif
2350 
2351  if (list == NULL)
2352  return;
2353  CHECK_STOPPED;
2354 
2355  /*
2356  * Check for infinite recursion: stop if the maximum of nested templates
2357  * is excceeded. Adjust xsltMaxDepth if you need more.
2358  */
2359  if (ctxt->depth >= ctxt->maxTemplateDepth) {
2360  xsltTransformError(ctxt, NULL, list,
2361  "xsltApplySequenceConstructor: A potential infinite template "
2362  "recursion was detected.\n"
2363  "You can adjust xsltMaxDepth (--maxdepth) in order to "
2364  "raise the maximum number of nested template calls and "
2365  "variables/params (currently set to %d).\n",
2366  ctxt->maxTemplateDepth);
2367  xsltDebug(ctxt, contextNode, list, NULL);
2368  ctxt->state = XSLT_STATE_STOPPED;
2369  return;
2370  }
2371  ctxt->depth++;
2372 
2373  oldLocalFragmentTop = ctxt->localRVT;
2374  oldInsert = insert = ctxt->insert;
2375  oldInst = oldCurInst = ctxt->inst;
2376  oldContextNode = ctxt->node;
2377  /*
2378  * Save current number of variables on the stack; new vars are popped when
2379  * exiting.
2380  */
2381  oldVarsNr = ctxt->varsNr;
2382  /*
2383  * Process the sequence constructor.
2384  */
2385  cur = list;
2386  while (cur != NULL) {
2387  if (ctxt->opLimit != 0) {
2388  if (ctxt->opCount >= ctxt->opLimit) {
2389  xsltTransformError(ctxt, NULL, cur,
2390  "xsltApplySequenceConstructor: "
2391  "Operation limit exceeded\n");
2392  ctxt->state = XSLT_STATE_STOPPED;
2393  goto error;
2394  }
2395  ctxt->opCount += 1;
2396  }
2397 
2398  ctxt->inst = cur;
2399 
2400 #ifdef WITH_DEBUGGER
2401  switch (ctxt->debugStatus) {
2403  case XSLT_DEBUG_QUIT:
2404  break;
2405 
2406  }
2407 #endif
2408  /*
2409  * Test; we must have a valid insertion point.
2410  */
2411  if (insert == NULL) {
2412 
2413 #ifdef WITH_XSLT_DEBUG_PROCESS
2415  "xsltApplySequenceConstructor: insert == NULL !\n"));
2416 #endif
2417  goto error;
2418  }
2419 
2420 #ifdef WITH_DEBUGGER
2421  if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2422  xslHandleDebugger(cur, contextNode, templ, ctxt);
2423 #endif
2424 
2425 #ifdef XSLT_REFACTORED
2426  if (cur->type == XML_ELEMENT_NODE) {
2427  info = (xsltStylePreCompPtr) cur->psvi;
2428  /*
2429  * We expect a compiled representation on:
2430  * 1) XSLT instructions of this XSLT version (1.0)
2431  * (with a few exceptions)
2432  * 2) Literal result elements
2433  * 3) Extension instructions
2434  * 4) XSLT instructions of future XSLT versions
2435  * (forwards-compatible mode).
2436  */
2437  if (info == NULL) {
2438  /*
2439  * Handle the rare cases where we don't expect a compiled
2440  * representation on an XSLT element.
2441  */
2442  if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2443  xsltMessage(ctxt, contextNode, cur);
2444  goto skip_children;
2445  }
2446  /*
2447  * Something really went wrong:
2448  */
2449  xsltTransformError(ctxt, NULL, cur,
2450  "Internal error in xsltApplySequenceConstructor(): "
2451  "The element '%s' in the stylesheet has no compiled "
2452  "representation.\n",
2453  cur->name);
2454  goto skip_children;
2455  }
2456 
2457  if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2458  xsltStyleItemLRElementInfoPtr lrInfo =
2459  (xsltStyleItemLRElementInfoPtr) info;
2460  /*
2461  * Literal result elements
2462  * --------------------------------------------------------
2463  */
2464 #ifdef WITH_XSLT_DEBUG_PROCESS
2467  "xsltApplySequenceConstructor: copy literal result "
2468  "element '%s'\n", cur->name));
2469 #endif
2470  /*
2471  * Copy the raw element-node.
2472  * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2473  * == NULL)
2474  * goto error;
2475  */
2476  copy = xmlDocCopyNode(cur, insert->doc, 0);
2477  if (copy == NULL) {
2478  xsltTransformError(ctxt, NULL, cur,
2479  "Internal error in xsltApplySequenceConstructor(): "
2480  "Failed to copy literal result element '%s'.\n",
2481  cur->name);
2482  goto error;
2483  } else {
2484  /*
2485  * Add the element-node to the result tree.
2486  */
2487  copy->doc = ctxt->output;
2489  /*
2490  * Create effective namespaces declarations.
2491  * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2492  */
2493  if (lrInfo->effectiveNs != NULL) {
2494  xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2495  xmlNsPtr ns, lastns = NULL;
2496 
2497  while (effNs != NULL) {
2498  /*
2499  * Avoid generating redundant namespace
2500  * declarations; thus lookup if there is already
2501  * such a ns-decl in the result.
2502  */
2503  ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2504  if ((ns != NULL) &&
2505  (xmlStrEqual(ns->href, effNs->nsName)))
2506  {
2507  effNs = effNs->next;
2508  continue;
2509  }
2510  ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2511  if (ns == NULL) {
2512  xsltTransformError(ctxt, NULL, cur,
2513  "Internal error in "
2514  "xsltApplySequenceConstructor(): "
2515  "Failed to copy a namespace "
2516  "declaration.\n");
2517  goto error;
2518  }
2519 
2520  if (lastns == NULL)
2521  copy->nsDef = ns;
2522  else
2523  lastns->next =ns;
2524  lastns = ns;
2525 
2526  effNs = effNs->next;
2527  }
2528 
2529  }
2530  /*
2531  * NOTE that we don't need to apply ns-alising: this was
2532  * already done at compile-time.
2533  */
2534  if (cur->ns != NULL) {
2535  /*
2536  * If there's no such ns-decl in the result tree,
2537  * then xsltGetSpecialNamespace() will
2538  * create a ns-decl on the copied node.
2539  */
2540  copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2541  cur->ns->href, cur->ns->prefix, copy);
2542  } else {
2543  /*
2544  * Undeclare the default namespace if needed.
2545  * This can be skipped, if the result element has
2546  * no ns-decls, in which case the result element
2547  * obviously does not declare a default namespace;
2548  * AND there's either no parent, or the parent
2549  * element is in no namespace; this means there's no
2550  * default namespace is scope to care about.
2551  *
2552  * REVISIT: This might result in massive
2553  * generation of ns-decls if nodes in a default
2554  * namespaces are mixed with nodes in no namespace.
2555  *
2556  */
2557  if (copy->nsDef ||
2558  ((insert != NULL) &&
2559  (insert->type == XML_ELEMENT_NODE) &&
2560  (insert->ns != NULL)))
2561  {
2562  xsltGetSpecialNamespace(ctxt, cur,
2563  NULL, NULL, copy);
2564  }
2565  }
2566  }
2567  /*
2568  * SPEC XSLT 2.0 "Each attribute of the literal result
2569  * element, other than an attribute in the XSLT namespace,
2570  * is processed to produce an attribute for the element in
2571  * the result tree."
2572  * NOTE: See bug #341325.
2573  */
2574  if (cur->properties != NULL) {
2576  }
2577  } else if (IS_XSLT_ELEM_FAST(cur)) {
2578  /*
2579  * XSLT instructions
2580  * --------------------------------------------------------
2581  */
2582  if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2583  /*
2584  * We hit an unknown XSLT element.
2585  * Try to apply one of the fallback cases.
2586  */
2587  ctxt->insert = insert;
2588  if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2589  xsltTransformError(ctxt, NULL, cur,
2590  "The is no fallback behaviour defined for "
2591  "the unknown XSLT element '%s'.\n",
2592  cur->name);
2593  }
2594  ctxt->insert = oldInsert;
2595  } else if (info->func != NULL) {
2596  /*
2597  * Execute the XSLT instruction.
2598  */
2599  ctxt->insert = insert;
2600 
2601  info->func(ctxt, contextNode, cur,
2603 
2604  /*
2605  * Cleanup temporary tree fragments.
2606  */
2607  if (oldLocalFragmentTop != ctxt->localRVT)
2608  xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2609 
2610  ctxt->insert = oldInsert;
2611  } else if (info->type == XSLT_FUNC_VARIABLE) {
2612  xsltStackElemPtr tmpvar = ctxt->vars;
2613 
2614  xsltParseStylesheetVariable(ctxt, cur);
2615 
2616  if (tmpvar != ctxt->vars) {
2617  /*
2618  * TODO: Using a @tmpvar is an annoying workaround, but
2619  * the current mechanisms do not provide any other way
2620  * of knowing if the var was really pushed onto the
2621  * stack.
2622  */
2623  ctxt->vars->level = level;
2624  }
2625  } else if (info->type == XSLT_FUNC_MESSAGE) {
2626  /*
2627  * TODO: Won't be hit, since we don't compile xsl:message.
2628  */
2629  xsltMessage(ctxt, contextNode, cur);
2630  } else {
2631  xsltTransformError(ctxt, NULL, cur,
2632  "Unexpected XSLT element '%s'.\n", cur->name);
2633  }
2634  goto skip_children;
2635 
2636  } else {
2638  /*
2639  * Extension intructions (elements)
2640  * --------------------------------------------------------
2641  */
2642  if (cur->psvi == xsltExtMarker) {
2643  /*
2644  * The xsltExtMarker was set during the compilation
2645  * of extension instructions if there was no registered
2646  * handler for this specific extension function at
2647  * compile-time.
2648  * Libxslt will now lookup if a handler is
2649  * registered in the context of this transformation.
2650  */
2651  func = xsltExtElementLookup(ctxt, cur->name,
2652  cur->ns->href);
2653  } else
2654  func = ((xsltElemPreCompPtr) cur->psvi)->func;
2655 
2656  if (func == NULL) {
2657  /*
2658  * No handler available.
2659  * Try to execute fallback behaviour via xsl:fallback.
2660  */
2661 #ifdef WITH_XSLT_DEBUG_PROCESS
2664  "xsltApplySequenceConstructor: unknown extension %s\n",
2665  cur->name));
2666 #endif
2667  ctxt->insert = insert;
2668  if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2669  xsltTransformError(ctxt, NULL, cur,
2670  "Unknown extension instruction '{%s}%s'.\n",
2671  cur->ns->href, cur->name);
2672  }
2673  ctxt->insert = oldInsert;
2674  } else {
2675  /*
2676  * Execute the handler-callback.
2677  */
2678 #ifdef WITH_XSLT_DEBUG_PROCESS
2680  "xsltApplySequenceConstructor: extension construct %s\n",
2681  cur->name));
2682 #endif
2683  /*
2684  * Disable the xsltCopyTextString optimization for
2685  * extension elements. Extensions could append text using
2686  * xmlAddChild which will free the buffer pointed to by
2687  * 'lasttext'. This buffer could later be reallocated with
2688  * a different size than recorded in 'lasttsize'. See bug
2689  * #777432.
2690  */
2691  if (cur->psvi == xsltExtMarker) {
2692  ctxt->lasttext = NULL;
2693  }
2694 
2695  ctxt->insert = insert;
2696 
2697  func(ctxt, contextNode, cur, cur->psvi);
2698 
2699  /*
2700  * Cleanup temporary tree fragments.
2701  */
2702  if (oldLocalFragmentTop != ctxt->localRVT)
2703  xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2704 
2705  ctxt->insert = oldInsert;
2706  }
2707  goto skip_children;
2708  }
2709 
2710  } else if (XSLT_IS_TEXT_NODE(cur)) {
2711  /*
2712  * Text
2713  * ------------------------------------------------------------
2714  */
2715 #ifdef WITH_XSLT_DEBUG_PROCESS
2716  if (cur->name == xmlStringTextNoenc) {
2719  "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2720  cur->content));
2721  } else {
2724  "xsltApplySequenceConstructor: copy text '%s'\n",
2725  cur->content));
2726  }
2727 #endif
2728  if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2729  goto error;
2730  }
2731 
2732 #else /* XSLT_REFACTORED */
2733 
2734  if (IS_XSLT_ELEM(cur)) {
2735  /*
2736  * This is an XSLT node
2737  */
2739 
2740  if (info == NULL) {
2741  if (IS_XSLT_NAME(cur, "message")) {
2742  xsltMessage(ctxt, contextNode, cur);
2743  } else {
2744  /*
2745  * That's an error try to apply one of the fallback cases
2746  */
2747  ctxt->insert = insert;
2748  if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2750  "xsltApplySequenceConstructor: %s was not compiled\n",
2751  cur->name);
2752  }
2753  ctxt->insert = oldInsert;
2754  }
2755  goto skip_children;
2756  }
2757 
2758  if (info->func != NULL) {
2759  oldCurInst = ctxt->inst;
2760  ctxt->inst = cur;
2761  ctxt->insert = insert;
2762 
2763  info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2764 
2765  /*
2766  * Cleanup temporary tree fragments.
2767  */
2768  if (oldLocalFragmentTop != ctxt->localRVT)
2769  xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2770 
2771  ctxt->insert = oldInsert;
2772  ctxt->inst = oldCurInst;
2773  goto skip_children;
2774  }
2775 
2776  if (IS_XSLT_NAME(cur, "variable")) {
2777  xsltStackElemPtr tmpvar = ctxt->vars;
2778 
2779  oldCurInst = ctxt->inst;
2780  ctxt->inst = cur;
2781 
2782  xsltParseStylesheetVariable(ctxt, cur);
2783 
2784  ctxt->inst = oldCurInst;
2785 
2786  if (tmpvar != ctxt->vars) {
2787  /*
2788  * TODO: Using a @tmpvar is an annoying workaround, but
2789  * the current mechanisms do not provide any other way
2790  * of knowing if the var was really pushed onto the
2791  * stack.
2792  */
2793  ctxt->vars->level = level;
2794  }
2795  } else if (IS_XSLT_NAME(cur, "message")) {
2796  xsltMessage(ctxt, contextNode, cur);
2797  } else {
2798  xsltTransformError(ctxt, NULL, cur,
2799  "Unexpected XSLT element '%s'.\n", cur->name);
2800  }
2801  goto skip_children;
2802  } else if ((cur->type == XML_TEXT_NODE) ||
2803  (cur->type == XML_CDATA_SECTION_NODE)) {
2804 
2805  /*
2806  * This text comes from the stylesheet
2807  * For stylesheets, the set of whitespace-preserving
2808  * element names consists of just xsl:text.
2809  */
2810 #ifdef WITH_XSLT_DEBUG_PROCESS
2811  if (cur->type == XML_CDATA_SECTION_NODE) {
2813  "xsltApplySequenceConstructor: copy CDATA text %s\n",
2814  cur->content));
2815  } else if (cur->name == xmlStringTextNoenc) {
2817  "xsltApplySequenceConstructor: copy unescaped text %s\n",
2818  cur->content));
2819  } else {
2821  "xsltApplySequenceConstructor: copy text %s\n",
2822  cur->content));
2823  }
2824 #endif
2825  if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2826  goto error;
2827  } else if ((cur->type == XML_ELEMENT_NODE) &&
2828  (cur->ns != NULL) && (cur->psvi != NULL)) {
2829  xsltTransformFunction function;
2830 
2831  oldCurInst = ctxt->inst;
2832  ctxt->inst = cur;
2833  /*
2834  * Flagged as an extension element
2835  */
2836  if (cur->psvi == xsltExtMarker)
2837  function = xsltExtElementLookup(ctxt, cur->name,
2838  cur->ns->href);
2839  else
2840  function = ((xsltElemPreCompPtr) cur->psvi)->func;
2841 
2842  if (function == NULL) {
2843  xmlNodePtr child;
2844  int found = 0;
2845 
2846 #ifdef WITH_XSLT_DEBUG_PROCESS
2848  "xsltApplySequenceConstructor: unknown extension %s\n",
2849  cur->name));
2850 #endif
2851  /*
2852  * Search if there are fallbacks
2853  */
2854  ctxt->insert = insert;
2855  child = cur->children;
2856  while (child != NULL) {
2857  if ((IS_XSLT_ELEM(child)) &&
2858  (IS_XSLT_NAME(child, "fallback")))
2859  {
2860  found = 1;
2861  xsltApplySequenceConstructor(ctxt, contextNode,
2862  child->children, NULL);
2863  }
2864  child = child->next;
2865  }
2866  ctxt->insert = oldInsert;
2867 
2868  if (!found) {
2869  xsltTransformError(ctxt, NULL, cur,
2870  "xsltApplySequenceConstructor: failed to find extension %s\n",
2871  cur->name);
2872  }
2873  } else {
2874 #ifdef WITH_XSLT_DEBUG_PROCESS
2876  "xsltApplySequenceConstructor: extension construct %s\n",
2877  cur->name));
2878 #endif
2879 
2880  /*
2881  * Disable the xsltCopyTextString optimization for
2882  * extension elements. Extensions could append text using
2883  * xmlAddChild which will free the buffer pointed to by
2884  * 'lasttext'. This buffer could later be reallocated with
2885  * a different size than recorded in 'lasttsize'. See bug
2886  * #777432.
2887  */
2888  if (cur->psvi == xsltExtMarker) {
2889  ctxt->lasttext = NULL;
2890  }
2891 
2892  ctxt->insert = insert;
2893 
2894  function(ctxt, contextNode, cur, cur->psvi);
2895  /*
2896  * Cleanup temporary tree fragments.
2897  */
2898  if (oldLocalFragmentTop != ctxt->localRVT)
2899  xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2900 
2901  ctxt->insert = oldInsert;
2902 
2903  }
2904  ctxt->inst = oldCurInst;
2905  goto skip_children;
2906  } else if (cur->type == XML_ELEMENT_NODE) {
2907 #ifdef WITH_XSLT_DEBUG_PROCESS
2909  "xsltApplySequenceConstructor: copy node %s\n",
2910  cur->name));
2911 #endif
2912  oldCurInst = ctxt->inst;
2913  ctxt->inst = cur;
2914 
2915  if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2916  goto error;
2917  /*
2918  * Add extra namespaces inherited from the current template
2919  * if we are in the first level children and this is a
2920  * "real" template.
2921  */
2922  if ((templ != NULL) && (oldInsert == insert) &&
2923  (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2924  int i;
2925  xmlNsPtr ns, ret;
2926 
2927  for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2928  const xmlChar *URI = NULL;
2930  ns = ctxt->templ->inheritedNs[i];
2931 
2932  /* Note that the XSLT namespace was already excluded
2933  * in xsltGetInheritedNsList().
2934  */
2935 #if 0
2936  if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2937  continue;
2938 #endif
2939  style = ctxt->style;
2940  while (style != NULL) {
2941  if (style->nsAliases != NULL)
2942  URI = (const xmlChar *)
2943  xmlHashLookup(style->nsAliases, ns->href);
2944  if (URI != NULL)
2945  break;
2946 
2948  }
2949  if (URI == UNDEFINED_DEFAULT_NS)
2950  continue;
2951  if (URI == NULL)
2952  URI = ns->href;
2953  /*
2954  * TODO: The following will still be buggy for the
2955  * non-refactored code.
2956  */
2957  ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2958  if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2959  {
2960  xmlNewNs(copy, URI, ns->prefix);
2961  }
2962  }
2963  if (copy->ns != NULL) {
2964  /*
2965  * Fix the node namespace if needed
2966  */
2967  copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2968  }
2969  }
2970  /*
2971  * all the attributes are directly inherited
2972  */
2973  if (cur->properties != NULL) {
2975  }
2976  ctxt->inst = oldCurInst;
2977  }
2978 #endif /* else of XSLT_REFACTORED */
2979 
2980  /*
2981  * Descend into content in document order.
2982  */
2983  if (cur->children != NULL) {
2984  if (cur->children->type != XML_ENTITY_DECL) {
2985  cur = cur->children;
2986  level++;
2987  if (copy != NULL)
2988  insert = copy;
2989  continue;
2990  }
2991  }
2992 
2993 skip_children:
2994  /*
2995  * If xslt:message was just processed, we might have hit a
2996  * terminate='yes'; if so, then break the loop and clean up.
2997  * TODO: Do we need to check this also before trying to descend
2998  * into the content?
2999  */
3000  if (ctxt->state == XSLT_STATE_STOPPED)
3001  break;
3002  if (cur->next != NULL) {
3003  cur = cur->next;
3004  continue;
3005  }
3006 
3007  do {
3008  cur = cur->parent;
3009  level--;
3010  /*
3011  * Pop variables/params (xsl:variable and xsl:param).
3012  */
3013  if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
3014  xsltLocalVariablePop(ctxt, oldVarsNr, level);
3015  }
3016 
3017  insert = insert->parent;
3018  if (cur == NULL)
3019  break;
3020  if (cur == list->parent) {
3021  cur = NULL;
3022  break;
3023  }
3024  if (cur->next != NULL) {
3025  cur = cur->next;
3026  break;
3027  }
3028  } while (cur != NULL);
3029  }
3030 
3031 error:
3032  /*
3033  * In case of errors: pop remaining variables.
3034  */
3035  if (ctxt->varsNr > oldVarsNr)
3036  xsltLocalVariablePop(ctxt, oldVarsNr, -1);
3037 
3038  ctxt->node = oldContextNode;
3039  ctxt->inst = oldInst;
3040  ctxt->insert = oldInsert;
3041 
3042  ctxt->depth--;
3043 
3044 #ifdef WITH_DEBUGGER
3045  if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3046  xslDropCall();
3047  }
3048 #endif
3049 }
3050 
3051 /*
3052 * xsltApplyXSLTTemplate:
3053 * @ctxt: a XSLT transformation context
3054 * @contextNode: the node in the source tree.
3055 * @list: the nodes of a sequence constructor;
3056 * (plus leading xsl:param elements)
3057 * @templ: the compiled xsl:template declaration;
3058 * NULL if a sequence constructor
3059 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
3060 *
3061 * Called by:
3062 * - xsltApplyImports()
3063 * - xsltCallTemplate()
3064 * - xsltDefaultProcessOneNode()
3065 * - xsltProcessOneNode()
3066 */
3067 static void
3069  xmlNodePtr contextNode,
3070  xmlNodePtr list,
3071  xsltTemplatePtr templ,
3072  xsltStackElemPtr withParams)
3073 {
3074  int oldVarsBase = 0;
3075  xmlNodePtr cur;
3076  xsltStackElemPtr tmpParam = NULL;
3077  xmlDocPtr oldUserFragmentTop;
3078 #ifdef WITH_PROFILER
3079  long start = 0;
3080 #endif
3081 
3082 #ifdef XSLT_REFACTORED
3083  xsltStyleItemParamPtr iparam;
3084 #else
3085  xsltStylePreCompPtr iparam;
3086 #endif
3087 
3088 #ifdef WITH_DEBUGGER
3089  int addCallResult = 0;
3090 #endif
3091 
3092  if (ctxt == NULL)
3093  return;
3094  if (templ == NULL) {
3095  xsltTransformError(ctxt, NULL, list,
3096  "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3097  return;
3098  }
3099 
3100 #ifdef WITH_DEBUGGER
3101  if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
3102  if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
3103  list, templ, &addCallResult) == NULL)
3104  return;
3105  }
3106 #endif
3107 
3108  if (list == NULL)
3109  return;
3110  CHECK_STOPPED;
3111 
3112  if (ctxt->varsNr >= ctxt->maxTemplateVars)
3113  {
3114  xsltTransformError(ctxt, NULL, list,
3115  "xsltApplyXSLTTemplate: A potential infinite template recursion "
3116  "was detected.\n"
3117  "You can adjust maxTemplateVars (--maxvars) in order to "
3118  "raise the maximum number of variables/params (currently set to %d).\n",
3119  ctxt->maxTemplateVars);
3120  xsltDebug(ctxt, contextNode, list, NULL);
3121  ctxt->state = XSLT_STATE_STOPPED;
3122  return;
3123  }
3124 
3125  oldUserFragmentTop = ctxt->tmpRVT;
3126  ctxt->tmpRVT = NULL;
3127 
3128  /*
3129  * Initiate a distinct scope of local params/variables.
3130  */
3131  oldVarsBase = ctxt->varsBase;
3132  ctxt->varsBase = ctxt->varsNr;
3133 
3134  ctxt->node = contextNode;
3135 
3136 #ifdef WITH_PROFILER
3137  if (ctxt->profile) {
3138  templ->nbCalls++;
3139  start = xsltTimestamp();
3140  profPush(ctxt, 0);
3141  profCallgraphAdd(templ, ctxt->templ);
3142  }
3143 #endif
3144 
3145  /*
3146  * Push the xsl:template declaration onto the stack.
3147  */
3148  templPush(ctxt, templ);
3149 
3150 #ifdef WITH_XSLT_DEBUG_PROCESS
3151  if (templ->name != NULL)
3153  "applying xsl:template '%s'\n", templ->name));
3154 #endif
3155  /*
3156  * Process xsl:param instructions and skip those elements for
3157  * further processing.
3158  */
3159  cur = list;
3160  do {
3161  if (cur->type == XML_TEXT_NODE) {
3162  cur = cur->next;
3163  continue;
3164  }
3165  if ((cur->type != XML_ELEMENT_NODE) ||
3166  (cur->name[0] != 'p') ||
3167  (cur->psvi == NULL) ||
3168  (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
3169  (! IS_XSLT_ELEM(cur)))
3170  {
3171  break;
3172  }
3173 
3174  list = cur->next;
3175 
3176 #ifdef XSLT_REFACTORED
3177  iparam = (xsltStyleItemParamPtr) cur->psvi;
3178 #else
3179  iparam = (xsltStylePreCompPtr) cur->psvi;
3180 #endif
3181 
3182  /*
3183  * Substitute xsl:param for a given xsl:with-param.
3184  * Since the XPath expression will reference the params/vars
3185  * by index, we need to slot the xsl:with-params in the
3186  * order of encountered xsl:params to keep the sequence of
3187  * params/variables in the stack exactly as it was at
3188  * compile time,
3189  */
3190  tmpParam = NULL;
3191  if (withParams) {
3192  tmpParam = withParams;
3193  do {
3194  if ((tmpParam->name == (iparam->name)) &&
3195  (tmpParam->nameURI == (iparam->ns)))
3196  {
3197  /*
3198  * Push the caller-parameter.
3199  */
3200  xsltLocalVariablePush(ctxt, tmpParam, -1);
3201  break;
3202  }
3203  tmpParam = tmpParam->next;
3204  } while (tmpParam != NULL);
3205  }
3206  /*
3207  * Push the xsl:param.
3208  */
3209  if (tmpParam == NULL) {
3210  /*
3211  * Note that we must assume that the added parameter
3212  * has a @depth of 0.
3213  */
3214  xsltParseStylesheetParam(ctxt, cur);
3215  }
3216  cur = cur->next;
3217  } while (cur != NULL);
3218  /*
3219  * Process the sequence constructor.
3220  */
3221  xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3222 
3223  /*
3224  * Remove remaining xsl:param and xsl:with-param items from
3225  * the stack. Don't free xsl:with-param items.
3226  */
3227  if (ctxt->varsNr > ctxt->varsBase)
3229  ctxt->varsBase = oldVarsBase;
3230 
3231  /*
3232  * Release user-created fragments stored in the scope
3233  * of xsl:template. Note that this mechanism is deprecated:
3234  * user code should now use xsltRegisterLocalRVT() instead
3235  * of the obsolete xsltRegisterTmpRVT().
3236  */
3237  if (ctxt->tmpRVT) {
3238  xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3239 
3240  while (curdoc != NULL) {
3241  tmp = curdoc;
3242  curdoc = (xmlDocPtr) curdoc->next;
3243  xsltReleaseRVT(ctxt, tmp);
3244  }
3245  }
3246  ctxt->tmpRVT = oldUserFragmentTop;
3247 
3248  /*
3249  * Pop the xsl:template declaration from the stack.
3250  */
3251  templPop(ctxt);
3252 
3253 #ifdef WITH_PROFILER
3254  if (ctxt->profile) {
3255  long spent, child, total, end;
3256 
3257  end = xsltTimestamp();
3258  child = profPop(ctxt);
3259  total = end - start;
3260  spent = total - child;
3261  if (spent <= 0) {
3262  /*
3263  * Not possible unless the original calibration failed
3264  * we can try to correct it on the fly.
3265  */
3266  xsltCalibrateAdjust(spent);
3267  spent = 0;
3268  }
3269 
3270  templ->time += spent;
3271  if (ctxt->profNr > 0)
3272  ctxt->profTab[ctxt->profNr - 1] += total;
3273  }
3274 #endif
3275 
3276 #ifdef WITH_DEBUGGER
3277  if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3278  xslDropCall();
3279  }
3280 #endif
3281 }
3282 
3283 
3314 void
3316  xmlNodePtr contextNode,
3317  xmlNodePtr list,
3320 {
3321  if ((ctxt == NULL) || (list == NULL))
3322  return;
3323  CHECK_STOPPED;
3324 
3325  if (params) {
3326  /*
3327  * This code should be obsolete - was previously used
3328  * by libexslt/functions.c, but due to bug 381319 the
3329  * logic there was changed.
3330  */
3331  int oldVarsNr = ctxt->varsNr;
3332 
3333  /*
3334  * Push the given xsl:param(s) onto the variable stack.
3335  */
3336  while (params != NULL) {
3337  xsltLocalVariablePush(ctxt, params, -1);
3338  params = params->next;
3339  }
3340  xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3341  /*
3342  * Pop the given xsl:param(s) from the stack but don't free them.
3343  */
3344  xsltLocalVariablePop(ctxt, oldVarsNr, -2);
3345  } else
3346  xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3347 }
3348 
3349 /************************************************************************
3350  * *
3351  * XSLT-1.1 extensions *
3352  * *
3353  ************************************************************************/
3354 
3364 void
3366  xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3367 {
3368 #ifdef XSLT_REFACTORED
3369  xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
3370 #else
3371  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3372 #endif
3374  int ret;
3375  xmlChar *filename = NULL, *prop, *elements;
3376  xmlChar *element, *end;
3377  xmlDocPtr res = NULL;
3378  xmlDocPtr oldOutput;
3379  xmlNodePtr oldInsert, root;
3380  const char *oldOutputFile;
3381  xsltOutputType oldType;
3382  xmlChar *URL = NULL;
3383  const xmlChar *method;
3384  const xmlChar *doctypePublic;
3385  const xmlChar *doctypeSystem;
3386  const xmlChar *version;
3387  const xmlChar *encoding;
3388  int redirect_write_append = 0;
3389 
3390  if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
3391  return;
3392 
3393  if (comp->filename == NULL) {
3394 
3395  if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
3396  /*
3397  * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3398  * (http://icl.com/saxon)
3399  * The @file is in no namespace.
3400  */
3401 #ifdef WITH_XSLT_DEBUG_EXTRA
3403  "Found saxon:output extension\n");
3404 #endif
3405  URL = xsltEvalAttrValueTemplate(ctxt, inst,
3406  (const xmlChar *) "file",
3408 
3409  if (URL == NULL)
3410  URL = xsltEvalAttrValueTemplate(ctxt, inst,
3411  (const xmlChar *) "href",
3413  } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
3414 #ifdef WITH_XSLT_DEBUG_EXTRA
3416  "Found xalan:write extension\n");
3417 #endif
3418  URL = xsltEvalAttrValueTemplate(ctxt, inst,
3419  (const xmlChar *)
3420  "select",
3422  if (URL != NULL) {
3423  xmlXPathCompExprPtr cmp;
3424  xmlChar *val;
3425 
3426  /*
3427  * Trying to handle bug #59212
3428  * The value of the "select" attribute is an
3429  * XPath expression.
3430  * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3431  */
3432  cmp = xmlXPathCtxtCompile(ctxt->xpathCtxt, URL);
3433  val = xsltEvalXPathString(ctxt, cmp);
3434  xmlXPathFreeCompExpr(cmp);
3435  xmlFree(URL);
3436  URL = val;
3437  }
3438  if (URL == NULL)
3439  URL = xsltEvalAttrValueTemplate(ctxt, inst,
3440  (const xmlChar *)
3441  "file",
3443  if (URL == NULL)
3444  URL = xsltEvalAttrValueTemplate(ctxt, inst,
3445  (const xmlChar *)
3446  "href",
3448  } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
3449  URL = xsltEvalAttrValueTemplate(ctxt, inst,
3450  (const xmlChar *) "href",
3451  NULL);
3452  }
3453 
3454  } else {
3455  URL = xmlStrdup(comp->filename);
3456  }
3457 
3458  if (URL == NULL) {
3459  xsltTransformError(ctxt, NULL, inst,
3460  "xsltDocumentElem: href/URI-Reference not found\n");
3461  return;
3462  }
3463 
3464  /*
3465  * If the computation failed, it's likely that the URL wasn't escaped
3466  */
3467  filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
3468  if (filename == NULL) {
3469  xmlChar *escURL;
3470 
3471  escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
3472  if (escURL != NULL) {
3473  filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
3474  xmlFree(escURL);
3475  }
3476  }
3477 
3478  if (filename == NULL) {
3479  xsltTransformError(ctxt, NULL, inst,
3480  "xsltDocumentElem: URL computation failed for %s\n",
3481  URL);
3482  xmlFree(URL);
3483  return;
3484  }
3485 
3486  /*
3487  * Security checking: can we write to this resource
3488  */
3489  if (ctxt->sec != NULL) {
3490  ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
3491  if (ret <= 0) {
3492  if (ret == 0)
3493  xsltTransformError(ctxt, NULL, inst,
3494  "xsltDocumentElem: write rights for %s denied\n",
3495  filename);
3496  xmlFree(URL);
3497  xmlFree(filename);
3498  return;
3499  }
3500  }
3501 
3502  oldOutputFile = ctxt->outputFile;
3503  oldOutput = ctxt->output;
3504  oldInsert = ctxt->insert;
3505  oldType = ctxt->type;
3506  ctxt->outputFile = (const char *) filename;
3507 
3509  if (style == NULL) {
3510  xsltTransformError(ctxt, NULL, inst,
3511  "xsltDocumentElem: out of memory\n");
3512  goto error;
3513  }
3514 
3515  /*
3516  * Version described in 1.1 draft allows full parameterization
3517  * of the output.
3518  */
3519  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3520  (const xmlChar *) "version",
3521  NULL);
3522  if (prop != NULL) {
3523  if (style->version != NULL)
3524  xmlFree(style->version);
3525  style->version = prop;
3526  }
3527  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3528  (const xmlChar *) "encoding",
3529  NULL);
3530  if (prop != NULL) {
3531  if (style->encoding != NULL)
3532  xmlFree(style->encoding);
3533  style->encoding = prop;
3534  }
3535  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3536  (const xmlChar *) "method",
3537  NULL);
3538  if (prop != NULL) {
3539  const xmlChar *URI;
3540 
3541  if (style->method != NULL)
3542  xmlFree(style->method);
3543  style->method = NULL;
3544  if (style->methodURI != NULL)
3545  xmlFree(style->methodURI);
3546  style->methodURI = NULL;
3547 
3548  URI = xsltGetQNameURI(inst, &prop);
3549  if (prop == NULL) {
3550  if (style != NULL) style->errors++;
3551  } else if (URI == NULL) {
3552  if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3553  (xmlStrEqual(prop, (const xmlChar *) "html")) ||
3554  (xmlStrEqual(prop, (const xmlChar *) "text"))) {
3555  style->method = prop;
3556  } else {
3557  xsltTransformError(ctxt, NULL, inst,
3558  "invalid value for method: %s\n", prop);
3559  if (style != NULL) style->warnings++;
3560  }
3561  } else {
3562  style->method = prop;
3563  style->methodURI = xmlStrdup(URI);
3564  }
3565  }
3566  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3567  (const xmlChar *)
3568  "doctype-system", NULL);
3569  if (prop != NULL) {
3570  if (style->doctypeSystem != NULL)
3571  xmlFree(style->doctypeSystem);
3572  style->doctypeSystem = prop;
3573  }
3574  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3575  (const xmlChar *)
3576  "doctype-public", NULL);
3577  if (prop != NULL) {
3578  if (style->doctypePublic != NULL)
3579  xmlFree(style->doctypePublic);
3580  style->doctypePublic = prop;
3581  }
3582  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3583  (const xmlChar *) "standalone",
3584  NULL);
3585  if (prop != NULL) {
3586  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3587  style->standalone = 1;
3588  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3589  style->standalone = 0;
3590  } else {
3591  xsltTransformError(ctxt, NULL, inst,
3592  "invalid value for standalone: %s\n",
3593  prop);
3594  if (style != NULL) style->warnings++;
3595  }
3596  xmlFree(prop);
3597  }
3598 
3599  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3600  (const xmlChar *) "indent",
3601  NULL);
3602  if (prop != NULL) {
3603  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3604  style->indent = 1;
3605  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3606  style->indent = 0;
3607  } else {
3608  xsltTransformError(ctxt, NULL, inst,
3609  "invalid value for indent: %s\n", prop);
3610  if (style != NULL) style->warnings++;
3611  }
3612  xmlFree(prop);
3613  }
3614 
3615  prop = xsltEvalAttrValueTemplate(ctxt, inst,
3616  (const xmlChar *)
3617  "omit-xml-declaration",
3618  NULL);
3619  if (prop != NULL) {
3620  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3621  style->omitXmlDeclaration = 1;
3622  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3623  style->omitXmlDeclaration = 0;
3624  } else {
3625  xsltTransformError(ctxt, NULL, inst,
3626  "invalid value for omit-xml-declaration: %s\n",
3627  prop);
3628  if (style != NULL) style->warnings++;
3629  }
3630  xmlFree(prop);
3631  }
3632 
3633  elements = xsltEvalAttrValueTemplate(ctxt, inst,
3634  (const xmlChar *)
3635  "cdata-section-elements",
3636  NULL);
3637  if (elements != NULL) {
3638  if (style->stripSpaces == NULL)
3639  style->stripSpaces = xmlHashCreate(10);
3640  if (style->stripSpaces == NULL)
3641  return;
3642 
3643  element = elements;
3644  while (*element != 0) {
3645  while (IS_BLANK_CH(*element))
3646  element++;
3647  if (*element == 0)
3648  break;
3649  end = element;
3650  while ((*end != 0) && (!IS_BLANK_CH(*end)))
3651  end++;
3653  if (element) {
3654  const xmlChar *URI;
3655 
3656 #ifdef WITH_XSLT_DEBUG_PARSING
3658  "add cdata section output element %s\n",
3659  element);
3660 #endif
3661  URI = xsltGetQNameURI(inst, &element);
3662 
3663  xmlHashAddEntry2(style->stripSpaces, element, URI,
3664  (xmlChar *) "cdata");
3665  xmlFree(element);
3666  }
3667  element = end;
3668  }
3669  xmlFree(elements);
3670  }
3671 
3672  /*
3673  * Create a new document tree and process the element template
3674  */
3676  XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3677  XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3680 
3681  if ((method != NULL) &&
3682  (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3683  if (xmlStrEqual(method, (const xmlChar *) "html")) {
3684  ctxt->type = XSLT_OUTPUT_HTML;
3685  if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3686  res = htmlNewDoc(doctypeSystem, doctypePublic);
3687  else {
3688  if (version != NULL) {
3689 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3690  xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3691 #endif
3692  }
3693  res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3694  }
3695  if (res == NULL)
3696  goto error;
3697  res->dict = ctxt->dict;
3698  xmlDictReference(res->dict);
3699  } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3700  xsltTransformError(ctxt, NULL, inst,
3701  "xsltDocumentElem: unsupported method xhtml\n");
3702  ctxt->type = XSLT_OUTPUT_HTML;
3703  res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3704  if (res == NULL)
3705  goto error;
3706  res->dict = ctxt->dict;
3707  xmlDictReference(res->dict);
3708  } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3709  ctxt->type = XSLT_OUTPUT_TEXT;
3710  res = xmlNewDoc(style->version);
3711  if (res == NULL)
3712  goto error;
3713  res->dict = ctxt->dict;
3714  xmlDictReference(res->dict);
3715 #ifdef WITH_XSLT_DEBUG
3717  "reusing transformation dict for output\n");
3718 #endif
3719  } else {
3720  xsltTransformError(ctxt, NULL, inst,
3721  "xsltDocumentElem: unsupported method (%s)\n",
3722  method);
3723  goto error;
3724  }
3725  } else {
3726  ctxt->type = XSLT_OUTPUT_XML;
3727  res = xmlNewDoc(style->version);
3728  if (res == NULL)
3729  goto error;
3730  res->dict = ctxt->dict;
3731  xmlDictReference(res->dict);
3732 #ifdef WITH_XSLT_DEBUG
3734  "reusing transformation dict for output\n");
3735 #endif
3736  }
3737  res->charset = XML_CHAR_ENCODING_UTF8;
3738  if (encoding != NULL)
3739  res->encoding = xmlStrdup(encoding);
3740  ctxt->output = res;
3741  ctxt->insert = (xmlNodePtr) res;
3743 
3744  /*
3745  * Do some post processing work depending on the generated output
3746  */
3748  if (root != NULL) {
3749  const xmlChar *doctype = NULL;
3750 
3751  if ((root->ns != NULL) && (root->ns->prefix != NULL))
3752  doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3753  if (doctype == NULL)
3754  doctype = root->name;
3755 
3756  /*
3757  * Apply the default selection of the method
3758  */
3759  if ((method == NULL) &&
3760  (root->ns == NULL) &&
3761  (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3762  xmlNodePtr tmp;
3763 
3764  tmp = res->children;
3765  while ((tmp != NULL) && (tmp != root)) {
3766  if (tmp->type == XML_ELEMENT_NODE)
3767  break;
3768  if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3769  break;
3770  tmp = tmp->next;
3771  }
3772  if (tmp == root) {
3773  ctxt->type = XSLT_OUTPUT_HTML;
3774  res->type = XML_HTML_DOCUMENT_NODE;
3775  if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3776  res->intSubset = xmlCreateIntSubset(res, doctype,
3777  doctypePublic,
3778  doctypeSystem);
3779 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3780  } else if (version != NULL) {
3781  xsltGetHTMLIDs(version, &doctypePublic,
3782  &doctypeSystem);
3783  if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3784  res->intSubset =
3785  xmlCreateIntSubset(res, doctype,
3786  doctypePublic,
3787  doctypeSystem);
3788 #endif
3789  }
3790  }
3791 
3792  }
3793  if (ctxt->type == XSLT_OUTPUT_XML) {
3794  XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3795  XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3796  if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3797  res->intSubset = xmlCreateIntSubset(res, doctype,
3798  doctypePublic,
3799  doctypeSystem);
3800  }
3801  }
3802 
3803  /*
3804  * Calls to redirect:write also take an optional attribute append.
3805  * Attribute append="true|yes" which will attempt to simply append
3806  * to an existing file instead of always opening a new file. The
3807  * default behavior of always overwriting the file still happens
3808  * if we do not specify append.
3809  * Note that append use will forbid use of remote URI target.
3810  */
3811  prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
3812  NULL);
3813  if (prop != NULL) {
3814  if (xmlStrEqual(prop, (const xmlChar *) "true") ||
3815  xmlStrEqual(prop, (const xmlChar *) "yes")) {
3816  style->omitXmlDeclaration = 1;
3817  redirect_write_append = 1;
3818  } else
3819  style->omitXmlDeclaration = 0;
3820  xmlFree(prop);
3821  }
3822 
3823  if (redirect_write_append) {
3824  FILE *f;
3825 
3826  f = fopen((const char *) filename, "ab");
3827  if (f == NULL) {
3828  ret = -1;
3829  } else {
3831  fclose(f);
3832  }
3833  } else {
3834  ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
3835  }
3836  if (ret < 0) {
3837  xsltTransformError(ctxt, NULL, inst,
3838  "xsltDocumentElem: unable to save to %s\n",
3839  filename);
3840 #ifdef WITH_XSLT_DEBUG_EXTRA
3841  } else {
3843  "Wrote %d bytes to %s\n", ret, filename);
3844 #endif
3845  }
3846 
3847  error:
3848  ctxt->output = oldOutput;
3849  ctxt->insert = oldInsert;
3850  ctxt->type = oldType;
3851  ctxt->outputFile = oldOutputFile;
3852  if (URL != NULL)
3853  xmlFree(URL);
3854  if (filename != NULL)
3855  xmlFree(filename);
3856  if (style != NULL)
3858  if (res != NULL)
3859  xmlFreeDoc(res);
3860 }
3861 
3862 /************************************************************************
3863  * *
3864  * Most of the XSLT-1.0 transformations *
3865  * *
3866  ************************************************************************/
3867 
3878 void
3881  xsltElemPreCompPtr comp) {
3882  if (comp == NULL) {
3883  xsltTransformError(ctxt, NULL, inst,
3884  "xsl:sort : compilation failed\n");
3885  return;
3886  }
3887  xsltTransformError(ctxt, NULL, inst,
3888  "xsl:sort : improper use this should not be reached\n");
3889 }
3890 
3900 void
3902  xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3903 {
3904 #ifdef XSLT_REFACTORED
3905  xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3906 #else
3907  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3908 #endif
3909  xmlNodePtr copy, oldInsert;
3910 
3911  oldInsert = ctxt->insert;
3912  if (ctxt->insert != NULL) {
3913  switch (node->type) {
3914  case XML_TEXT_NODE:
3916  /*
3917  * This text comes from the stylesheet
3918  * For stylesheets, the set of whitespace-preserving
3919  * element names consists of just xsl:text.
3920  */
3921 #ifdef WITH_XSLT_DEBUG_PROCESS
3922  if (node->type == XML_CDATA_SECTION_NODE) {
3924  "xsltCopy: CDATA text %s\n", node->content));
3925  } else {
3927  "xsltCopy: text %s\n", node->content));
3928  }
3929 #endif
3930  xsltCopyText(ctxt, ctxt->insert, node, 0);
3931  break;
3932  case XML_DOCUMENT_NODE:
3934  break;
3935  case XML_ELEMENT_NODE:
3936  /*
3937  * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3938  * REMOVED:
3939  * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3940  * return;
3941  */
3942 
3943 #ifdef WITH_XSLT_DEBUG_PROCESS
3945  "xsltCopy: node %s\n", node->name));
3946 #endif
3947  copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3948  ctxt->insert = copy;
3949  if (comp->use != NULL) {
3950  xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3951  }
3952  break;
3953  case XML_ATTRIBUTE_NODE: {
3954 #ifdef WITH_XSLT_DEBUG_PROCESS
3956  "xsltCopy: attribute %s\n", node->name));
3957 #endif
3958  /*
3959  * REVISIT: We could also raise an error if the parent is not
3960  * an element node.
3961  * OPTIMIZE TODO: Can we set the value/children of the
3962  * attribute without an intermediate copy of the string value?
3963  */
3964  xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
3965  break;
3966  }
3967  case XML_PI_NODE:
3968 #ifdef WITH_XSLT_DEBUG_PROCESS
3970  "xsltCopy: PI %s\n", node->name));
3971 #endif
3972  copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3973  node->content);
3974  copy = xsltAddChild(ctxt->insert, copy);
3975  break;
3976  case XML_COMMENT_NODE:
3977 #ifdef WITH_XSLT_DEBUG_PROCESS
3979  "xsltCopy: comment\n"));
3980 #endif
3981  copy = xmlNewComment(node->content);
3982  copy = xsltAddChild(ctxt->insert, copy);
3983  break;
3984  case XML_NAMESPACE_DECL:
3985 #ifdef WITH_XSLT_DEBUG_PROCESS
3987  "xsltCopy: namespace declaration\n"));
3988 #endif
3989  xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3990  break;
3991  default:
3992  break;
3993 
3994  }
3995  }
3996 
3997  switch (node->type) {
3998  case XML_DOCUMENT_NODE:
4000  case XML_ELEMENT_NODE:
4001  xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4002  NULL);
4003  break;
4004  default:
4005  break;
4006  }
4007  ctxt->insert = oldInsert;
4008 }
4009 
4019 void
4022  if ((inst->children != NULL) && (comp != NULL)) {
4023  xmlNodePtr text = inst->children;
4024  xmlNodePtr copy;
4025 
4026  while (text != NULL) {
4027  if ((text->type != XML_TEXT_NODE) &&
4028  (text->type != XML_CDATA_SECTION_NODE)) {
4029  xsltTransformError(ctxt, NULL, inst,
4030  "xsl:text content problem\n");
4031  break;
4032  }
4033  copy = xmlNewDocText(ctxt->output, text->content);
4034  if (text->type != XML_CDATA_SECTION_NODE) {
4035 #ifdef WITH_XSLT_DEBUG_PARSING
4037  "Disable escaping: %s\n", text->content);
4038 #endif
4039  copy->name = xmlStringTextNoenc;
4040  }
4041  copy = xsltAddChild(ctxt->insert, copy);
4042  text = text->next;
4043  }
4044  }
4045 }
4046 
4056 void
4058  xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4059 #ifdef XSLT_REFACTORED
4060  xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
4061 #else
4062  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4063 #endif
4064  xmlChar *prop = NULL;
4065  const xmlChar *name, *prefix = NULL, *nsName = NULL;
4066  xmlNodePtr copy;
4067  xmlNodePtr oldInsert;
4068 
4069  if (ctxt->insert == NULL)
4070  return;
4071 
4072  /*
4073  * A comp->has_name == 0 indicates that we need to skip this instruction,
4074  * since it was evaluated to be invalid already during compilation.
4075  */
4076  if (!comp->has_name)
4077  return;
4078 
4079  /*
4080  * stack and saves
4081  */
4082  oldInsert = ctxt->insert;
4083 
4084  if (comp->name == NULL) {
4085  /* TODO: fix attr acquisition wrt to the XSLT namespace */
4086  prop = xsltEvalAttrValueTemplate(ctxt, inst,
4087  (const xmlChar *) "name", XSLT_NAMESPACE);
4088  if (prop == NULL) {
4089  xsltTransformError(ctxt, NULL, inst,
4090  "xsl:element: The attribute 'name' is missing.\n");
4091  goto error;
4092  }
4093  if (xmlValidateQName(prop, 0)) {
4094  xsltTransformError(ctxt, NULL, inst,
4095  "xsl:element: The effective name '%s' is not a "
4096  "valid QName.\n", prop);
4097  /* we fall through to catch any further errors, if possible */
4098  }
4099  name = xsltSplitQName(ctxt->dict, prop, &prefix);
4100  xmlFree(prop);
4101  } else {
4102  /*
4103  * The "name" value was static.
4104  */
4105 #ifdef XSLT_REFACTORED
4106  prefix = comp->nsPrefix;
4107  name = comp->name;
4108 #else
4109  name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
4110 #endif
4111  }
4112 
4113  /*
4114  * Create the new element
4115  */
4116  if (ctxt->output->dict == ctxt->dict) {
4118  } else {
4119  copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
4120  }
4121  if (copy == NULL) {
4122  xsltTransformError(ctxt, NULL, inst,
4123  "xsl:element : creation of %s failed\n", name);
4124  return;
4125  }
4126  copy = xsltAddChild(ctxt->insert, copy);
4127  if (copy == NULL) {
4128  xsltTransformError(ctxt, NULL, inst,
4129  "xsl:element : xsltAddChild failed\n");
4130  return;
4131  }
4132 
4133  /*
4134  * Namespace
4135  * ---------
4136  */
4137  if (comp->has_ns) {
4138  if (comp->ns != NULL) {
4139  /*
4140  * No AVT; just plain text for the namespace name.
4141  */
4142  if (comp->ns[0] != 0)
4143  nsName = comp->ns;
4144  } else {
4145  xmlChar *tmpNsName;
4146  /*
4147  * Eval the AVT.
4148  */
4149  /* TODO: check attr acquisition wrt to the XSLT namespace */
4150  tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
4151  (const xmlChar *) "namespace", XSLT_NAMESPACE);
4152  /*
4153  * SPEC XSLT 1.0:
4154  * "If the string is empty, then the expanded-name of the
4155  * attribute has a null namespace URI."
4156  */
4157  if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
4158  nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
4159  xmlFree(tmpNsName);
4160  }
4161 
4162  if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
4163  xsltTransformError(ctxt, NULL, inst,
4164  "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4165  "forbidden.\n");
4166  goto error;
4167  }
4168  if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
4169  prefix = BAD_CAST "xml";
4170  } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
4171  prefix = NULL;
4172  }
4173  } else {
4174  xmlNsPtr ns;
4175  /*
4176  * SPEC XSLT 1.0:
4177  * "If the namespace attribute is not present, then the QName is
4178  * expanded into an expanded-name using the namespace declarations
4179  * in effect for the xsl:element element, including any default
4180  * namespace declaration.
4181  */
4182  ns = xmlSearchNs(inst->doc, inst, prefix);
4183  if (ns == NULL) {
4184  /*
4185  * TODO: Check this in the compilation layer in case it's a
4186  * static value.
4187  */
4188  if (prefix != NULL) {
4189  xsltTransformError(ctxt, NULL, inst,
4190  "xsl:element: The QName '%s:%s' has no "
4191  "namespace binding in scope in the stylesheet; "
4192  "this is an error, since the namespace was not "
4193  "specified by the instruction itself.\n", prefix, name);
4194  }
4195  } else
4196  nsName = ns->href;
4197  }
4198  /*
4199  * Find/create a matching ns-decl in the result tree.
4200  */
4201  if (nsName != NULL) {
4202  if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
4203  /* Don't use a prefix of "xmlns" */
4204  xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
4205 
4206  copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
4207 
4208  xmlFree(pref);
4209  } else {
4210  copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
4211  copy);
4212  }
4213  } else if ((copy->parent != NULL) &&
4214  (copy->parent->type == XML_ELEMENT_NODE) &&
4215  (copy->parent->ns != NULL))
4216  {
4217  /*
4218  * "Undeclare" the default namespace.
4219  */
4220  xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4221  }
4222 
4223  ctxt->insert = copy;
4224 
4225  if (comp->has_use) {
4226  if (comp->use != NULL) {
4227  xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4228  } else {
4229  xmlChar *attrSets = NULL;
4230  /*
4231  * BUG TODO: use-attribute-sets is not a value template.
4232  * use-attribute-sets = qnames
4233  */
4234  attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4235  (const xmlChar *)"use-attribute-sets", NULL);
4236  if (attrSets != NULL) {
4237  xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4238  xmlFree(attrSets);
4239  }
4240  }
4241  }
4242  /*
4243  * Instantiate the sequence constructor.
4244  */
4245  if (inst->children != NULL)
4246  xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4247  NULL);
4248 
4249 error:
4250  ctxt->insert = oldInsert;
4251  return;
4252 }
4253 
4254 
4264 void
4267  xmlChar *value = NULL;
4268  xmlNodePtr commentNode;
4269  int len;
4270 
4271  value = xsltEvalTemplateString(ctxt, node, inst);
4272  /* TODO: use or generate the compiled form */
4273  len = xmlStrlen(value);
4274  if (len > 0) {
4275  if ((value[len-1] == '-') ||
4276  (xmlStrstr(value, BAD_CAST "--"))) {
4277  xsltTransformError(ctxt, NULL, inst,
4278  "xsl:comment : '--' or ending '-' not allowed in comment\n");
4279  /* fall through to try to catch further errors */
4280  }
4281  }
4282 #ifdef WITH_XSLT_DEBUG_PROCESS
4283  if (value == NULL) {
4285  "xsltComment: empty\n"));
4286  } else {
4288  "xsltComment: content %s\n", value));
4289  }
4290 #endif
4291 
4292  commentNode = xmlNewComment(value);
4293  commentNode = xsltAddChild(ctxt->insert, commentNode);
4294 
4295  if (value != NULL)
4296  xmlFree(value);
4297 }
4298 
4308 void
4310  xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4311 #ifdef XSLT_REFACTORED
4312  xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4313 #else
4314  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4315 #endif
4316  const xmlChar *name;
4317  xmlChar *value = NULL;
4318  xmlNodePtr pi;
4319 
4320 
4321  if (ctxt->insert == NULL)
4322  return;
4323  if (comp->has_name == 0)
4324  return;
4325  if (comp->name == NULL) {
4326  name = xsltEvalAttrValueTemplate(ctxt, inst,
4327  (const xmlChar *)"name", NULL);
4328  if (name == NULL) {
4329  xsltTransformError(ctxt, NULL, inst,
4330  "xsl:processing-instruction : name is missing\n");
4331  goto error;
4332  }
4333  } else {
4334  name = comp->name;
4335  }
4336  /* TODO: check that it's both an an NCName and a PITarget. */
4337 
4338 
4339  value = xsltEvalTemplateString(ctxt, node, inst);
4340  if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4341  xsltTransformError(ctxt, NULL, inst,
4342  "xsl:processing-instruction: '?>' not allowed within PI content\n");
4343  goto error;
4344  }
4345 #ifdef WITH_XSLT_DEBUG_PROCESS
4346  if (value == NULL) {
4348  "xsltProcessingInstruction: %s empty\n", name));
4349  } else {
4351  "xsltProcessingInstruction: %s content %s\n", name, value));
4352  }
4353 #endif
4354 
4355  pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4356  pi = xsltAddChild(ctxt->insert, pi);
4357 
4358 error:
4359  if ((name != NULL) && (name != comp->name))
4360  xmlFree((xmlChar *) name);
4361  if (value != NULL)
4362  xmlFree(value);
4363 }
4364 
4374 void
4376  xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4377 #ifdef XSLT_REFACTORED
4378  xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4379 #else
4380  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4381 #endif
4382  xmlXPathObjectPtr res = NULL;
4383  xmlNodeSetPtr list = NULL;
4384  int i;
4385 
4386  if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4387  return;
4388  if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4389  xsltTransformError(ctxt, NULL, inst,
4390  "xsl:copy-of : compilation failed\n");
4391  return;
4392  }
4393 
4394  /*
4395  * SPEC XSLT 1.0:
4396  * "The xsl:copy-of element can be used to insert a result tree
4397  * fragment into the result tree, without first converting it to
4398  * a string as xsl:value-of does (see [7.6.1 Generating Text with
4399  * xsl:value-of]). The required select attribute contains an
4400  * expression. When the result of evaluating the expression is a
4401  * result tree fragment, the complete fragment is copied into the
4402  * result tree. When the result is a node-set, all the nodes in the
4403  * set are copied in document order into the result tree; copying
4404  * an element node copies the attribute nodes, namespace nodes and
4405  * children of the element node as well as the element node itself;
4406  * a root node is copied by copying its children. When the result
4407  * is neither a node-set nor a result tree fragment, the result is
4408  * converted to a string and then inserted into the result tree,
4409  * as with xsl:value-of.
4410  */
4411 
4412 #ifdef WITH_XSLT_DEBUG_PROCESS
4414  "xsltCopyOf: select %s\n", comp->select));
4415 #endif
4416 
4417  /*
4418  * Evaluate the "select" expression.
4419  */
4420  res = xsltPreCompEval(ctxt, node, comp);
4421 
4422  if (res != NULL) {
4423  if (res->type == XPATH_NODESET) {
4424  /*
4425  * Node-set
4426  * --------
4427  */
4428 #ifdef WITH_XSLT_DEBUG_PROCESS
4430  "xsltCopyOf: result is a node set\n"));
4431 #endif
4432  list = res->nodesetval;
4433  if (list != NULL) {
4434  xmlNodePtr cur;
4435  /*
4436  * The list is already sorted in document order by XPath.
4437  * Append everything in this order under ctxt->insert.
4438  */
4439  for (i = 0;i < list->nodeNr;i++) {
4440  cur = list->nodeTab[i];
4441  if (cur == NULL)
4442  continue;
4443  if ((cur->type == XML_DOCUMENT_NODE) ||
4444  (cur->type == XML_HTML_DOCUMENT_NODE))
4445  {
4446  xsltCopyTreeList(ctxt, inst,
4447  cur->children, ctxt->insert, 0, 0);
4448  } else if (cur->type == XML_ATTRIBUTE_NODE) {
4449  xsltShallowCopyAttr(ctxt, inst,
4450  ctxt->insert, (xmlAttrPtr) cur);
4451  } else {
4452  xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
4453  }
4454  }
4455  }
4456  } else if (res->type == XPATH_XSLT_TREE) {
4457  /*
4458  * Result tree fragment
4459  * --------------------
4460  * E.g. via <xsl:variable ...><foo/></xsl:variable>
4461  * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4462  */
4463 #ifdef WITH_XSLT_DEBUG_PROCESS
4465  "xsltCopyOf: result is a result tree fragment\n"));
4466 #endif
4467  list = res->nodesetval;
4468  if ((list != NULL) && (list->nodeTab != NULL) &&
4469  (list->nodeTab[0] != NULL) &&
4470  (IS_XSLT_REAL_NODE(list->nodeTab[0])))
4471  {
4472  xsltCopyTreeList(ctxt, inst,
4473  list->nodeTab[0]->children, ctxt->insert, 0, 0);
4474  }
4475  } else {
4476  xmlChar *value = NULL;
4477  /*
4478  * Convert to a string.
4479  */
4480  value = xmlXPathCastToString(res);
4481  if (value == NULL) {
4482  xsltTransformError(ctxt, NULL, inst,
4483  "Internal error in xsltCopyOf(): "
4484  "failed to cast an XPath object to string.\n");
4485  ctxt->state = XSLT_STATE_STOPPED;
4486  } else {
4487  if (value[0] != 0) {
4488  /*
4489  * Append content as text node.
4490  */
4491  xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4492  }
4493  xmlFree(value);
4494 
4495 #ifdef WITH_XSLT_DEBUG_PROCESS
4497  "xsltCopyOf: result %s\n", res->stringval));
4498 #endif
4499  }
4500  }
4501  } else {
4502  ctxt->state = XSLT_STATE_STOPPED;
4503  }
4504 
4505  if (res != NULL)
4506  xmlXPathFreeObject(res);
4507 }
4508 
4518 void
4520  xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4521 {
4522 #ifdef XSLT_REFACTORED
4523  xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4524 #else
4525  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4526 #endif
4527  xmlXPathObjectPtr res = NULL;
4528  xmlChar *value = NULL;
4529 
4530  if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4531  return;
4532 
4533  if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4534  xsltTransformError(ctxt, NULL, inst,
4535  "Internal error in xsltValueOf(): "
4536  "The XSLT 'value-of' instruction was not compiled.\n");
4537  return;
4538  }
4539 
4540 #ifdef WITH_XSLT_DEBUG_PROCESS
4542  "xsltValueOf: select %s\n", comp->select));
4543 #endif
4544 
4545  res = xsltPreCompEval(ctxt, node, comp);
4546 
4547  /*
4548  * Cast the XPath object to string.
4549  */
4550  if (res != NULL) {
4551  value = xmlXPathCastToString(res);
4552  if (value == NULL) {
4553  xsltTransformError(ctxt, NULL, inst,
4554  "Internal error in xsltValueOf(): "
4555  "failed to cast an XPath object to string.\n");
4556  ctxt->state = XSLT_STATE_STOPPED;
4557  goto error;
4558  }
4559  if (value[0] != 0) {
4560  xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
4561  }
4562  } else {
4563  xsltTransformError(ctxt, NULL, inst,
4564  "XPath evaluation returned no result.\n");
4565  ctxt->state = XSLT_STATE_STOPPED;
4566  goto error;
4567  }
4568 
4569 #ifdef WITH_XSLT_DEBUG_PROCESS
4570  if (value) {
4572  "xsltValueOf: result '%s'\n", value));
4573  }
4574 #endif
4575 
4576 error:
4577  if (value != NULL)
4578  xmlFree(value);
4579  if (res != NULL)
4580  xmlXPathFreeObject(res);
4581 }
4582 
4592 void
4594  xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4595 {
4596 #ifdef XSLT_REFACTORED
4597  xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4598 #else
4599  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4600 #endif
4601  xmlXPathContextPtr xpctxt;
4602  xmlNsPtr *oldXPNamespaces;
4603  int oldXPNsNr;
4604 
4605  if (comp == NULL) {
4606  xsltTransformError(ctxt, NULL, inst,
4607  "xsl:number : compilation failed\n");
4608  return;
4609  }
4610 
4611  if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4612  return;
4613 
4614  comp->numdata.doc = inst->doc;
4615  comp->numdata.node = inst;
4616 
4617  xpctxt = ctxt->xpathCtxt;
4618  oldXPNsNr = xpctxt->nsNr;
4619  oldXPNamespaces = xpctxt->namespaces;
4620 
4621 #ifdef XSLT_REFACTORED
4622  if (comp->inScopeNs != NULL) {
4623  xpctxt->namespaces = comp->inScopeNs->list;
4624  xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4625  } else {
4626  xpctxt->namespaces = NULL;
4627  xpctxt->nsNr = 0;
4628  }
4629 #else
4630  xpctxt->namespaces = comp->nsList;
4631  xpctxt->nsNr = comp->nsNr;
4632 #endif
4633 
4634  xsltNumberFormat(ctxt, &comp->numdata, node);
4635 
4636  xpctxt->nsNr = oldXPNsNr;
4637  xpctxt->namespaces = oldXPNamespaces;
4638 }
4639 
4649 void
4651  xmlNodePtr inst,
4653 {
4654  xsltTemplatePtr templ;
4655 
4656  if ((ctxt == NULL) || (inst == NULL))
4657  return;
4658 
4659  if (comp == NULL) {
4660  xsltTransformError(ctxt, NULL, inst,
4661  "Internal error in xsltApplyImports(): "
4662  "The XSLT 'apply-imports' instruction was not compiled.\n");
4663  return;
4664  }
4665  /*
4666  * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4667  * same; the former is the "Current Template Rule" as defined by the
4668  * XSLT spec, the latter is simply the template struct being
4669  * currently processed.
4670  */
4671  if (ctxt->currentTemplateRule == NULL) {
4672  /*
4673  * SPEC XSLT 2.0:
4674  * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4675  * xsl:apply-imports or xsl:next-match is evaluated when the
4676  * current template rule is null."
4677  */
4678  xsltTransformError(ctxt, NULL, inst,
4679  "It is an error to call 'apply-imports' "
4680  "when there's no current template rule.\n");
4681  return;
4682  }
4683  /*
4684  * TODO: Check if this is correct.
4685  */
4686  templ = xsltGetTemplate(ctxt, contextNode,
4687  ctxt->currentTemplateRule->style);
4688 
4689  if (templ != NULL) {
4690  xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4691  /*
4692  * Set the current template rule.
4693  */
4694  ctxt->currentTemplateRule = templ;
4695  /*
4696  * URGENT TODO: Need xsl:with-param be handled somehow here?
4697  */
4698  xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4699  templ, NULL);
4700 
4701  ctxt->currentTemplateRule = oldCurTemplRule;
4702  }
4703  else {
4704  /* Use built-in templates. */
4705  xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
4706  }
4707 }
4708 
4718 void
4720  xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4721 {
4722 #ifdef XSLT_REFACTORED
4723  xsltStyleItemCallTemplatePtr comp =
4724  (xsltStyleItemCallTemplatePtr) castedComp;
4725 #else
4726  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4727 #endif
4728  xsltStackElemPtr withParams = NULL;
4729 
4730  if (ctxt->insert == NULL)
4731  return;
4732  if (comp == NULL) {
4733  xsltTransformError(ctxt, NULL, inst,
4734  "The XSLT 'call-template' instruction was not compiled.\n");
4735  return;
4736  }
4737 
4738  /*
4739  * The template must have been precomputed
4740  */
4741  if (comp->templ == NULL) {
4742  comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4743  if (comp->templ == NULL) {
4744  if (comp->ns != NULL) {
4745  xsltTransformError(ctxt, NULL, inst,
4746  "The called template '{%s}%s' was not found.\n",
4747  comp->ns, comp->name);
4748  } else {
4749  xsltTransformError(ctxt, NULL, inst,
4750  "The called template '%s' was not found.\n",
4751  comp->name);
4752  }
4753  return;
4754  }
4755  }
4756 
4757 #ifdef WITH_XSLT_DEBUG_PROCESS
4758  if ((comp != NULL) && (comp->name != NULL))
4760  "call-template: name %s\n", comp->name));
4761 #endif
4762 
4763  if (inst->children) {
4764  xmlNodePtr cur;
4766 
4767  cur = inst->children;
4768  while (cur != NULL) {
4769 #ifdef WITH_DEBUGGER
4770  if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4771  xslHandleDebugger(cur, node, comp->templ, ctxt);
4772 #endif
4773  if (ctxt->state == XSLT_STATE_STOPPED) break;
4774  /*
4775  * TODO: The "with-param"s could be part of the "call-template"
4776  * structure. Avoid to "search" for params dynamically
4777  * in the XML tree every time.
4778  */
4779  if (IS_XSLT_ELEM(cur)) {
4780  if (IS_XSLT_NAME(cur, "with-param")) {
4782  if (param != NULL) {
4783  param->next = withParams;
4784  withParams = param;
4785  }
4786  } else {
4788  "xsl:call-template: misplaced xsl:%s\n", cur->name);
4789  }
4790  } else {
4792  "xsl:call-template: misplaced %s element\n", cur->name);
4793  }
4794  cur = cur->next;
4795  }
4796  }
4797  /*
4798  * Create a new frame using the params first
4799  */
4800  xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4801  withParams);
4802  if (withParams != NULL)
4803  xsltFreeStackElemList(withParams);
4804 
4805 #ifdef WITH_XSLT_DEBUG_PROCESS
4806  if ((comp != NULL) && (comp->name != NULL))
4808  "call-template returned: name %s\n", comp->name));
4809 #endif
4810 }
4811 
4821 void
4823  xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4824 {
4825 #ifdef XSLT_REFACTORED
4826  xsltStyleItemApplyTemplatesPtr comp =
4827  (xsltStyleItemApplyTemplatesPtr) castedComp;
4828 #else
4829  xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4830 #endif
4831  int i;
4832  xmlNodePtr cur, delNode = NULL, oldContextNode;
4833  xmlNodeSetPtr list = NULL, oldList;
4834  xsltStackElemPtr withParams = NULL;
4835  int oldXPProximityPosition, oldXPContextSize;
4836  const xmlChar *oldMode, *oldModeURI;
4837  xmlDocPtr oldXPDoc;
4838  xsltDocumentPtr oldDocInfo;
4839  xmlXPathContextPtr xpctxt;
4840 
4841  if (comp == NULL) {
4842  xsltTransformError(ctxt, NULL, inst,
4843  "xsl:apply-templates : compilation failed\n");
4844  return;
4845  }
4846  if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4847  return;
4848 
4849 #ifdef WITH_XSLT_DEBUG_PROCESS
4850  if ((node != NULL) && (node->name != NULL))
4852  "xsltApplyTemplates: node: '%s'\n", node->name));
4853 #endif
4854 
4855  xpctxt = ctxt->xpathCtxt;
4856  /*
4857  * Save context states.
4858  */
4859  oldContextNode = ctxt->node;
4860  oldMode = ctxt->mode;
4861  oldModeURI = ctxt->modeURI;
4862  oldDocInfo = ctxt->document;
4863  oldList = ctxt->nodeList;
4864 
4865  /*
4866  * The xpath context size and proximity position, as
4867  * well as the xpath and context documents, may be changed
4868  * so we save their initial state and will restore on exit
4869  */
4870  oldXPContextSize = xpctxt->contextSize;
4871  oldXPProximityPosition = xpctxt->proximityPosition;
4872  oldXPDoc = xpctxt->doc;
4873 
4874  /*
4875  * Set up contexts.
4876  */
4877  ctxt->mode = comp->mode;
4878  ctxt->modeURI = comp->modeURI;
4879 
4880  if (comp->select != NULL) {
4881  xmlXPathObjectPtr res = NULL;
4882 
4883  if (comp->comp == NULL) {
4884  xsltTransformError(ctxt, NULL, inst,
4885  "xsl:apply-templates : compilation failed\n");
4886  goto error;
4887  }
4888 #ifdef WITH_XSLT_DEBUG_PROCESS
4890  "xsltApplyTemplates: select %s\n", comp->select));
4891 #endif
4892 
4893  res = xsltPreCompEval(ctxt, node, comp);
4894 
4895  if (res != NULL) {
4896  if (res->type == XPATH_NODESET) {
4897  list = res->nodesetval; /* consume the node set */
4898  res->nodesetval = NULL;
4899  } else {
4900  xsltTransformError(ctxt, NULL, inst,
4901  "The 'select' expression did not evaluate to a "
4902  "node set.\n");
4903  ctxt->state = XSLT_STATE_STOPPED;
4904  xmlXPathFreeObject(res);
4905  goto error;
4906  }
4907  xmlXPathFreeObject(res);
4908  /*
4909  * Note: An xsl:apply-templates with a 'select' attribute,
4910  * can change the current source doc.
4911  */
4912  } else {
4913  xsltTransformError(ctxt, NULL, inst,
4914  "Failed to evaluate the 'select' expression.\n");
4915  ctxt->state = XSLT_STATE_STOPPED;
4916  goto error;
4917  }
4918  if (list == NULL) {
4919 #ifdef WITH_XSLT_DEBUG_PROCESS
4921  "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4922 #endif
4923  goto exit;
4924  }
4925  /*
4926  *
4927  * NOTE: Previously a document info (xsltDocument) was
4928  * created and attached to the Result Tree Fragment.
4929  * But such a document info is created on demand in
4930  * xsltKeyFunction() (functions.c), so we need to create
4931  * it here beforehand.
4932  * In order to take care of potential keys we need to
4933  * do some extra work for the case when a Result Tree Fragment
4934  * is converted into a nodeset (e.g. exslt:node-set()) :
4935  * We attach a "pseudo-doc" (xsltDocument) to _private.
4936  * This xsltDocument, together with the keyset, will be freed
4937  * when the Result Tree Fragment is freed.
4938  *
4939  */
4940 #if 0
4941  if ((ctxt->nbKeys > 0) &&
4942  (list->nodeNr != 0) &&
4943  (list->nodeTab[0]->doc != NULL) &&
4944  XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
4945  {
4946  /*
4947  * NOTE that it's also OK if @effectiveDocInfo will be
4948  * set to NULL.
4949  */
4950  isRTF = 1;
4951  effectiveDocInfo = list->nodeTab[0]->doc->_private;
4952  }
4953 #endif
4954  } else {
4955  /*
4956  * Build an XPath node set with the children
4957  */
4958  list = xmlXPathNodeSetCreate(NULL);
4959  if (list == NULL)
4960  goto error;
4961  if (node->type != XML_NAMESPACE_DECL)
4962  cur = node->children;
4963  else
4964  cur = NULL;
4965  while (cur != NULL) {
4966  switch (cur->type) {
4967  case XML_TEXT_NODE:
4968  if ((IS_BLANK_NODE(cur)) &&
4969  (cur->parent != NULL) &&
4970  (cur->parent->type == XML_ELEMENT_NODE) &&
4971  (ctxt->style->stripSpaces != NULL)) {
4972  const xmlChar *val;
4973 
4974  if (cur->parent->ns != NULL) {
4975  val = (const xmlChar *)
4977  cur->parent->name,
4978  cur->parent->ns->href);
4979  if (val == NULL) {
4980  val = (const xmlChar *)
4982  BAD_CAST "*",
4983  cur->parent->ns->href);
4984  }
4985  } else {
4986  val = (const xmlChar *)
4988  cur->parent->name, NULL);
4989  }
4990  if ((val != NULL) &&
4991  (xmlStrEqual(val, (xmlChar *) "strip"))) {
4992  delNode = cur;
4993  break;
4994  }
4995  }
4996  /* Intentional fall-through */
4997  case XML_ELEMENT_NODE:
4998  case XML_DOCUMENT_NODE:
5001  case XML_PI_NODE:
5002  case XML_COMMENT_NODE:
5003  xmlXPathNodeSetAddUnique(list, cur);
5004  break;
5005  case XML_DTD_NODE:
5006  /* Unlink the DTD, it's still reachable
5007  * using doc->intSubset */
5008  if (cur->next != NULL)
5009  cur->next->prev = cur->prev;
5010  if (cur->prev != NULL)
5011  cur->prev->next = cur->next;
5012  break;
5013  case XML_NAMESPACE_DECL:
5014  break;
5015  default:
5016 #ifdef WITH_XSLT_DEBUG_PROCESS
5018  "xsltApplyTemplates: skipping cur type %d\n",
5019  cur->type));
5020 #endif
5021  delNode = cur;
5022  }
5023  cur = cur->next;
5024  if (delNode != NULL) {
5025 #ifdef WITH_XSLT_DEBUG_PROCESS
5027  "xsltApplyTemplates: removing ignorable blank cur\n"));
5028 #endif
5029  xmlUnlinkNode(delNode);
5030  xmlFreeNode(delNode);
5031  delNode = NULL;
5032  }
5033  }
5034  }
5035 
5036 #ifdef WITH_XSLT_DEBUG_PROCESS
5037  if (list != NULL)
5039  "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
5040 #endif
5041 
5042  if ((list == NULL) || (list->nodeNr == 0))
5043  goto exit;
5044 
5045  /*
5046  * Set the context's node set and size; this is also needed for
5047  * for xsltDoSortFunction().
5048  */
5049  ctxt->nodeList = list;
5050  /*
5051  * Process xsl:with-param and xsl:sort instructions.
5052  * (The code became so verbose just to avoid the
5053  * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
5054  * BUG TODO: We are not using namespaced potentially defined on the
5055  * xsl:sort or xsl:with-param elements; XPath expression might fail.
5056  */
5057  if (inst->children) {
5059 
5060  cur = inst->children;
5061  while (cur) {
5062 
5063 #ifdef WITH_DEBUGGER
5064  if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5065  xslHandleDebugger(cur, node, NULL, ctxt);
5066 #endif
5067  if (ctxt->state == XSLT_STATE_STOPPED)
5068  break;
5069  if (cur->type == XML_TEXT_NODE) {
5070  cur = cur->next;
5071  continue;
5072  }
5073  if (! IS_XSLT_ELEM(cur))
5074  break;
5075  if (IS_XSLT_NAME(cur, "with-param")) {
5077  if (param != NULL) {
5078  param->next = withParams;
5079  withParams = param;
5080  }
5081  }
5082  if (IS_XSLT_NAME(cur, "sort")) {
5083  xsltTemplatePtr oldCurTempRule =
5084  ctxt->currentTemplateRule;
5085  int nbsorts = 0;
5086  xmlNodePtr sorts[XSLT_MAX_SORT];
5087 
5088  sorts[nbsorts++] = cur;
5089 
5090  while (cur) {
5091 
5092 #ifdef WITH_DEBUGGER
5093  if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5094  xslHandleDebugger(cur, node, NULL, ctxt);
5095 #endif
5096  if (ctxt->state == XSLT_STATE_STOPPED)
5097  break;
5098 
5099  if (cur->type == XML_TEXT_NODE) {
5100  cur = cur->next;
5101  continue;
5102  }
5103 
5104  if (! IS_XSLT_ELEM(cur))
5105  break;
5106  if (IS_XSLT_NAME(cur, "with-param")) {
5108  if (param != NULL) {
5109  param->next = withParams;
5110  withParams = param;
5111  }
5112  }
5113  if (IS_XSLT_NAME(cur, "sort")) {
5114  if (nbsorts >= XSLT_MAX_SORT) {
5115  xsltTransformError(ctxt, NULL, cur,
5116  "The number (%d) of xsl:sort instructions exceeds the "
5117  "maximum allowed by this processor's settings.\n",
5118  nbsorts);
5119  ctxt->state = XSLT_STATE_STOPPED;
5120  break;
5121  } else {
5122  sorts[nbsorts++] = cur;
5123  }
5124  }
5125  cur = cur->next;
5126  }
5127  /*
5128  * The "current template rule" is cleared for xsl:sort.
5129  */
5130  ctxt->currentTemplateRule = NULL;
5131  /*
5132  * Sort.
5133  */
5134  xsltDoSortFunction(ctxt, sorts, nbsorts);
5135  ctxt->currentTemplateRule = oldCurTempRule;
5136  break;
5137  }
5138  cur = cur->next;
5139  }
5140  }
5141  xpctxt->contextSize = list->nodeNr;
5142  /*
5143  * Apply templates for all selected source nodes.
5144  */
5145  for (i = 0; i < list->nodeNr; i++) {
5146  cur = list->nodeTab[i];
5147  /*
5148  * The node becomes the "current node".
5149  */
5150  ctxt->node = cur;
5151  /*
5152  * An xsl:apply-templates can change the current context doc.
5153  * OPTIMIZE TODO: Get rid of the need to set the context doc.
5154  */
5155  if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5156  xpctxt->doc = cur->doc;
5157 
5158  xpctxt->proximityPosition = i + 1;
5159  /*
5160  * Find and apply a template for this node.
5161  */
5162  xsltProcessOneNode(ctxt, cur, withParams);
5163  }
5164 
5165 exit:
5166 error:
5167  /*
5168  * Free the parameter list.
5169  */
5170  if (withParams != NULL)
5171  xsltFreeStackElemList(withParams);
5172  if (list != NULL)
5173  xmlXPathFreeNodeSet(list);
5174  /*
5175  * Restore context states.
5176  */
5177  xpctxt->doc = oldXPDoc;
5178  xpctxt->contextSize = oldXPContextSize;
5179  xpctxt->proximityPosition = oldXPProximityPosition;
5180 
5181  ctxt->document = oldDocInfo;
5182  ctxt->nodeList = oldList;
5183  ctxt->node = oldContextNode;
5184  ctxt->mode = oldMode;
5185  ctxt->modeURI = oldModeURI;
5186 }
5187 
5188 
5198 void
5201 {
5202  xmlNodePtr cur;
5203 
5204  if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5205  return;
5206 
5207  /*
5208  * TODO: Content model checks should be done only at compilation
5209  * time.
5210  */
5211  cur = inst->children;
5212  if (cur == NULL) {
5213  xsltTransformError(ctxt, NULL, inst,
5214  "xsl:choose: The instruction has no content.\n");
5215  return;
5216  }
5217 
5218 #ifdef XSLT_REFACTORED
5219  /*
5220  * We don't check the content model during transformation.
5221  */
5222 #else
5223  if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
5224  xsltTransformError(ctxt, NULL, inst,
5225  "xsl:choose: xsl:when expected first\n");
5226  return;
5227  }
5228 #endif
5229 
5230  {
5231  int testRes = 0, res = 0;
5232 
5233 #ifdef XSLT_REFACTORED
5234  xsltStyleItemWhenPtr wcomp = NULL;
5235 #else
5236  xsltStylePreCompPtr wcomp = NULL;
5237 #endif
5238 
5239  /*
5240  * Process xsl:when ---------------------------------------------------
5241  */
5242  while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
5243  wcomp = cur->psvi;
5244 
5245  if ((wcomp == NULL) || (wcomp->test == NULL) ||
5246  (wcomp->comp == NULL))
5247  {
5248  xsltTransformError(ctxt, NULL, cur,
5249  "Internal error in xsltChoose(): "
5250  "The XSLT 'when' instruction was not compiled.\n");
5251  goto error;
5252  }
5253 
5254 
5255 #ifdef WITH_DEBUGGER
5257  /*
5258  * TODO: Isn't comp->templ always NULL for xsl:choose?
5259  */
5260  xslHandleDebugger(cur, contextNode, NULL, ctxt);
5261  }
5262 #endif
5263 #ifdef WITH_XSLT_DEBUG_PROCESS
5265  "xsltChoose: test %s\n", wcomp->test));
5266 #endif
5267 
5268 #ifdef XSLT_FAST_IF
5269  res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp);
5270 
5271  if (res == -1) {
5272  ctxt->state = XSLT_STATE_STOPPED;
5273  goto error;
5274  }
5275  testRes = (res == 1) ? 1 : 0;
5276 
5277 #else /* XSLT_FAST_IF */
5278 
5279  res = xsltPreCompEval(ctxt, cotextNode, wcomp);
5280 
5281  if (res != NULL) {
5282  if (res->type != XPATH_BOOLEAN)
5283  res = xmlXPathConvertBoolean(res);
5284  if (res->type == XPATH_BOOLEAN)
5285  testRes = res->boolval;
5286  else {
5287 #ifdef WITH_XSLT_DEBUG_PROCESS
5289  "xsltChoose: test didn't evaluate to a boolean\n"));
5290 #endif
5291  goto error;
5292  }
5293  xmlXPathFreeObject(res);
5294  res = NULL;
5295  } else {
5296  ctxt->state = XSLT_STATE_STOPPED;
5297  goto error;
5298  }
5299 
5300 #endif /* else of XSLT_FAST_IF */
5301 
5302 #ifdef WITH_XSLT_DEBUG_PROCESS
5304  "xsltChoose: test evaluate to %d\n", testRes));
5305 #endif
5306  if (testRes)
5307  goto test_is_true;
5308 
5309  cur = cur->next;
5310  }
5311 
5312  /*
5313  * Process xsl:otherwise ----------------------------------------------
5314  */
5315  if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
5316 
5317 #ifdef WITH_DEBUGGER
5319  xslHandleDebugger(cur, contextNode, NULL, ctxt);
5320 #endif
5321 
5322 #ifdef WITH_XSLT_DEBUG_PROCESS