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