ReactOS  0.4.13-dev-961-g238ea69
xslt.c
Go to the documentation of this file.
1 /*
2  * xslt.c: Implemetation of an XSL Transformation 1.0 engine
3  *
4  * Reference:
5  * XSLT specification
6  * http://www.w3.org/TR/1999/REC-xslt-19991116
7  *
8  * Associating Style Sheets with XML documents
9  * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
10  *
11  * See Copyright for the status of this software.
12  *
13  * daniel@veillard.com
14  */
15 
16 #include "precomp.h"
17 
18 #ifdef WITH_XSLT_DEBUG
19 #define WITH_XSLT_DEBUG_PARSING
20 /* #define WITH_XSLT_DEBUG_BLANKS */
21 #endif
22 
26 
27 #ifdef XSLT_REFACTORED
28 
29 const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
30 
31 #define XSLT_ELEMENT_CATEGORY_XSLT 0
32 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
33 #define XSLT_ELEMENT_CATEGORY_LRE 2
34 
35 /*
36 * xsltLiteralResultMarker:
37 * Marker for Literal result elements, in order to avoid multiple attempts
38 * to recognize such elements in the stylesheet's tree.
39 * This marker is set on node->psvi during the initial traversal
40 * of a stylesheet's node tree.
41 *
42 const xmlChar *xsltLiteralResultMarker =
43  (const xmlChar *) "Literal Result Element";
44 */
45 
46 /*
47 * xsltXSLTTextMarker:
48 * Marker for xsl:text elements. Used to recognize xsl:text elements
49 * for post-processing of the stylesheet's tree, where those
50 * elements are removed from the tree.
51 */
52 const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
53 
54 /*
55 * xsltXSLTAttrMarker:
56 * Marker for XSLT attribute on Literal Result Elements.
57 */
58 const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
59 
60 #endif
61 
62 #ifdef XSLT_LOCALE_WINAPI
63 extern xmlRMutexPtr xsltLocaleMutex;
64 #endif
65 /*
66  * Harmless but avoiding a problem when compiling against a
67  * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
68  */
69 #ifndef LIBXML_DEBUG_ENABLED
70 double xmlXPathStringEvalNumber(const xmlChar *str);
71 #endif
72 /*
73  * Useful macros
74  */
75 
76 #ifdef IS_BLANK
77 #undef IS_BLANK
78 #endif
79 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
80  ((c) == 0x0D))
81 
82 #ifdef IS_BLANK_NODE
83 #undef IS_BLANK_NODE
84 #endif
85 #define IS_BLANK_NODE(n) \
86  (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
87 
96 static void
99 {
100  if ((style == NULL) || (node == NULL))
101  return;
102 
103  if (IS_XSLT_ELEM(node))
105  "The XSLT-element '%s' is not allowed at this position.\n",
106  node->name);
107  else
109  "The element '%s' is not allowed at this position.\n",
110  node->name);
111  style->errors++;
112 }
113 
114 #ifdef XSLT_REFACTORED
115 #else
116 
126 static int
128 {
129  int i;
130 
131  if (style->exclPrefixMax == 0) {
132  style->exclPrefixMax = 4;
133  style->exclPrefixTab =
134  (xmlChar * *)xmlMalloc(style->exclPrefixMax *
135  sizeof(style->exclPrefixTab[0]));
136  if (style->exclPrefixTab == NULL) {
137  xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
138  return (-1);
139  }
140  }
141  /* do not push duplicates */
142  for (i = 0;i < style->exclPrefixNr;i++) {
143  if (xmlStrEqual(style->exclPrefixTab[i], value))
144  return(-1);
145  }
146  if (style->exclPrefixNr >= style->exclPrefixMax) {
147  style->exclPrefixMax *= 2;
148  style->exclPrefixTab =
149  (xmlChar * *)xmlRealloc(style->exclPrefixTab,
150  style->exclPrefixMax *
151  sizeof(style->exclPrefixTab[0]));
152  if (style->exclPrefixTab == NULL) {
153  xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
154  return (-1);
155  }
156  }
157  style->exclPrefixTab[style->exclPrefixNr] = value;
158  style->exclPrefix = value;
159  return (style->exclPrefixNr++);
160 }
169 static xmlChar *
171 {
172  xmlChar *ret;
173 
174  if (style->exclPrefixNr <= 0)
175  return (0);
176  style->exclPrefixNr--;
177  if (style->exclPrefixNr > 0)
178  style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
179  else
180  style->exclPrefix = NULL;
181  ret = style->exclPrefixTab[style->exclPrefixNr];
182  style->exclPrefixTab[style->exclPrefixNr] = 0;
183  return (ret);
184 }
185 #endif
186 
187 /************************************************************************
188  * *
189  * Helper functions *
190  * *
191  ************************************************************************/
192 
193 static int initialized = 0;
200 void
201 xsltInit (void) {
202  if (initialized == 0) {
203  initialized = 1;
204 #ifdef XSLT_LOCALE_WINAPI
205  xsltLocaleMutex = xmlNewRMutex();
206 #endif
208  }
209 }
210 
216 void
217 xsltUninit (void) {
218 #ifdef XSLT_LOCALE_WINAPI
219  xmlFreeRMutex(xsltLocaleMutex);
220  xsltLocaleMutex = NULL;
221 #endif
222  initialized = 0;
223 }
224 
233 int
235  if (str == NULL)
236  return(1);
237  while (*str != 0) {
238  if (!(IS_BLANK(*str))) return(0);
239  str++;
240  }
241  return(1);
242 }
243 
244 /************************************************************************
245  * *
246  * Routines to handle XSLT data structures *
247  * *
248  ************************************************************************/
251 {
253  /* UTF-8 for 0x2030 */
254  static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
255 
256  self = xmlMalloc(sizeof(xsltDecimalFormat));
257  if (self != NULL) {
258  self->next = NULL;
259  self->nsUri = nsUri;
260  self->name = name;
261 
262  /* Default values */
263  self->digit = xmlStrdup(BAD_CAST("#"));
264  self->patternSeparator = xmlStrdup(BAD_CAST(";"));
265  self->decimalPoint = xmlStrdup(BAD_CAST("."));
266  self->grouping = xmlStrdup(BAD_CAST(","));
267  self->percent = xmlStrdup(BAD_CAST("%"));
268  self->permille = xmlStrdup(BAD_CAST(permille));
269  self->zeroDigit = xmlStrdup(BAD_CAST("0"));
270  self->minusSign = xmlStrdup(BAD_CAST("-"));
271  self->infinity = xmlStrdup(BAD_CAST("Infinity"));
272  self->noNumber = xmlStrdup(BAD_CAST("NaN"));
273  }
274  return self;
275 }
276 
277 static void
279 {
280  if (self != NULL) {
281  if (self->digit)
282  xmlFree(self->digit);
283  if (self->patternSeparator)
284  xmlFree(self->patternSeparator);
285  if (self->decimalPoint)
286  xmlFree(self->decimalPoint);
287  if (self->grouping)
288  xmlFree(self->grouping);
289  if (self->percent)
290  xmlFree(self->percent);
291  if (self->permille)
292  xmlFree(self->permille);
293  if (self->zeroDigit)
294  xmlFree(self->zeroDigit);
295  if (self->minusSign)
296  xmlFree(self->minusSign);
297  if (self->infinity)
298  xmlFree(self->infinity);
299  if (self->noNumber)
300  xmlFree(self->noNumber);
301  if (self->name)
302  xmlFree(self->name);
303  xmlFree(self);
304  }
305 }
306 
307 static void
309 {
312 
313  if (self == NULL)
314  return;
315 
316  iter = self->decimalFormat;
317  while (iter != NULL) {
318  tmp = iter->next;
319  xsltFreeDecimalFormat(iter);
320  iter = tmp;
321  }
322 }
323 
335 {
337 
338  if (name == NULL)
339  return style->decimalFormat;
340 
341  while (style != NULL) {
342  for (result = style->decimalFormat->next;
343  result != NULL;
344  result = result->next) {
345  if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
346  return result;
347  }
349  }
350  return result;
351 }
352 
365  const xmlChar *name)
366 {
368 
369  if (name == NULL)
370  return style->decimalFormat;
371 
372  while (style != NULL) {
373  for (result = style->decimalFormat->next;
374  result != NULL;
375  result = result->next) {
376  if (xmlStrEqual(nsUri, result->nsUri) &&
378  return result;
379  }
381  }
382  return result;
383 }
384 
385 
393 static xsltTemplatePtr
395  xsltTemplatePtr cur;
396 
397  cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
398  if (cur == NULL) {
400  "xsltNewTemplate : malloc failed\n");
401  return(NULL);
402  }
403  memset(cur, 0, sizeof(xsltTemplate));
405  return(cur);
406 }
407 
414 static void
416  if (template == NULL)
417  return;
418  if (template->match) xmlFree(template->match);
419 /*
420 * NOTE: @name and @nameURI are put into the string dict now.
421 * if (template->name) xmlFree(template->name);
422 * if (template->nameURI) xmlFree(template->nameURI);
423 */
424 /*
425  if (template->mode) xmlFree(template->mode);
426  if (template->modeURI) xmlFree(template->modeURI);
427  */
428  if (template->inheritedNs) xmlFree(template->inheritedNs);
429 
430  /* free profiling data */
431  if (template->templCalledTab) xmlFree(template->templCalledTab);
432  if (template->templCountTab) xmlFree(template->templCountTab);
433 
434  memset(template, -1, sizeof(xsltTemplate));
435  xmlFree(template);
436 }
437 
444 static void
446  xsltTemplatePtr cur;
447 
448  while (template != NULL) {
449  cur = template;
450  template = template->next;
451  xsltFreeTemplate(cur);
452  }
453 }
454 
455 #ifdef XSLT_REFACTORED
456 
457 static void
458 xsltFreeNsAliasList(xsltNsAliasPtr item)
459 {
460  xsltNsAliasPtr tmp;
461 
462  while (item) {
463  tmp = item;
464  item = item->next;
465  xmlFree(tmp);
466  }
467  return;
468 }
469 
470 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
471 static void
472 xsltFreeNamespaceMap(xsltNsMapPtr item)
473 {
474  xsltNsMapPtr tmp;
475 
476  while (item) {
477  tmp = item;
478  item = item->next;
479  xmlFree(tmp);
480  }
481  return;
482 }
483 
484 static xsltNsMapPtr
485 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
486  xmlDocPtr doc,
487  xmlNsPtr ns,
489 {
490  xsltNsMapPtr ret;
491 
492  if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
493  return(NULL);
494 
495  ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
496  if (ret == NULL) {
497  xsltTransformError(NULL, cctxt->style, elem,
498  "Internal error: (xsltNewNamespaceMapItem) "
499  "memory allocation failed.\n");
500  return(NULL);
501  }
502  memset(ret, 0, sizeof(xsltNsMap));
503  ret->doc = doc;
504  ret->ns = ns;
505  ret->origNsName = ns->href;
506  /*
507  * Store the item at current stylesheet-level.
508  */
509  if (cctxt->psData->nsMap != NULL)
510  ret->next = cctxt->psData->nsMap;
511  cctxt->psData->nsMap = ret;
512 
513  return(ret);
514 }
515 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
516 
523 static void
524 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
525 {
526  xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
527 
528  while (ivar) {
529  ivartmp = ivar;
530  ivar = ivar->next;
531  xmlFree(ivartmp);
532  }
533 }
534 
540 static void
541 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
542 {
543  if (cctxt == NULL)
544  return;
545 #ifdef WITH_XSLT_DEBUG_PARSING
547  "Freeing compilation context\n");
549  "### Max inodes: %d\n", cctxt->maxNodeInfos);
551  "### Max LREs : %d\n", cctxt->maxLREs);
552 #endif
553  /*
554  * Free node-infos.
555  */
556  if (cctxt->inodeList != NULL) {
557  xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
558  while (cur != NULL) {
559  tmp = cur;
560  cur = cur->next;
561  xmlFree(tmp);
562  }
563  }
564  if (cctxt->tmpList != NULL)
565  xsltPointerListFree(cctxt->tmpList);
566 #ifdef XSLT_REFACTORED_XPATHCOMP
567  if (cctxt->xpathCtxt != NULL)
568  xmlXPathFreeContext(cctxt->xpathCtxt);
569 #endif
570  if (cctxt->nsAliases != NULL)
571  xsltFreeNsAliasList(cctxt->nsAliases);
572 
573  if (cctxt->ivars)
574  xsltCompilerVarInfoFree(cctxt);
575 
576  xmlFree(cctxt);
577 }
578 
587 static xsltCompilerCtxtPtr
588 xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
589  xsltCompilerCtxtPtr ret;
590 
591  ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
592  if (ret == NULL) {
594  "xsltCompilerCreate: allocation of compiler "
595  "context failed.\n");
596  return(NULL);
597  }
598  memset(ret, 0, sizeof(xsltCompilerCtxt));
599 
600  ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
601  ret->tmpList = xsltPointerListCreate(20);
602  if (ret->tmpList == NULL) {
603  goto internal_err;
604  }
605 #ifdef XSLT_REFACTORED_XPATHCOMP
606  /*
607  * Create the XPath compilation context in order
608  * to speed up precompilation of XPath expressions.
609  */
610  ret->xpathCtxt = xmlXPathNewContext(NULL);
611  if (ret->xpathCtxt == NULL)
612  goto internal_err;
613 #endif
614 
615  return(ret);
616 
617 internal_err:
618  xsltCompilationCtxtFree(ret);
619  return(NULL);
620 }
621 
622 static void
623 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
624 {
625  xsltEffectiveNsPtr tmp;
626 
627  while (first != NULL) {
628  tmp = first;
629  first = first->nextInStore;
630  xmlFree(tmp);
631  }
632 }
633 
634 static void
635 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
636 {
637  if (data == NULL)
638  return;
639 
640  if (data->inScopeNamespaces != NULL) {
641  int i;
642  xsltNsListContainerPtr nsi;
643  xsltPointerListPtr list =
644  (xsltPointerListPtr) data->inScopeNamespaces;
645 
646  for (i = 0; i < list->number; i++) {
647  /*
648  * REVISIT TODO: Free info of in-scope namespaces.
649  */
650  nsi = (xsltNsListContainerPtr) list->items[i];
651  if (nsi->list != NULL)
652  xmlFree(nsi->list);
653  xmlFree(nsi);
654  }
655  xsltPointerListFree(list);
656  data->inScopeNamespaces = NULL;
657  }
658 
659  if (data->exclResultNamespaces != NULL) {
660  int i;
661  xsltPointerListPtr list = (xsltPointerListPtr)
662  data->exclResultNamespaces;
663 
664  for (i = 0; i < list->number; i++)
665  xsltPointerListFree((xsltPointerListPtr) list->items[i]);
666 
667  xsltPointerListFree(list);
668  data->exclResultNamespaces = NULL;
669  }
670 
671  if (data->extElemNamespaces != NULL) {
672  xsltPointerListPtr list = (xsltPointerListPtr)
673  data->extElemNamespaces;
674  int i;
675 
676  for (i = 0; i < list->number; i++)
677  xsltPointerListFree((xsltPointerListPtr) list->items[i]);
678 
679  xsltPointerListFree(list);
680  data->extElemNamespaces = NULL;
681  }
682  if (data->effectiveNs) {
683  xsltLREEffectiveNsNodesFree(data->effectiveNs);
684  data->effectiveNs = NULL;
685  }
686 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
687  xsltFreeNamespaceMap(data->nsMap);
688 #endif
689  xmlFree(data);
690 }
691 
692 static xsltPrincipalStylesheetDataPtr
693 xsltNewPrincipalStylesheetData(void)
694 {
695  xsltPrincipalStylesheetDataPtr ret;
696 
697  ret = (xsltPrincipalStylesheetDataPtr)
698  xmlMalloc(sizeof(xsltPrincipalStylesheetData));
699  if (ret == NULL) {
701  "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
702  return(NULL);
703  }
704  memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
705 
706  /*
707  * Global list of in-scope namespaces.
708  */
709  ret->inScopeNamespaces = xsltPointerListCreate(-1);
710  if (ret->inScopeNamespaces == NULL)
711  goto internal_err;
712  /*
713  * Global list of excluded result ns-decls.
714  */
715  ret->exclResultNamespaces = xsltPointerListCreate(-1);
716  if (ret->exclResultNamespaces == NULL)
717  goto internal_err;
718  /*
719  * Global list of extension instruction namespace names.
720  */
721  ret->extElemNamespaces = xsltPointerListCreate(-1);
722  if (ret->extElemNamespaces == NULL)
723  goto internal_err;
724 
725  return(ret);
726 
727 internal_err:
728 
729  return(NULL);
730 }
731 
732 #endif
733 
744 
746  if (ret == NULL) {
748  "xsltNewStylesheet : malloc failed\n");
749  goto internal_err;
750  }
751  memset(ret, 0, sizeof(xsltStylesheet));
752 
753  ret->omitXmlDeclaration = -1;
754  ret->standalone = -1;
755  ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
756  ret->indent = -1;
757  ret->errors = 0;
758  ret->warnings = 0;
759  ret->exclPrefixNr = 0;
760  ret->exclPrefixMax = 0;
761  ret->exclPrefixTab = NULL;
762  ret->extInfos = NULL;
763  ret->extrasNr = 0;
764  ret->internalized = 1;
765  ret->literal_result = 0;
766  ret->forwards_compatible = 0;
767  ret->dict = xmlDictCreate();
768 #ifdef WITH_XSLT_DEBUG
770  "creating dictionary for stylesheet\n");
771 #endif
772 
773  xsltInit();
774 
775  return(ret);
776 
777 internal_err:
778  if (ret != NULL)
780  return(NULL);
781 }
782 
792 int
794 {
795  return(style->extrasNr++);
796 }
797 
808 int
810 {
811  if (ctxt->extrasNr >= ctxt->extrasMax) {
812  int i;
813  if (ctxt->extrasNr == 0) {
814  ctxt->extrasMax = 20;
815  ctxt->extras = (xsltRuntimeExtraPtr)
816  xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
817  if (ctxt->extras == NULL) {
819  "xsltAllocateExtraCtxt: out of memory\n");
820  return(0);
821  }
822  for (i = 0;i < ctxt->extrasMax;i++) {
823  ctxt->extras[i].info = NULL;
824  ctxt->extras[i].deallocate = NULL;
825  ctxt->extras[i].val.ptr = NULL;
826  }
827 
828  } else {
830 
831  ctxt->extrasMax += 100;
832  tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
833  ctxt->extrasMax * sizeof(xsltRuntimeExtra));
834  if (tmp == NULL) {
836  "xsltAllocateExtraCtxt: out of memory\n");
837  return(0);
838  }
839  ctxt->extras = tmp;
840  for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
841  ctxt->extras[i].info = NULL;
842  ctxt->extras[i].deallocate = NULL;
843  ctxt->extras[i].val.ptr = NULL;
844  }
845  }
846  }
847  return(ctxt->extrasNr++);
848 }
849 
856 static void
859 
860  while (style != NULL) {
861  next = style->next;
863  style = next;
864  }
865 }
866 
878 static int
880  xmlNodePtr rootElem ATTRIBUTE_UNUSED)
881 {
882 #if 0 /* TODO: Currently disabled, since probably not needed. */
883  xmlNodePtr cur;
884 
885  if ((doc == NULL) || (rootElem == NULL) ||
886  (rootElem->type != XML_ELEMENT_NODE) ||
887  (doc != rootElem->doc))
888  return(-1);
889 
890  /*
891  * Cleanup was suggested by Aleksey Sanin:
892  * Clear the PSVI field to avoid problems if the
893  * node-tree of the stylesheet is intended to be used for
894  * further processing by the user (e.g. for compiling it
895  * once again - although not recommended).
896  */
897 
898  cur = rootElem;
899  while (cur != NULL) {
900  if (cur->type == XML_ELEMENT_NODE) {
901  /*
902  * Clear the PSVI field.
903  */
904  cur->psvi = NULL;
905  if (cur->children) {
906  cur = cur->children;
907  continue;
908  }
909  }
910 
911 leave_node:
912  if (cur == rootElem)
913  break;
914  if (cur->next != NULL)
915  cur = cur->next;
916  else {
917  cur = cur->parent;
918  if (cur == NULL)
919  break;
920  goto leave_node;
921  }
922  }
923 #endif /* #if 0 */
924  return(0);
925 }
926 
933 void
935 {
936  if (style == NULL)
937  return;
938 
939 #ifdef XSLT_REFACTORED
940  /*
941  * Start with a cleanup of the main stylesheet's doc.
942  */
943  if ((style->principal == style) && (style->doc))
946 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
947  /*
948  * Restore changed ns-decls before freeing the document.
949  */
950  if ((style->doc != NULL) &&
951  XSLT_HAS_INTERNAL_NSMAP(style))
952  {
953  xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
954  style->doc);
955  }
956 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
957 #else
958  /*
959  * Start with a cleanup of the main stylesheet's doc.
960  */
961  if ((style->parent == NULL) && (style->doc))
964 #endif /* XSLT_REFACTORED */
965 
970  xsltFreeTemplateList(style->templates);
974  /*
975  * Free documents of all included stylsheet modules of this
976  * stylesheet level.
977  */
979  /*
980  * TODO: Best time to shutdown extension stuff?
981  */
983 
984  if (style->variables != NULL)
985  xsltFreeStackElemList(style->variables);
986  if (style->cdataSection != NULL)
987  xmlHashFree(style->cdataSection, NULL);
988  if (style->stripSpaces != NULL)
989  xmlHashFree(style->stripSpaces, NULL);
990  if (style->nsHash != NULL)
991  xmlHashFree(style->nsHash, NULL);
992  if (style->exclPrefixTab != NULL)
993  xmlFree(style->exclPrefixTab);
994  if (style->method != NULL)
995  xmlFree(style->method);
996  if (style->methodURI != NULL)
997  xmlFree(style->methodURI);
998  if (style->version != NULL)
999  xmlFree(style->version);
1000  if (style->encoding != NULL)
1001  xmlFree(style->encoding);
1002  if (style->doctypePublic != NULL)
1003  xmlFree(style->doctypePublic);
1004  if (style->doctypeSystem != NULL)
1005  xmlFree(style->doctypeSystem);
1006  if (style->mediaType != NULL)
1007  xmlFree(style->mediaType);
1008  if (style->attVTs)
1009  xsltFreeAVTList(style->attVTs);
1010  if (style->imports != NULL)
1011  xsltFreeStylesheetList(style->imports);
1012 
1013 #ifdef XSLT_REFACTORED
1014  /*
1015  * If this is the principal stylesheet, then
1016  * free its internal data.
1017  */
1018  if (style->principal == style) {
1019  if (style->principalData) {
1020  xsltFreePrincipalStylesheetData(style->principalData);
1021  style->principalData = NULL;
1022  }
1023  }
1024 #endif
1025  /*
1026  * Better to free the main document of this stylesheet level
1027  * at the end - so here.
1028  */
1029  if (style->doc != NULL) {
1030  xmlFreeDoc(style->doc);
1031  }
1032 
1033 #ifdef WITH_XSLT_DEBUG
1035  "freeing dictionary from stylesheet\n");
1036 #endif
1037  xmlDictFree(style->dict);
1038 
1039  memset(style, -1, sizeof(xsltStylesheet));
1040  xmlFree(style);
1041 }
1042 
1043 /************************************************************************
1044  * *
1045  * Parsing of an XSLT Stylesheet *
1046  * *
1047  ************************************************************************/
1048 
1049 #ifdef XSLT_REFACTORED
1050  /*
1051  * This is now performed in an optimized way in xsltParseXSLTTemplate.
1052  */
1053 #else
1054 
1066 static int
1068  xsltTemplatePtr template,
1069  xmlNodePtr node)
1070 {
1071  xmlNsPtr cur;
1072  xmlNsPtr *ret = NULL;
1073  int nbns = 0;
1074  int maxns = 10;
1075  int i;
1076 
1077  if ((style == NULL) || (template == NULL) || (node == NULL) ||
1078  (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1079  return(0);
1080  while (node != NULL) {
1081  if (node->type == XML_ELEMENT_NODE) {
1082  cur = node->nsDef;
1083  while (cur != NULL) {
1084  if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1085  goto skip_ns;
1086 
1087  if ((cur->prefix != NULL) &&
1088  (xsltCheckExtPrefix(style, cur->prefix)))
1089  goto skip_ns;
1090  /*
1091  * Check if this namespace was excluded.
1092  * Note that at this point only the exclusions defined
1093  * on the topmost stylesheet element are in the exclusion-list.
1094  */
1095  for (i = 0;i < style->exclPrefixNr;i++) {
1096  if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1097  goto skip_ns;
1098  }
1099  if (ret == NULL) {
1100  ret =
1101  (xmlNsPtr *) xmlMalloc((maxns + 1) *
1102  sizeof(xmlNsPtr));
1103  if (ret == NULL) {
1105  "xsltGetInheritedNsList : out of memory!\n");
1106  return(0);
1107  }
1108  ret[nbns] = NULL;
1109  }
1110  /*
1111  * Skip shadowed namespace bindings.
1112  */
1113  for (i = 0; i < nbns; i++) {
1114  if ((cur->prefix == ret[i]->prefix) ||
1115  (xmlStrEqual(cur->prefix, ret[i]->prefix)))
1116  break;
1117  }
1118  if (i >= nbns) {
1119  if (nbns >= maxns) {
1120  maxns *= 2;
1121  ret = (xmlNsPtr *) xmlRealloc(ret,
1122  (maxns +
1123  1) *
1124  sizeof(xmlNsPtr));
1125  if (ret == NULL) {
1127  "xsltGetInheritedNsList : realloc failed!\n");
1128  return(0);
1129  }
1130  }
1131  ret[nbns++] = cur;
1132  ret[nbns] = NULL;
1133  }
1134 skip_ns:
1135  cur = cur->next;
1136  }
1137  }
1138  node = node->parent;
1139  }
1140  if (nbns != 0) {
1141 #ifdef WITH_XSLT_DEBUG_PARSING
1143  "template has %d inherited namespaces\n", nbns);
1144 #endif
1145  template->inheritedNsNr = nbns;
1146  template->inheritedNs = ret;
1147  }
1148  return (nbns);
1149 }
1150 #endif /* else of XSLT_REFACTORED */
1151 
1161 void
1163 {
1164  xmlChar *elements,
1165  *prop;
1166  xmlChar *element,
1167  *end;
1168 
1169  if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1170  return;
1171 
1172  prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1173  if (prop != NULL) {
1174  if (style->version != NULL)
1175  xmlFree(style->version);
1176  style->version = prop;
1177  }
1178 
1179  prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1180  if (prop != NULL) {
1181  if (style->encoding != NULL)
1182  xmlFree(style->encoding);
1183  style->encoding = prop;
1184  }
1185 
1186  /* relaxed to support xt:document
1187  * TODO KB: What does "relaxed to support xt:document" mean?
1188  */
1189  prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1190  if (prop != NULL) {
1191  const xmlChar *URI;
1192 
1193  if (style->method != NULL)
1194  xmlFree(style->method);
1195  style->method = NULL;
1196  if (style->methodURI != NULL)
1197  xmlFree(style->methodURI);
1198  style->methodURI = NULL;
1199 
1200  /*
1201  * TODO: Don't use xsltGetQNameURI().
1202  */
1203  URI = xsltGetQNameURI(cur, &prop);
1204  if (prop == NULL) {
1205  if (style != NULL) style->errors++;
1206  } else if (URI == NULL) {
1207  if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1208  (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1209  (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1210  style->method = prop;
1211  } else {
1213  "invalid value for method: %s\n", prop);
1214  if (style != NULL) style->warnings++;
1215  xmlFree(prop);
1216  }
1217  } else {
1218  style->method = prop;
1219  style->methodURI = xmlStrdup(URI);
1220  }
1221  }
1222 
1223  prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1224  if (prop != NULL) {
1225  if (style->doctypeSystem != NULL)
1226  xmlFree(style->doctypeSystem);
1227  style->doctypeSystem = prop;
1228  }
1229 
1230  prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1231  if (prop != NULL) {
1232  if (style->doctypePublic != NULL)
1233  xmlFree(style->doctypePublic);
1234  style->doctypePublic = prop;
1235  }
1236 
1237  prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1238  if (prop != NULL) {
1239  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1240  style->standalone = 1;
1241  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1242  style->standalone = 0;
1243  } else {
1245  "invalid value for standalone: %s\n", prop);
1246  style->errors++;
1247  }
1248  xmlFree(prop);
1249  }
1250 
1251  prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1252  if (prop != NULL) {
1253  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1254  style->indent = 1;
1255  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1256  style->indent = 0;
1257  } else {
1259  "invalid value for indent: %s\n", prop);
1260  style->errors++;
1261  }
1262  xmlFree(prop);
1263  }
1264 
1265  prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1266  if (prop != NULL) {
1267  if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1268  style->omitXmlDeclaration = 1;
1269  } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1270  style->omitXmlDeclaration = 0;
1271  } else {
1273  "invalid value for omit-xml-declaration: %s\n",
1274  prop);
1275  style->errors++;
1276  }
1277  xmlFree(prop);
1278  }
1279 
1280  elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1281  NULL);
1282  if (elements != NULL) {
1283  if (style->cdataSection == NULL)
1284  style->cdataSection = xmlHashCreate(10);
1285  if (style->cdataSection == NULL)
1286  return;
1287 
1288  element = elements;
1289  while (*element != 0) {
1290  while (IS_BLANK(*element))
1291  element++;
1292  if (*element == 0)
1293  break;
1294  end = element;
1295  while ((*end != 0) && (!IS_BLANK(*end)))
1296  end++;
1298  if (element) {
1299 #ifdef WITH_XSLT_DEBUG_PARSING
1301  "add cdata section output element %s\n",
1302  element);
1303 #endif
1304  if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1306  "Attribute 'cdata-section-elements': The value "
1307  "'%s' is not a valid QName.\n", element);
1308  xmlFree(element);
1309  style->errors++;
1310  } else {
1311  const xmlChar *URI;
1312 
1313  /*
1314  * TODO: Don't use xsltGetQNameURI().
1315  */
1316  URI = xsltGetQNameURI(cur, &element);
1317  if (element == NULL) {
1318  /*
1319  * TODO: We'll report additionally an error
1320  * via the stylesheet's error handling.
1321  */
1323  "Attribute 'cdata-section-elements': The value "
1324  "'%s' is not a valid QName.\n", element);
1325  style->errors++;
1326  } else {
1327  xmlNsPtr ns;
1328 
1329  /*
1330  * XSLT-1.0 "Each QName is expanded into an
1331  * expanded-name using the namespace declarations in
1332  * effect on the xsl:output element in which the QName
1333  * occurs; if there is a default namespace, it is used
1334  * for QNames that do not have a prefix"
1335  * NOTE: Fix of bug #339570.
1336  */
1337  if (URI == NULL) {
1338  ns = xmlSearchNs(style->doc, cur, NULL);
1339  if (ns != NULL)
1340  URI = ns->href;
1341  }
1342  xmlHashAddEntry2(style->cdataSection, element, URI,
1343  (void *) "cdata");
1344  xmlFree(element);
1345  }
1346  }
1347  }
1348  element = end;
1349  }
1350  xmlFree(elements);
1351  }
1352 
1353  prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1354  if (prop != NULL) {
1355  if (style->mediaType)
1356  xmlFree(style->mediaType);
1357  style->mediaType = prop;
1358  }
1359  if (cur->children != NULL) {
1361  }
1362 }
1363 
1379 static void
1381 {
1382  xmlChar *prop;
1384  xsltDecimalFormatPtr iter;
1385 
1386  if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1387  return;
1388 
1389  format = style->decimalFormat;
1390 
1391  prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1392  if (prop != NULL) {
1393  const xmlChar *nsUri;
1394 
1395  if (xmlValidateQName(prop, 0) != 0) {
1397  "xsl:decimal-format: Invalid QName '%s'.\n", prop);
1398  style->warnings++;
1399  xmlFree(prop);
1400  return;
1401  }
1402  /*
1403  * TODO: Don't use xsltGetQNameURI().
1404  */
1405  nsUri = xsltGetQNameURI(cur, &prop);
1406  if (prop == NULL) {
1407  style->warnings++;
1408  return;
1409  }
1410  format = xsltDecimalFormatGetByQName(style, nsUri, prop);
1411  if (format != NULL) {
1413  "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1414  style->warnings++;
1415  xmlFree(prop);
1416  return;
1417  }
1418  format = xsltNewDecimalFormat(nsUri, prop);
1419  if (format == NULL) {
1421  "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1422  style->errors++;
1423  xmlFree(prop);
1424  return;
1425  }
1426  /* Append new decimal-format structure */
1427  for (iter = style->decimalFormat; iter->next; iter = iter->next)
1428  ;
1429  if (iter)
1430  iter->next = format;
1431  }
1432 
1433  prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1434  if (prop != NULL) {
1435  if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1436  format->decimalPoint = prop;
1437  }
1438 
1439  prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1440  if (prop != NULL) {
1441  if (format->grouping != NULL) xmlFree(format->grouping);
1442  format->grouping = prop;
1443  }
1444 
1445  prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1446  if (prop != NULL) {
1447  if (format->infinity != NULL) xmlFree(format->infinity);
1448  format->infinity = prop;
1449  }
1450 
1451  prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1452  if (prop != NULL) {
1453  if (format->minusSign != NULL) xmlFree(format->minusSign);
1454  format->minusSign = prop;
1455  }
1456 
1457  prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1458  if (prop != NULL) {
1459  if (format->noNumber != NULL) xmlFree(format->noNumber);
1460  format->noNumber = prop;
1461  }
1462 
1463  prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1464  if (prop != NULL) {
1465  if (format->percent != NULL) xmlFree(format->percent);
1466  format->percent = prop;
1467  }
1468 
1469  prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1470  if (prop != NULL) {
1471  if (format->permille != NULL) xmlFree(format->permille);
1472  format->permille = prop;
1473  }
1474 
1475  prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1476  if (prop != NULL) {
1477  if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1478  format->zeroDigit = prop;
1479  }
1480 
1481  prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1482  if (prop != NULL) {
1483  if (format->digit != NULL) xmlFree(format->digit);
1484  format->digit = prop;
1485  }
1486 
1487  prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1488  if (prop != NULL) {
1489  if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1490  format->patternSeparator = prop;
1491  }
1492  if (cur->children != NULL) {
1494  }
1495 }
1496 
1506 static void
1508  xmlChar *elements;
1509  xmlChar *element, *end;
1510 
1511  if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1512  return;
1513 
1514  elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1515  if (elements == NULL) {
1517  "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1518  if (style != NULL) style->warnings++;
1519  return;
1520  }
1521 
1522  if (style->stripSpaces == NULL)
1523  style->stripSpaces = xmlHashCreate(10);
1524  if (style->stripSpaces == NULL)
1525  return;
1526 
1527  element = elements;
1528  while (*element != 0) {
1529  while (IS_BLANK(*element)) element++;
1530  if (*element == 0)
1531  break;
1532  end = element;
1533  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1535  if (element) {
1536 #ifdef WITH_XSLT_DEBUG_PARSING
1538  "add preserved space element %s\n", element);
1539 #endif
1540  if (xmlStrEqual(element, (const xmlChar *)"*")) {
1541  style->stripAll = -1;
1542  } else {
1543  const xmlChar *URI;
1544 
1545  /*
1546  * TODO: Don't use xsltGetQNameURI().
1547  */
1548  URI = xsltGetQNameURI(cur, &element);
1549 
1550  xmlHashAddEntry2(style->stripSpaces, element, URI,
1551  (xmlChar *) "preserve");
1552  }
1553  xmlFree(element);
1554  }
1555  element = end;
1556  }
1557  xmlFree(elements);
1558  if (cur->children != NULL) {
1560  }
1561 }
1562 
1563 #ifdef XSLT_REFACTORED
1564 #else
1565 
1579 static void
1581  int isXsltElem) {
1582  xmlChar *prefixes;
1583  xmlChar *prefix, *end;
1584 
1585  if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1586  return;
1587 
1588  if (isXsltElem) {
1589  /* For xsl:stylesheet/xsl:transform. */
1590  prefixes = xmlGetNsProp(cur,
1591  (const xmlChar *)"extension-element-prefixes", NULL);
1592  } else {
1593  /* For literal result elements and extension instructions. */
1594  prefixes = xmlGetNsProp(cur,
1595  (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1596  }
1597  if (prefixes == NULL) {
1598  return;
1599  }
1600 
1601  prefix = prefixes;
1602  while (*prefix != 0) {
1603  while (IS_BLANK(*prefix)) prefix++;
1604  if (*prefix == 0)
1605  break;
1606  end = prefix;
1607  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1608  prefix = xmlStrndup(prefix, end - prefix);
1609  if (prefix) {
1610  xmlNsPtr ns;
1611 
1612  if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1613  ns = xmlSearchNs(style->doc, cur, NULL);
1614  else
1615  ns = xmlSearchNs(style->doc, cur, prefix);
1616  if (ns == NULL) {
1618  "xsl:extension-element-prefix : undefined namespace %s\n",
1619  prefix);
1620  if (style != NULL) style->warnings++;
1621  } else {
1622 #ifdef WITH_XSLT_DEBUG_PARSING
1624  "add extension prefix %s\n", prefix);
1625 #endif
1626  xsltRegisterExtPrefix(style, prefix, ns->href);
1627  }
1628  xmlFree(prefix);
1629  }
1630  prefix = end;
1631  }
1632  xmlFree(prefixes);
1633 }
1634 #endif /* else of XSLT_REFACTORED */
1635 
1645 static void
1647  xmlChar *elements;
1648  xmlChar *element, *end;
1649 
1650  if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1651  return;
1652 
1653  elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1654  if (elements == NULL) {
1656  "xsltParseStylesheetStripSpace: missing elements attribute\n");
1657  if (style != NULL) style->warnings++;
1658  return;
1659  }
1660 
1661  if (style->stripSpaces == NULL)
1662  style->stripSpaces = xmlHashCreate(10);
1663  if (style->stripSpaces == NULL)
1664  return;
1665 
1666  element = elements;
1667  while (*element != 0) {
1668  while (IS_BLANK(*element)) element++;
1669  if (*element == 0)
1670  break;
1671  end = element;
1672  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1674  if (element) {
1675 #ifdef WITH_XSLT_DEBUG_PARSING
1677  "add stripped space element %s\n", element);
1678 #endif
1679  if (xmlStrEqual(element, (const xmlChar *)"*")) {
1680  style->stripAll = 1;
1681  } else {
1682  const xmlChar *URI;
1683 
1684  /*
1685  * TODO: Don't use xsltGetQNameURI().
1686  */
1687  URI = xsltGetQNameURI(cur, &element);
1688 
1689  xmlHashAddEntry2(style->stripSpaces, element, URI,
1690  (xmlChar *) "strip");
1691  }
1692  xmlFree(element);
1693  }
1694  element = end;
1695  }
1696  xmlFree(elements);
1697  if (cur->children != NULL) {
1699  }
1700 }
1701 
1702 #ifdef XSLT_REFACTORED
1703 #else
1704 
1715 static int
1717  int isXsltElem)
1718 {
1719  int nb = 0;
1720  xmlChar *prefixes;
1721  xmlChar *prefix, *end;
1722 
1723  if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1724  return(0);
1725 
1726  if (isXsltElem)
1727  prefixes = xmlGetNsProp(cur,
1728  (const xmlChar *)"exclude-result-prefixes", NULL);
1729  else
1730  prefixes = xmlGetNsProp(cur,
1731  (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1732 
1733  if (prefixes == NULL) {
1734  return(0);
1735  }
1736 
1737  prefix = prefixes;
1738  while (*prefix != 0) {
1739  while (IS_BLANK(*prefix)) prefix++;
1740  if (*prefix == 0)
1741  break;
1742  end = prefix;
1743  while ((*end != 0) && (!IS_BLANK(*end))) end++;
1744  prefix = xmlStrndup(prefix, end - prefix);
1745  if (prefix) {
1746  xmlNsPtr ns;
1747 
1748  if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1749  ns = xmlSearchNs(style->doc, cur, NULL);
1750  else
1751  ns = xmlSearchNs(style->doc, cur, prefix);
1752  if (ns == NULL) {
1754  "xsl:exclude-result-prefixes : undefined namespace %s\n",
1755  prefix);
1756  if (style != NULL) style->warnings++;
1757  } else {
1758  if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
1759 #ifdef WITH_XSLT_DEBUG_PARSING
1761  "exclude result prefix %s\n", prefix);
1762 #endif
1763  nb++;
1764  }
1765  }
1766  xmlFree(prefix);
1767  }
1768  prefix = end;
1769  }
1770  xmlFree(prefixes);
1771  return(nb);
1772 }
1773 #endif /* else of XSLT_REFACTORED */
1774 
1775 #ifdef XSLT_REFACTORED
1776 
1777 /*
1778 * xsltTreeEnsureXMLDecl:
1779 * @doc: the doc
1780 *
1781 * BIG NOTE:
1782 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1783 * Ensures that there is an XML namespace declaration on the doc.
1784 *
1785 * Returns the XML ns-struct or NULL on API and internal errors.
1786 */
1787 static xmlNsPtr
1788 xsltTreeEnsureXMLDecl(xmlDocPtr doc)
1789 {
1790  if (doc == NULL)
1791  return (NULL);
1792  if (doc->oldNs != NULL)
1793  return (doc->oldNs);
1794  {
1795  xmlNsPtr ns;
1796  ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1797  if (ns == NULL) {
1799  "xsltTreeEnsureXMLDecl: Failed to allocate "
1800  "the XML namespace.\n");
1801  return (NULL);
1802  }
1803  memset(ns, 0, sizeof(xmlNs));
1804  ns->type = XML_LOCAL_NAMESPACE;
1805  /*
1806  * URGENT TODO: revisit this.
1807  */
1808 #ifdef LIBXML_NAMESPACE_DICT
1809  if (doc->dict)
1810  ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
1811  else
1812  ns->href = xmlStrdup(XML_XML_NAMESPACE);
1813 #else
1814  ns->href = xmlStrdup(XML_XML_NAMESPACE);
1815 #endif
1816  ns->prefix = xmlStrdup((const xmlChar *)"xml");
1817  doc->oldNs = ns;
1818  return (ns);
1819  }
1820 }
1821 
1822 /*
1823 * xsltTreeAcquireStoredNs:
1824 * @doc: the doc
1825 * @nsName: the namespace name
1826 * @prefix: the prefix
1827 *
1828 * BIG NOTE:
1829 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1830 * Creates or reuses an xmlNs struct on doc->oldNs with
1831 * the given prefix and namespace name.
1832 *
1833 * Returns the aquired ns struct or NULL in case of an API
1834 * or internal error.
1835 */
1836 static xmlNsPtr
1837 xsltTreeAcquireStoredNs(xmlDocPtr doc,
1838  const xmlChar *nsName,
1839  const xmlChar *prefix)
1840 {
1841  xmlNsPtr ns;
1842 
1843  if (doc == NULL)
1844  return (NULL);
1845  if (doc->oldNs != NULL)
1846  ns = doc->oldNs;
1847  else
1848  ns = xsltTreeEnsureXMLDecl(doc);
1849  if (ns == NULL)
1850  return (NULL);
1851  if (ns->next != NULL) {
1852  /* Reuse. */
1853  ns = ns->next;
1854  while (ns != NULL) {
1855  if ((ns->prefix == NULL) != (prefix == NULL)) {
1856  /* NOP */
1857  } else if (prefix == NULL) {
1858  if (xmlStrEqual(ns->href, nsName))
1859  return (ns);
1860  } else {
1861  if ((ns->prefix[0] == prefix[0]) &&
1862  xmlStrEqual(ns->prefix, prefix) &&
1863  xmlStrEqual(ns->href, nsName))
1864  return (ns);
1865 
1866  }
1867  if (ns->next == NULL)
1868  break;
1869  ns = ns->next;
1870  }
1871  }
1872  /* Create. */
1873  ns->next = xmlNewNs(NULL, nsName, prefix);
1874  return (ns->next);
1875 }
1876 
1883 static int
1884 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
1885  xmlNodePtr elem)
1886 {
1887  xmlNsPtr ns;
1888  xsltNsAliasPtr alias;
1889 
1890  if ((cctxt == NULL) || (elem == NULL))
1891  return(-1);
1892  if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
1893  return(0);
1894 
1895  alias = cctxt->nsAliases;
1896  while (alias != NULL) {
1897  if ( /* If both namespaces are NULL... */
1898  ( (elem->ns == NULL) &&
1899  ((alias->literalNs == NULL) ||
1900  (alias->literalNs->href == NULL)) ) ||
1901  /* ... or both namespace are equal */
1902  ( (elem->ns != NULL) &&
1903  (alias->literalNs != NULL) &&
1904  xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1905  {
1906  if ((alias->targetNs != NULL) &&
1907  (alias->targetNs->href != NULL))
1908  {
1909  /*
1910  * Convert namespace.
1911  */
1912  if (elem->doc == alias->docOfTargetNs) {
1913  /*
1914  * This is the nice case: same docs.
1915  * This will eventually assign a ns-decl which
1916  * is shadowed, but this has no negative effect on
1917  * the generation of the result tree.
1918  */
1919  elem->ns = alias->targetNs;
1920  } else {
1921  /*
1922  * This target xmlNs originates from a different
1923  * stylesheet tree. Try to locate it in the
1924  * in-scope namespaces.
1925  * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1926  */
1927  ns = xmlSearchNs(elem->doc, elem,
1928  alias->targetNs->prefix);
1929  /*
1930  * If no matching ns-decl found, then assign a
1931  * ns-decl stored in xmlDoc.
1932  */
1933  if ((ns == NULL) ||
1934  (! xmlStrEqual(ns->href, alias->targetNs->href)))
1935  {
1936  /*
1937  * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1938  * is not very efficient, but currently I don't
1939  * see an other way of *safely* changing a node's
1940  * namespace, since the xmlNs struct in
1941  * alias->targetNs might come from an other
1942  * stylesheet tree. So we need to anchor it in the
1943  * current document, without adding it to the tree,
1944  * which would otherwise change the in-scope-ns
1945  * semantic of the tree.
1946  */
1947  ns = xsltTreeAcquireStoredNs(elem->doc,
1948  alias->targetNs->href,
1949  alias->targetNs->prefix);
1950 
1951  if (ns == NULL) {
1952  xsltTransformError(NULL, cctxt->style, elem,
1953  "Internal error in "
1954  "xsltLREBuildEffectiveNs(): "
1955  "failed to acquire a stored "
1956  "ns-declaration.\n");
1957  cctxt->style->errors++;
1958  return(-1);
1959 
1960  }
1961  }
1962  elem->ns = ns;
1963  }
1964  } else {
1965  /*
1966  * Move into or leave in the NULL namespace.
1967  */
1968  elem->ns = NULL;
1969  }
1970  break;
1971  }
1972  alias = alias->next;
1973  }
1974  /*
1975  * Same with attributes of literal result elements.
1976  */
1977  if (elem->properties != NULL) {
1978  xmlAttrPtr attr = elem->properties;
1979 
1980  while (attr != NULL) {
1981  if (attr->ns == NULL) {
1982  attr = attr->next;
1983  continue;
1984  }
1985  alias = cctxt->nsAliases;
1986  while (alias != NULL) {
1987  if ( /* If both namespaces are NULL... */
1988  ( (elem->ns == NULL) &&
1989  ((alias->literalNs == NULL) ||
1990  (alias->literalNs->href == NULL)) ) ||
1991  /* ... or both namespace are equal */
1992  ( (elem->ns != NULL) &&
1993  (alias->literalNs != NULL) &&
1994  xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1995  {
1996  if ((alias->targetNs != NULL) &&
1997  (alias->targetNs->href != NULL))
1998  {
1999  if (elem->doc == alias->docOfTargetNs) {
2000  elem->ns = alias->targetNs;
2001  } else {
2002  ns = xmlSearchNs(elem->doc, elem,
2003  alias->targetNs->prefix);
2004  if ((ns == NULL) ||
2005  (! xmlStrEqual(ns->href, alias->targetNs->href)))
2006  {
2007  ns = xsltTreeAcquireStoredNs(elem->doc,
2008  alias->targetNs->href,
2009  alias->targetNs->prefix);
2010 
2011  if (ns == NULL) {
2012  xsltTransformError(NULL, cctxt->style, elem,
2013  "Internal error in "
2014  "xsltLREBuildEffectiveNs(): "
2015  "failed to acquire a stored "
2016  "ns-declaration.\n");
2017  cctxt->style->errors++;
2018  return(-1);
2019 
2020  }
2021  }
2022  elem->ns = ns;
2023  }
2024  } else {
2025  /*
2026  * Move into or leave in the NULL namespace.
2027  */
2028  elem->ns = NULL;
2029  }
2030  break;
2031  }
2032  alias = alias->next;
2033  }
2034 
2035  attr = attr->next;
2036  }
2037  }
2038  return(0);
2039 }
2040 
2054 static int
2055 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2056  xsltStyleItemLRElementInfoPtr item,
2057  xmlNodePtr elem,
2058  int isLRE)
2059 {
2060  xmlNsPtr ns, tmpns;
2061  xsltEffectiveNsPtr effNs, lastEffNs = NULL;
2062  int i, j, holdByElem;
2063  xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
2064  xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
2065 
2066  if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
2067  (item == NULL) || (item->effectiveNs != NULL))
2068  return(-1);
2069 
2070  if (item->inScopeNs == NULL)
2071  return(0);
2072 
2073  extElemNs = cctxt->inode->extElemNs;
2074  exclResultNs = cctxt->inode->exclResultNs;
2075 
2076  for (i = 0; i < item->inScopeNs->totalNumber; i++) {
2077  ns = item->inScopeNs->list[i];
2078  /*
2079  * Skip namespaces designated as excluded namespaces
2080  * -------------------------------------------------
2081  *
2082  * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2083  * which are target namespaces of namespace-aliases
2084  * regardless if designated as excluded.
2085  *
2086  * Exclude the XSLT namespace.
2087  */
2088  if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2089  goto skip_ns;
2090 
2091  /*
2092  * Apply namespace aliasing
2093  * ------------------------
2094  *
2095  * SPEC XSLT 2.0
2096  * "- A namespace node whose string value is a literal namespace
2097  * URI is not copied to the result tree.
2098  * - A namespace node whose string value is a target namespace URI
2099  * is copied to the result tree, whether or not the URI
2100  * identifies an excluded namespace."
2101  *
2102  * NOTE: The ns-aliasing machanism is non-cascading.
2103  * (checked with Saxon, Xalan and MSXML .NET).
2104  * URGENT TODO: is style->nsAliases the effective list of
2105  * ns-aliases, or do we need to lookup the whole
2106  * import-tree?
2107  * TODO: Get rid of import-tree lookup.
2108  */
2109  if (cctxt->hasNsAliases) {
2110  xsltNsAliasPtr alias;
2111  /*
2112  * First check for being a target namespace.
2113  */
2114  alias = cctxt->nsAliases;
2115  do {
2116  /*
2117  * TODO: Is xmlns="" handled already?
2118  */
2119  if ((alias->targetNs != NULL) &&
2120  (xmlStrEqual(alias->targetNs->href, ns->href)))
2121  {
2122  /*
2123  * Recognized as a target namespace; use it regardless
2124  * if excluded otherwise.
2125  */
2126  goto add_effective_ns;
2127  }
2128  alias = alias->next;
2129  } while (alias != NULL);
2130 
2131  alias = cctxt->nsAliases;
2132  do {
2133  /*
2134  * TODO: Is xmlns="" handled already?
2135  */
2136  if ((alias->literalNs != NULL) &&
2137  (xmlStrEqual(alias->literalNs->href, ns->href)))
2138  {
2139  /*
2140  * Recognized as an namespace alias; do not use it.
2141  */
2142  goto skip_ns;
2143  }
2144  alias = alias->next;
2145  } while (alias != NULL);
2146  }
2147 
2148  /*
2149  * Exclude excluded result namespaces.
2150  */
2151  if (exclResultNs) {
2152  for (j = 0; j < exclResultNs->number; j++)
2153  if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
2154  goto skip_ns;
2155  }
2156  /*
2157  * Exclude extension-element namespaces.
2158  */
2159  if (extElemNs) {
2160  for (j = 0; j < extElemNs->number; j++)
2161  if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
2162  goto skip_ns;
2163  }
2164 
2165 add_effective_ns:
2166  /*
2167  * OPTIMIZE TODO: This information may not be needed.
2168  */
2169  if (isLRE && (elem->nsDef != NULL)) {
2170  holdByElem = 0;
2171  tmpns = elem->nsDef;
2172  do {
2173  if (tmpns == ns) {
2174  holdByElem = 1;
2175  break;
2176  }
2177  tmpns = tmpns->next;
2178  } while (tmpns != NULL);
2179  } else
2180  holdByElem = 0;
2181 
2182 
2183  /*
2184  * Add the effective namespace declaration.
2185  */
2186  effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
2187  if (effNs == NULL) {
2188  xsltTransformError(NULL, cctxt->style, elem,
2189  "Internal error in xsltLREBuildEffectiveNs(): "
2190  "failed to allocate memory.\n");
2191  cctxt->style->errors++;
2192  return(-1);
2193  }
2194  if (cctxt->psData->effectiveNs == NULL) {
2195  cctxt->psData->effectiveNs = effNs;
2196  effNs->nextInStore = NULL;
2197  } else {
2198  effNs->nextInStore = cctxt->psData->effectiveNs;
2199  cctxt->psData->effectiveNs = effNs;
2200  }
2201 
2202  effNs->next = NULL;
2203  effNs->prefix = ns->prefix;
2204  effNs->nsName = ns->href;
2205  effNs->holdByElem = holdByElem;
2206 
2207  if (lastEffNs == NULL)
2208  item->effectiveNs = effNs;
2209  else
2210  lastEffNs->next = effNs;
2211  lastEffNs = effNs;
2212 
2213 skip_ns:
2214  {}
2215  }
2216  return(0);
2217 }
2218 
2219 
2227 static int
2228 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
2229  xmlNodePtr elem,
2230  int isLRE)
2231 {
2232  xsltStyleItemLRElementInfoPtr item;
2233 
2234  if ((cctxt == NULL) || (cctxt->inode == NULL))
2235  return(-1);
2236 
2237  item = (xsltStyleItemLRElementInfoPtr)
2238  xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
2239  if (item == NULL) {
2240  xsltTransformError(NULL, cctxt->style, NULL,
2241  "Internal error in xsltLREInfoCreate(): "
2242  "memory allocation failed.\n");
2243  cctxt->style->errors++;
2244  return(-1);
2245  }
2246  memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
2247  item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
2248  /*
2249  * Store it in the stylesheet.
2250  */
2251  item->next = cctxt->style->preComps;
2252  cctxt->style->preComps = (xsltElemPreCompPtr) item;
2253  /*
2254  * @inScopeNs are used for execution of XPath expressions
2255  * in AVTs.
2256  */
2257  item->inScopeNs = cctxt->inode->inScopeNs;
2258 
2259  if (elem)
2260  xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
2261 
2262  cctxt->inode->litResElemInfo = item;
2263  cctxt->inode->nsChanged = 0;
2264  cctxt->maxLREs++;
2265  return(0);
2266 }
2267 
2276 static xsltVarInfoPtr
2277 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
2278  xmlNodePtr inst,
2279  const xmlChar *name,
2280  const xmlChar *nsName)
2281 {
2282  xsltVarInfoPtr ivar;
2283 
2284  if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
2285  ivar = cctxt->ivar->next;
2286  } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
2287  ivar = cctxt->ivars;
2288  } else {
2289  ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
2290  if (ivar == NULL) {
2291  xsltTransformError(NULL, cctxt->style, inst,
2292  "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2293  cctxt->style->errors++;
2294  return(NULL);
2295  }
2296  /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2297  if (cctxt->ivars == NULL) {
2298  cctxt->ivars = ivar;
2299  ivar->prev = NULL;
2300  } else {
2301  cctxt->ivar->next = ivar;
2302  ivar->prev = cctxt->ivar;
2303  }
2304  cctxt->ivar = ivar;
2305  ivar->next = NULL;
2306  }
2307  ivar->depth = cctxt->depth;
2308  ivar->name = name;
2309  ivar->nsName = nsName;
2310  return(ivar);
2311 }
2312 
2320 static void
2321 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
2322 {
2323 
2324  while ((cctxt->ivar != NULL) &&
2325  (cctxt->ivar->depth > cctxt->depth))
2326  {
2327  cctxt->ivar = cctxt->ivar->prev;
2328  }
2329 }
2330 
2331 /*
2332 * xsltCompilerNodePush:
2333 *
2334 * @cctxt: the compilation context
2335 * @node: the node to be pushed (this can also be the doc-node)
2336 *
2337 *
2338 *
2339 * Returns the current node info structure or
2340 * NULL in case of an internal error.
2341 */
2342 static xsltCompilerNodeInfoPtr
2343 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2344 {
2345  xsltCompilerNodeInfoPtr inode, iprev;
2346 
2347  if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
2348  inode = cctxt->inode->next;
2349  } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
2350  inode = cctxt->inodeList;
2351  } else {
2352  /*
2353  * Create a new node-info.
2354  */
2355  inode = (xsltCompilerNodeInfoPtr)
2356  xmlMalloc(sizeof(xsltCompilerNodeInfo));
2357  if (inode == NULL) {
2358  xsltTransformError(NULL, cctxt->style, NULL,
2359  "xsltCompilerNodePush: malloc failed.\n");
2360  return(NULL);
2361  }
2362  memset(inode, 0, sizeof(xsltCompilerNodeInfo));
2363  if (cctxt->inodeList == NULL)
2364  cctxt->inodeList = inode;
2365  else {
2366  cctxt->inodeLast->next = inode;
2367  inode->prev = cctxt->inodeLast;
2368  }
2369  cctxt->inodeLast = inode;
2370  cctxt->maxNodeInfos++;
2371  if (cctxt->inode == NULL) {
2372  cctxt->inode = inode;
2373  /*
2374  * Create an initial literal result element info for
2375  * the root of the stylesheet.
2376  */
2377  xsltLREInfoCreate(cctxt, NULL, 0);
2378  }
2379  }
2380  cctxt->depth++;
2381  cctxt->inode = inode;
2382  /*
2383  * REVISIT TODO: Keep the reset always complete.
2384  * NOTE: Be carefull with the @node, since it might be
2385  * a doc-node.
2386  */
2387  inode->node = node;
2388  inode->depth = cctxt->depth;
2389  inode->templ = NULL;
2390  inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
2391  inode->type = 0;
2392  inode->item = NULL;
2393  inode->curChildType = 0;
2394  inode->extContentHandled = 0;
2395  inode->isRoot = 0;
2396 
2397  if (inode->prev != NULL) {
2398  iprev = inode->prev;
2399  /*
2400  * Inherit the following information:
2401  * ---------------------------------
2402  *
2403  * In-scope namespaces
2404  */
2405  inode->inScopeNs = iprev->inScopeNs;
2406  /*
2407  * Info for literal result elements
2408  */
2409  inode->litResElemInfo = iprev->litResElemInfo;
2410  inode->nsChanged = iprev->nsChanged;
2411  /*
2412  * Excluded result namespaces
2413  */
2414  inode->exclResultNs = iprev->exclResultNs;
2415  /*
2416  * Extension instruction namespaces
2417  */
2418  inode->extElemNs = iprev->extElemNs;
2419  /*
2420  * Whitespace preservation
2421  */
2422  inode->preserveWhitespace = iprev->preserveWhitespace;
2423  /*
2424  * Forwards-compatible mode
2425  */
2426  inode->forwardsCompat = iprev->forwardsCompat;
2427  } else {
2428  inode->inScopeNs = NULL;
2429  inode->exclResultNs = NULL;
2430  inode->extElemNs = NULL;
2431  inode->preserveWhitespace = 0;
2432  inode->forwardsCompat = 0;
2433  }
2434 
2435  return(inode);
2436 }
2437 
2438 /*
2439 * xsltCompilerNodePop:
2440 *
2441 * @cctxt: the compilation context
2442 * @node: the node to be pushed (this can also be the doc-node)
2443 *
2444 * Pops the current node info.
2445 */
2446 static void
2447 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2448 {
2449  if (cctxt->inode == NULL) {
2451  "xsltCompilerNodePop: Top-node mismatch.\n");
2452  return;
2453  }
2454  /*
2455  * NOTE: Be carefull with the @node, since it might be
2456  * a doc-node.
2457  */
2458  if (cctxt->inode->node != node) {
2460  "xsltCompilerNodePop: Node mismatch.\n");
2461  goto mismatch;
2462  }
2463  if (cctxt->inode->depth != cctxt->depth) {
2465  "xsltCompilerNodePop: Depth mismatch.\n");
2466  goto mismatch;
2467  }
2468  cctxt->depth--;
2469  /*
2470  * Pop information of variables.
2471  */
2472  if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
2473  xsltCompilerVarInfoPop(cctxt);
2474 
2475  cctxt->inode = cctxt->inode->prev;
2476  if (cctxt->inode != NULL)
2477  cctxt->inode->curChildType = 0;
2478  return;
2479 
2480 mismatch:
2481  {
2482  const xmlChar *nsName = NULL, *name = NULL;
2483  const xmlChar *infnsName = NULL, *infname = NULL;
2484 
2485  if (node) {
2486  if (node->type == XML_ELEMENT_NODE) {
2487  name = node->name;
2488  if (node->ns != NULL)
2489  nsName = node->ns->href;
2490  else
2491  nsName = BAD_CAST "";
2492  } else {
2493  name = BAD_CAST "#document";
2494  nsName = BAD_CAST "";
2495  }
2496  } else
2497  name = BAD_CAST "Not given";
2498 
2499  if (cctxt->inode->node) {
2500  if (node->type == XML_ELEMENT_NODE) {
2501  infname = cctxt->inode->node->name;
2502  if (cctxt->inode->node->ns != NULL)
2503  infnsName = cctxt->inode->node->ns->href;
2504  else
2505  infnsName = BAD_CAST "";
2506  } else {
2507  infname = BAD_CAST "#document";
2508  infnsName = BAD_CAST "";
2509  }
2510  } else
2511  infname = BAD_CAST "Not given";
2512 
2513 
2515  "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2516  name, nsName);
2518  "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2519  infname, infnsName);
2520  }
2521 }
2522 
2523 /*
2524 * xsltCompilerBuildInScopeNsList:
2525 *
2526 * Create and store the list of in-scope namespaces for the given
2527 * node in the stylesheet. If there are no changes in the in-scope
2528 * namespaces then the last ns-info of the ancestor axis will be returned.
2529 * Compilation-time only.
2530 *
2531 * Returns the ns-info or NULL if there are no namespaces in scope.
2532 */
2533 static xsltNsListContainerPtr
2534 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2535 {
2536  xsltNsListContainerPtr nsi = NULL;
2537  xmlNsPtr *list = NULL, ns;
2538  int i, maxns = 5;
2539  /*
2540  * Create a new ns-list for this position in the node-tree.
2541  * xmlGetNsList() will return NULL, if there are no ns-decls in the
2542  * tree. Note that the ns-decl for the XML namespace is not added
2543  * to the resulting list; the XPath module handles the XML namespace
2544  * internally.
2545  */
2546  while (node != NULL) {
2547  if (node->type == XML_ELEMENT_NODE) {
2548  ns = node->nsDef;
2549  while (ns != NULL) {
2550  if (nsi == NULL) {
2551  nsi = (xsltNsListContainerPtr)
2552  xmlMalloc(sizeof(xsltNsListContainer));
2553  if (nsi == NULL) {
2554  xsltTransformError(NULL, cctxt->style, NULL,
2555  "xsltCompilerBuildInScopeNsList: "
2556  "malloc failed!\n");
2557  goto internal_err;
2558  }
2559  memset(nsi, 0, sizeof(xsltNsListContainer));
2560  nsi->list =
2561  (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
2562  if (nsi->list == NULL) {
2563  xsltTransformError(NULL, cctxt->style, NULL,
2564  "xsltCompilerBuildInScopeNsList: "
2565  "malloc failed!\n");
2566  goto internal_err;
2567  }
2568  nsi->list[0] = NULL;
2569  }
2570  /*
2571  * Skip shadowed namespace bindings.
2572  */
2573  for (i = 0; i < nsi->totalNumber; i++) {
2574  if ((ns->prefix == nsi->list[i]->prefix) ||
2575  (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
2576  break;
2577  }
2578  if (i >= nsi->totalNumber) {
2579  if (nsi->totalNumber +1 >= maxns) {
2580  maxns *= 2;
2581  nsi->list =
2582  (xmlNsPtr *) xmlRealloc(nsi->list,
2583  maxns * sizeof(xmlNsPtr));
2584  if (nsi->list == NULL) {
2585  xsltTransformError(NULL, cctxt->style, NULL,
2586  "xsltCompilerBuildInScopeNsList: "
2587  "realloc failed!\n");
2588  goto internal_err;
2589  }
2590  }
2591  nsi->list[nsi->totalNumber++] = ns;
2592  nsi->list[nsi->totalNumber] = NULL;
2593  }
2594 
2595  ns = ns->next;
2596  }
2597  }
2598  node = node->parent;
2599  }
2600  if (nsi == NULL)
2601  return(NULL);
2602  /*
2603  * Move the default namespace to last position.
2604  */
2605  nsi->xpathNumber = nsi->totalNumber;
2606  for (i = 0; i < nsi->totalNumber; i++) {
2607  if (nsi->list[i]->prefix == NULL) {
2608  ns = nsi->list[i];
2609  nsi->list[i] = nsi->list[nsi->totalNumber-1];
2610  nsi->list[nsi->totalNumber-1] = ns;
2611  nsi->xpathNumber--;
2612  break;
2613  }
2614  }
2615  /*
2616  * Store the ns-list in the stylesheet.
2617  */
2618  if (xsltPointerListAddSize(
2619  (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
2620  (void *) nsi, 5) == -1)
2621  {
2622  xmlFree(nsi);
2623  nsi = NULL;
2624  xsltTransformError(NULL, cctxt->style, NULL,
2625  "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2626  goto internal_err;
2627  }
2628  /*
2629  * Notify of change in status wrt namespaces.
2630  */
2631  if (cctxt->inode != NULL)
2632  cctxt->inode->nsChanged = 1;
2633 
2634  return(nsi);
2635 
2636 internal_err:
2637  if (list != NULL)
2638  xmlFree(list);
2639  cctxt->style->errors++;
2640  return(NULL);
2641 }
2642 
2643 static int
2644 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2645  xsltPointerListPtr list,
2646  xmlNodePtr node,
2647  const xmlChar *value)
2648 {
2649  xmlChar *cur, *end;
2650  xmlNsPtr ns;
2651 
2652  if ((cctxt == NULL) || (value == NULL) || (list == NULL))
2653  return(-1);
2654 
2655  list->number = 0;
2656 
2657  cur = (xmlChar *) value;
2658  while (*cur != 0) {
2659  while (IS_BLANK(*cur)) cur++;
2660  if (*cur == 0)
2661  break;
2662  end = cur;
2663  while ((*end != 0) && (!IS_BLANK(*end))) end++;
2664  cur = xmlStrndup(cur, end - cur);
2665  if (cur == NULL) {
2666  cur = end;
2667  continue;
2668  }
2669  /*
2670  * TODO: Export and use xmlSearchNsByPrefixStrict()
2671  * in Libxml2, tree.c, since xmlSearchNs() is in most
2672  * cases not efficient and in some cases not correct.
2673  *
2674  * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2675  */
2676  if ((cur[0] == '#') &&
2677  xmlStrEqual(cur, (const xmlChar *)"#default"))
2678  ns = xmlSearchNs(cctxt->style->doc, node, NULL);
2679  else
2680  ns = xmlSearchNs(cctxt->style->doc, node, cur);
2681 
2682  if (ns == NULL) {
2683  /*
2684  * TODO: Better to report the attr-node, otherwise
2685  * the user won't know which attribute was invalid.
2686  */
2687  xsltTransformError(NULL, cctxt->style, node,
2688  "No namespace binding in scope for prefix '%s'.\n", cur);
2689  /*
2690  * XSLT-1.0: "It is an error if there is no namespace
2691  * bound to the prefix on the element bearing the
2692  * exclude-result-prefixes or xsl:exclude-result-prefixes
2693  * attribute."
2694  */
2695  cctxt->style->errors++;
2696  } else {
2697 #ifdef WITH_XSLT_DEBUG_PARSING
2699  "resolved prefix '%s'\n", cur);
2700 #endif
2701  /*
2702  * Note that we put the namespace name into the dict.
2703  */
2704  if (xsltPointerListAddSize(list,
2705  (void *) xmlDictLookup(cctxt->style->dict,
2706  ns->href, -1), 5) == -1)
2707  {
2708  xmlFree(cur);
2709  goto internal_err;
2710  }
2711  }
2712  xmlFree(cur);
2713 
2714  cur = end;
2715  }
2716  return(0);
2717 
2718 internal_err:
2719  cctxt->style->errors++;
2720  return(-1);
2721 }
2722 
2734 static xsltPointerListPtr
2735 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
2736  xsltPointerListPtr second)
2737 {
2738  xsltPointerListPtr ret;
2739  size_t num;
2740 
2741  if (first)
2742  num = first->number;
2743  else
2744  num = 0;
2745  if (second)
2746  num += second->number;
2747  if (num == 0)
2748  return(NULL);
2749  ret = xsltPointerListCreate(num);
2750  if (ret == NULL)
2751  return(NULL);
2752  /*
2753  * Copy contents.
2754  */
2755  if ((first != NULL) && (first->number != 0)) {
2756  memcpy(ret->items, first->items,
2757  first->number * sizeof(void *));
2758  if ((second != NULL) && (second->number != 0))
2759  memcpy(ret->items + first->number, second->items,
2760  second->number * sizeof(void *));
2761  } else if ((second != NULL) && (second->number != 0))
2762  memcpy(ret->items, (void *) second->items,
2763  second->number * sizeof(void *));
2764  ret->number = num;
2765  return(ret);
2766 }
2767 
2768 /*
2769 * xsltParseExclResultPrefixes:
2770 *
2771 * Create and store the list of in-scope namespaces for the given
2772 * node in the stylesheet. If there are no changes in the in-scope
2773 * namespaces then the last ns-info of the ancestor axis will be returned.
2774 * Compilation-time only.
2775 *
2776 * Returns the ns-info or NULL if there are no namespaces in scope.
2777 */
2778 static xsltPointerListPtr
2779 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2780  xsltPointerListPtr def,
2781  int instrCategory)
2782 {
2783  xsltPointerListPtr list = NULL;
2784  xmlChar *value;
2785  xmlAttrPtr attr;
2786 
2787  if ((cctxt == NULL) || (node == NULL))
2788  return(NULL);
2789 
2790  if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2791  attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
2792  else
2793  attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
2794  XSLT_NAMESPACE);
2795  if (attr == NULL)
2796  return(def);
2797 
2798  if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2799  /*
2800  * Mark the XSLT attr.
2801  */
2802  attr->psvi = (void *) xsltXSLTAttrMarker;
2803  }
2804 
2805  if ((attr->children != NULL) &&
2806  (attr->children->content != NULL))
2807  value = attr->children->content;
2808  else {
2809  xsltTransformError(NULL, cctxt->style, node,
2810  "Attribute 'exclude-result-prefixes': Invalid value.\n");
2811  cctxt->style->errors++;
2812  return(def);
2813  }
2814 
2815  if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2816  BAD_CAST value) != 0)
2817  goto exit;
2818  if (cctxt->tmpList->number == 0)
2819  goto exit;
2820  /*
2821  * Merge the list with the inherited list.
2822  */
2823  list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2824  if (list == NULL)
2825  goto exit;
2826  /*
2827  * Store the list in the stylesheet/compiler context.
2828  */
2829  if (xsltPointerListAddSize(
2830  cctxt->psData->exclResultNamespaces, list, 5) == -1)
2831  {
2832  xsltPointerListFree(list);
2833  list = NULL;
2834  goto exit;
2835  }
2836  /*
2837  * Notify of change in status wrt namespaces.
2838  */
2839  if (cctxt->inode != NULL)
2840  cctxt->inode->nsChanged = 1;
2841 
2842 exit:
2843  if (list != NULL)
2844  return(list);
2845  else
2846  return(def);
2847 }
2848 
2849 /*
2850 * xsltParseExtElemPrefixes:
2851 *
2852 * Create and store the list of in-scope namespaces for the given
2853 * node in the stylesheet. If there are no changes in the in-scope
2854 * namespaces then the last ns-info of the ancestor axis will be returned.
2855 * Compilation-time only.
2856 *
2857 * Returns the ns-info or NULL if there are no namespaces in scope.
2858 */
2859 static xsltPointerListPtr
2860 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2861  xsltPointerListPtr def,
2862  int instrCategory)
2863 {
2864  xsltPointerListPtr list = NULL;
2865  xmlAttrPtr attr;
2866  xmlChar *value;
2867  int i;
2868 
2869  if ((cctxt == NULL) || (node == NULL))
2870  return(NULL);
2871 
2872  if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2873  attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
2874  else
2875  attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
2876  XSLT_NAMESPACE);
2877  if (attr == NULL)
2878  return(def);
2879 
2880  if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2881  /*
2882  * Mark the XSLT attr.
2883  */
2884  attr->psvi = (void *) xsltXSLTAttrMarker;
2885  }
2886 
2887  if ((attr->children != NULL) &&
2888  (attr->children->content != NULL))
2889  value = attr->children->content;
2890  else {
2891  xsltTransformError(NULL, cctxt->style, node,
2892  "Attribute 'extension-element-prefixes': Invalid value.\n");
2893  cctxt->style->errors++;
2894  return(def);
2895  }
2896 
2897 
2898  if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2899  BAD_CAST value) != 0)
2900  goto exit;
2901 
2902  if (cctxt->tmpList->number == 0)
2903  goto exit;
2904  /*
2905  * REVISIT: Register the extension namespaces.
2906  */
2907  for (i = 0; i < cctxt->tmpList->number; i++)
2908  xsltRegisterExtPrefix(cctxt->style, NULL,
2909  BAD_CAST cctxt->tmpList->items[i]);
2910  /*
2911  * Merge the list with the inherited list.
2912  */
2913  list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2914  if (list == NULL)
2915  goto exit;
2916  /*
2917  * Store the list in the stylesheet.
2918  */
2919  if (xsltPointerListAddSize(
2920  cctxt->psData->extElemNamespaces, list, 5) == -1)
2921  {
2922  xsltPointerListFree(list);
2923  list = NULL;
2924  goto exit;
2925  }
2926  /*
2927  * Notify of change in status wrt namespaces.
2928  */
2929  if (cctxt->inode != NULL)
2930  cctxt->inode->nsChanged = 1;
2931 
2932 exit:
2933  if (list != NULL)
2934  return(list);
2935  else
2936  return(def);
2937 }
2938 
2939 /*
2940 * xsltParseAttrXSLTVersion:
2941 *
2942 * @cctxt: the compilation context
2943 * @node: the element-node
2944 * @isXsltElem: whether this is an XSLT element
2945 *
2946 * Parses the attribute xsl:version.
2947 *
2948 * Returns 1 if there was such an attribute, 0 if not and
2949 * -1 if an internal or API error occured.
2950 */
2951 static int
2952 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2953  int instrCategory)
2954 {
2955  xmlChar *value;
2956  xmlAttrPtr attr;
2957 
2958  if ((cctxt == NULL) || (node == NULL))
2959  return(-1);
2960 
2961  if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2962  attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
2963  else
2964  attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
2965 
2966  if (attr == NULL)
2967  return(0);
2968 
2969  attr->psvi = (void *) xsltXSLTAttrMarker;
2970 
2971  if ((attr->children != NULL) &&
2972  (attr->children->content != NULL))
2973  value = attr->children->content;
2974  else {
2975  xsltTransformError(NULL, cctxt->style, node,
2976  "Attribute 'version': Invalid value.\n");
2977  cctxt->style->errors++;
2978  return(1);
2979  }
2980 
2981  if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
2982  cctxt->inode->forwardsCompat = 1;
2983  /*
2984  * TODO: To what extent do we support the
2985  * forwards-compatible mode?
2986  */
2987  /*
2988  * Report this only once per compilation episode.
2989  */
2990  if (! cctxt->hasForwardsCompat) {
2991  cctxt->hasForwardsCompat = 1;
2992  cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
2993  xsltTransformError(NULL, cctxt->style, node,
2994  "Warning: the attribute xsl:version specifies a value "
2995  "different from '1.0'. Switching to forwards-compatible "
2996  "mode. Only features of XSLT 1.0 are supported by this "
2997  "processor.\n");
2998  cctxt->style->warnings++;
2999  cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
3000  }
3001  } else {
3002  cctxt->inode->forwardsCompat = 0;
3003  }
3004 
3005  if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
3006  /*
3007  * Set a marker on XSLT attributes.
3008  */
3009  attr->psvi = (void *) xsltXSLTAttrMarker;
3010  }
3011  return(1);
3012 }
3013 
3014 static int
3015 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
3016 {
3017  xmlNodePtr deleteNode, cur, txt, textNode = NULL;
3018  xmlDocPtr doc;
3020  int internalize = 0, findSpaceAttr;
3021  int xsltStylesheetElemDepth;
3022  xmlAttrPtr attr;
3023  xmlChar *value;
3024  const xmlChar *name, *nsNameXSLT = NULL;
3025  int strictWhitespace, inXSLText = 0;
3026 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3027  xsltNsMapPtr nsMapItem;
3028 #endif
3029 
3030  if ((cctxt == NULL) || (cctxt->style == NULL) ||
3031  (node == NULL) || (node->type != XML_ELEMENT_NODE))
3032  return(-1);
3033 
3034  doc = node->doc;
3035  if (doc == NULL)
3036  goto internal_err;
3037 
3038  style = cctxt->style;
3039  if ((style->dict != NULL) && (doc->dict == style->dict))
3040  internalize = 1;
3041  else
3042  style->internalized = 0;
3043 
3044  /*
3045  * Init value of xml:space. Since this might be an embedded
3046  * stylesheet, this is needed to be performed on the element
3047  * where the stylesheet is rooted at, taking xml:space of
3048  * ancestors into account.
3049  */
3050  if (! cctxt->simplified)
3051  xsltStylesheetElemDepth = cctxt->depth +1;
3052  else
3053  xsltStylesheetElemDepth = 0;
3054 
3055  if (xmlNodeGetSpacePreserve(node) != 1)
3056  cctxt->inode->preserveWhitespace = 0;
3057  else
3058  cctxt->inode->preserveWhitespace = 1;
3059 
3060  /*
3061  * Eval if we should keep the old incorrect behaviour.
3062  */
3063  strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
3064 
3065  nsNameXSLT = xsltConstNamespaceNameXSLT;
3066 
3067  deleteNode = NULL;
3068  cur = node;
3069  while (cur != NULL) {
3070  if (deleteNode != NULL) {
3071 
3072 #ifdef WITH_XSLT_DEBUG_BLANKS
3074  "xsltParsePreprocessStylesheetTree: removing node\n");
3075 #endif
3076  xmlUnlinkNode(deleteNode);
3077  xmlFreeNode(deleteNode);
3078  deleteNode = NULL;
3079  }
3080  if (cur->type == XML_ELEMENT_NODE) {
3081 
3082  /*
3083  * Clear the PSVI field.
3084  */
3085  cur->psvi = NULL;
3086 
3087  xsltCompilerNodePush(cctxt, cur);
3088 
3089  inXSLText = 0;
3090  textNode = NULL;
3091  findSpaceAttr = 1;
3092  cctxt->inode->stripWhitespace = 0;
3093  /*
3094  * TODO: I'd love to use a string pointer comparison here :-/
3095  */
3096  if (IS_XSLT_ELEM(cur)) {
3097 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3098  if (cur->ns->href != nsNameXSLT) {
3099  nsMapItem = xsltNewNamespaceMapItem(cctxt,
3100  doc, cur->ns, cur);
3101  if (nsMapItem == NULL)
3102  goto internal_err;
3103  cur->ns->href = nsNameXSLT;
3104  }
3105 #endif
3106 
3107  if (cur->name == NULL)
3108  goto process_attributes;
3109  /*
3110  * Mark the XSLT element for later recognition.
3111  * TODO: Using the marker is still too dangerous, since if
3112  * the parsing mechanism leaves out an XSLT element, then
3113  * this might hit the transformation-mechanism, which
3114  * will break if it doesn't expect such a marker.
3115  */
3116  /* cur->psvi = (void *) xsltXSLTElemMarker; */
3117 
3118  /*
3119  * XSLT 2.0: "Any whitespace text node whose parent is
3120  * one of the following elements is removed from the "
3121  * tree, regardless of any xml:space attributes:..."
3122  * xsl:apply-imports,
3123  * xsl:apply-templates,
3124  * xsl:attribute-set,
3125  * xsl:call-template,
3126  * xsl:choose,
3127  * xsl:stylesheet, xsl:transform.
3128  * XSLT 2.0: xsl:analyze-string,
3129  * xsl:character-map,
3130  * xsl:next-match
3131  *
3132  * TODO: I'd love to use a string pointer comparison here :-/
3133  */
3134  name = cur->name;
3135  switch (*name) {
3136  case 't':
3137  if ((name[0] == 't') && (name[1] == 'e') &&
3138  (name[2] == 'x') && (name[3] == 't') &&
3139  (name[4] == 0))
3140  {
3141  /*
3142  * Process the xsl:text element.
3143  * ----------------------------
3144  * Mark it for later recognition.
3145  */
3146  cur->psvi = (void *) xsltXSLTTextMarker;
3147  /*
3148  * For stylesheets, the set of
3149  * whitespace-preserving element names
3150  * consists of just xsl:text.
3151  */
3152  findSpaceAttr = 0;
3153  cctxt->inode->preserveWhitespace = 1;
3154  inXSLText = 1;
3155  }
3156  break;
3157  case 'c':
3158  if (xmlStrEqual(name, BAD_CAST "choose") ||
3159  xmlStrEqual(name, BAD_CAST "call-template"))
3160  cctxt->inode->stripWhitespace = 1;
3161  break;
3162  case 'a':
3163  if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
3164  xmlStrEqual(name, BAD_CAST "apply-imports") ||
3165  xmlStrEqual(name, BAD_CAST "attribute-set"))
3166 
3167  cctxt->inode->stripWhitespace = 1;
3168  break;
3169  default:
3170  if (xsltStylesheetElemDepth == cctxt->depth) {
3171  /*
3172  * This is a xsl:stylesheet/xsl:transform.
3173  */
3174  cctxt->inode->stripWhitespace = 1;
3175  break;
3176  }
3177 
3178  if ((cur->prev != NULL) &&
3179  (cur->prev->type == XML_TEXT_NODE))
3180  {
3181  /*
3182  * XSLT 2.0 : "Any whitespace text node whose
3183  * following-sibling node is an xsl:param or
3184  * xsl:sort element is removed from the tree,
3185  * regardless of any xml:space attributes."
3186  */
3187  if (((*name == 'p') || (*name == 's')) &&
3188  (xmlStrEqual(name, BAD_CAST "param") ||
3189  xmlStrEqual(name, BAD_CAST "sort")))
3190  {
3191  do {
3192  if (IS_BLANK_NODE(cur->prev)) {
3193  txt = cur->prev;
3194  xmlUnlinkNode(txt);
3195  xmlFreeNode(txt);
3196  } else {
3197  /*
3198  * This will result in a content
3199  * error, when hitting the parsing
3200  * functions.
3201  */
3202  break;
3203  }
3204  } while (cur->prev);
3205  }
3206  }
3207  break;
3208  }
3209  }
3210 
3211 process_attributes:
3212  /*
3213  * Process attributes.
3214  * ------------------
3215  */
3216  if (cur->properties != NULL) {
3217  if (cur->children == NULL)
3218  findSpaceAttr = 0;
3219  attr = cur->properties;
3220  do {
3221 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3222  if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
3223  xmlStrEqual(attr->ns->href, nsNameXSLT))
3224  {
3225  nsMapItem = xsltNewNamespaceMapItem(cctxt,
3226  doc, attr->ns, cur);
3227  if (nsMapItem == NULL)
3228  goto internal_err;
3229  attr->ns->href = nsNameXSLT;
3230  }
3231 #endif
3232  if (internalize) {
3233  /*
3234  * Internalize the attribute's value; the goal is to
3235  * speed up operations and minimize used space by
3236  * compiled stylesheets.
3237  */
3238  txt = attr->children;
3239  /*
3240  * NOTE that this assumes only one
3241  * text-node in the attribute's content.
3242  */
3243  if ((txt != NULL) && (txt->content != NULL) &&
3244  (!xmlDictOwns(style->dict, txt->content)))
3245  {
3246  value = (xmlChar *) xmlDictLookup(style->dict,
3247  txt->content, -1);
3248  xmlNodeSetContent(txt, NULL);
3249  txt->content = value;
3250  }
3251  }
3252  /*
3253  * Process xml:space attributes.
3254  * ----------------------------
3255  */
3256  if ((findSpaceAttr != 0) &&
3257  (attr->ns != NULL) &&
3258  (attr->name != NULL) &&
3259  (attr->name[0] == 's') &&
3260  (attr->ns->prefix != NULL) &&
3261  (attr->ns->prefix[0] == 'x') &&
3262  (attr->ns->prefix[1] == 'm') &&
3263  (attr->ns->prefix[2] == 'l') &&
3264  (attr->ns->prefix[3] == 0))
3265  {
3266  value = xmlGetNsProp(cur, BAD_CAST "space",
3268  if (value != NULL) {
3269  if (xmlStrEqual(value, BAD_CAST "preserve")) {
3270  cctxt->inode->preserveWhitespace = 1;
3271  } else if (xmlStrEqual(value, BAD_CAST "default")) {
3272  cctxt->inode->preserveWhitespace = 0;
3273  } else {
3274  /* Invalid value for xml:space. */
3276  "Attribute xml:space: Invalid value.\n");
3277  cctxt->style->warnings++;
3278  }
3279  findSpaceAttr = 0;
3280  xmlFree(value);
3281  }
3282 
3283  }
3284  attr = attr->next;
3285  } while (attr != NULL);
3286  }
3287  /*
3288  * We'll descend into the children of element nodes only.
3289  */
3290  if (cur->children != NULL) {
3291  cur = cur->children;
3292  continue;
3293  }
3294  } else if ((cur->type == XML_TEXT_NODE) ||
3295  (cur->type == XML_CDATA_SECTION_NODE))
3296  {
3297  /*
3298  * Merge adjacent text/CDATA-section-nodes
3299  * ---------------------------------------
3300  * In order to avoid breaking of existing stylesheets,
3301  * if the old behaviour is wanted (strictWhitespace == 0),
3302  * then we *won't* merge adjacent text-nodes
3303  * (except in xsl:text); this will ensure that whitespace-only
3304  * text nodes are (incorrectly) not stripped in some cases.
3305  *
3306  * Example: : <foo> <!-- bar -->zoo</foo>
3307  * Corrent (strict) result: <foo> zoo</foo>
3308  * Incorrect (old) result : <foo>zoo</foo>
3309  *
3310  * NOTE that we *will* merge adjacent text-nodes if
3311  * they are in xsl:text.
3312  * Example, the following:
3313  * <xsl:text> <!-- bar -->zoo<xsl:text>
3314  * will result in both cases in:
3315  * <xsl:text> zoo<xsl:text>
3316  */
3317  cur->type = XML_TEXT_NODE;
3318  if ((strictWhitespace != 0) || (inXSLText != 0)) {
3319  /*
3320  * New behaviour; merge nodes.
3321  */
3322  if (textNode == NULL)
3323  textNode = cur;
3324  else {
3325  if (cur->content != NULL)
3326  xmlNodeAddContent(textNode, cur->content);
3327  deleteNode = cur;
3328  }
3329  if ((cur->next == NULL) ||
3330  (cur->next->type == XML_ELEMENT_NODE))
3331  goto end_of_text;
3332  else
3333  goto next_sibling;
3334  } else {
3335  /*
3336  * Old behaviour.
3337  */
3338  if (textNode == NULL)
3339  textNode = cur;
3340  goto end_of_text;
3341  }
3342  } else if ((cur->type == XML_COMMENT_NODE) ||
3343  (cur->type == XML_PI_NODE))
3344  {
3345  /*
3346  * Remove processing instructions and comments.
3347  */
3348  deleteNode = cur;
3349  if ((cur->next == NULL) ||
3350  (cur->next->type == XML_ELEMENT_NODE))
3351  goto end_of_text;
3352  else
3353  goto next_sibling;
3354  } else {
3355  textNode = NULL;
3356  /*
3357  * Invalid node-type for this data-model.
3358  */
3360  "Invalid type of node for the XSLT data model.\n");
3361  cctxt->style->errors++;
3362  goto next_sibling;
3363  }
3364 
3365 end_of_text:
3366  if (textNode) {
3367  value = textNode->content;
3368  /*
3369  * At this point all adjacent text/CDATA-section nodes
3370  * have been merged.
3371  *
3372  * Strip whitespace-only text-nodes.
3373  * (cctxt->inode->stripWhitespace)
3374  */
3375  if ((value == NULL) || (*value == 0) ||
3376  (((cctxt->inode->stripWhitespace) ||
3377  (! cctxt->inode->preserveWhitespace)) &&
3378  IS_BLANK(*value) &&
3379  xsltIsBlank(value)))
3380  {
3381  if (textNode != cur) {
3382  xmlUnlinkNode(textNode);
3383  xmlFreeNode(textNode);
3384  } else
3385  deleteNode = textNode;
3386  textNode = NULL;
3387  goto next_sibling;
3388  }
3389  /*
3390  * Convert CDATA-section nodes to text-nodes.
3391  * TODO: Can this produce problems?
3392  */
3393  if (textNode->type != XML_TEXT_NODE) {
3394  textNode->type = XML_TEXT_NODE;
3395  textNode->name = xmlStringText;
3396  }
3397  if (internalize &&
3398  (textNode->content != NULL) &&
3399  (!xmlDictOwns(style->dict, textNode->content)))
3400  {
3401  /*
3402  * Internalize the string.
3403  */
3404  value = (xmlChar *) xmlDictLookup(style->dict,
3405  textNode->content, -1);
3406  xmlNodeSetContent(textNode, NULL);
3407  textNode->content = value;
3408  }
3409  textNode = NULL;
3410  /*
3411  * Note that "disable-output-escaping" of the xsl:text
3412  * element will be applied at a later level, when
3413  * XSLT elements are processed.
3414  */
3415  }
3416 
3417 next_sibling:
3418  if (cur->type == XML_ELEMENT_NODE) {
3419  xsltCompilerNodePop(cctxt, cur);
3420  }
3421  if (cur == node)
3422  break;
3423  if (cur->next != NULL) {
3424  cur = cur->next;
3425  } else {
3426  cur = cur->parent;
3427  inXSLText = 0;
3428  goto next_sibling;
3429  };
3430  }
3431  if (deleteNode != NULL) {
3432 #ifdef WITH_XSLT_DEBUG_PARSING
3434  "xsltParsePreprocessStylesheetTree: removing node\n");
3435 #endif
3436  xmlUnlinkNode(deleteNode);
3437  xmlFreeNode(deleteNode);
3438  }
3439  return(0);
3440 
3441 internal_err:
3442  return(-1);
3443 }
3444 
3445 #endif /* XSLT_REFACTORED */
3446 
3447 #ifdef XSLT_REFACTORED
3448 #else
3449 static void
3451 {
3452  xmlNodePtr deleteNode, styleelem;
3453  int internalize = 0;
3454 
3455  if ((style == NULL) || (cur == NULL))
3456  return;
3457 
3458  if ((cur->doc != NULL) && (style->dict != NULL) &&
3459  (cur->doc->dict == style->dict))
3460  internalize = 1;
3461  else
3462  style->internalized = 0;
3463 
3464  if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3465  (IS_XSLT_NAME(cur, "stylesheet"))) {
3466  styleelem = cur;
3467  } else {
3468  styleelem = NULL;
3469  }
3470 
3471  /*
3472  * This content comes from the stylesheet
3473  * For stylesheets, the set of whitespace-preserving
3474  * element names consists of just xsl:text.
3475  */
3476  deleteNode = NULL;
3477  while (cur != NULL) {
3478  if (deleteNode != NULL) {
3479 #ifdef WITH_XSLT_DEBUG_BLANKS
3481  "xsltPreprocessStylesheet: removing ignorable blank node\n");
3482 #endif
3483  xmlUnlinkNode(deleteNode);
3484  xmlFreeNode(deleteNode);
3485  deleteNode = NULL;
3486  }
3487  if (cur->type == XML_ELEMENT_NODE) {
3488  int exclPrefixes;
3489  /*
3490  * Internalize attributes values.
3491  */
3492  if ((internalize) && (cur->properties != NULL)) {
3493  xmlAttrPtr attr = cur->properties;
3494  xmlNodePtr txt;
3495 
3496  while (attr != NULL) {
3497  txt = attr->children;
3498  if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3499  (txt->content != NULL) &&
3500  (!xmlDictOwns(style->dict, txt->content)))
3501  {
3502  xmlChar *tmp;
3503 
3504  /*
3505  * internalize the text string, goal is to speed
3506  * up operations and minimize used space by compiled
3507  * stylesheets.
3508  */
3509  tmp = (xmlChar *) xmlDictLookup(style->dict,
3510  txt->content, -1);
3511  if (tmp != txt->content) {
3512  xmlNodeSetContent(txt, NULL);
3513  txt->content = tmp;
3514  }
3515  }
3516  attr = attr->next;
3517  }
3518  }
3519  if (IS_XSLT_ELEM(cur)) {
3520  exclPrefixes = 0;
3521  if (IS_XSLT_NAME(cur, "text")) {
3522  for (;exclPrefixes > 0;exclPrefixes--)
3524  goto skip_children;
3525  }
3526  } else {
3527  exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3528  }
3529 
3530  if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3531  xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3532  xmlNodePtr root = NULL;
3533  int i, moved;
3534 
3535  root = xmlDocGetRootElement(cur->doc);
3536  if ((root != NULL) && (root != cur)) {
3537  while (ns != NULL) {
3538  moved = 0;
3539  next = ns->next;
3540  for (i = 0;i < style->exclPrefixNr;i++) {
3541  if ((ns->prefix != NULL) &&
3542  (xmlStrEqual(ns->href,
3543  style->exclPrefixTab[i]))) {
3544  /*
3545  * Move the namespace definition on the root
3546  * element to avoid duplicating it without
3547  * loosing it.
3548  */
3549  if (prev == NULL) {
3550  cur->nsDef = ns->next;
3551  } else {
3552  prev->next = ns->next;
3553  }
3554  ns->next = root->nsDef;
3555  root->nsDef = ns;
3556  moved = 1;
3557  break;
3558  }
3559  }
3560  if (moved == 0)
3561  prev = ns;
3562  ns = next;
3563  }
3564  }
3565  }
3566  /*
3567  * If we have prefixes locally, recurse and pop them up when
3568  * going back
3569  */
3570  if (exclPrefixes > 0) {
3572  for (;exclPrefixes > 0;exclPrefixes--)
3574  goto skip_children;
3575  }
3576  } else if (cur->type == XML_TEXT_NODE) {
3577  if (IS_BLANK_NODE(cur)) {
3578  if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
3579  deleteNode = cur;
3580  }
3581  } else if ((cur->content != NULL) && (internalize) &&
3582  (!xmlDictOwns(style->dict, cur->content))) {
3583  xmlChar *tmp;
3584 
3585  /*
3586  * internalize the text string, goal is to speed
3587  * up operations and minimize used space by compiled
3588  * stylesheets.
3589  */
3590  tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3591  xmlNodeSetContent(cur, NULL);
3592  cur->content = tmp;
3593  }
3594  } else if ((cur->type != XML_ELEMENT_NODE) &&
3595  (cur->type != XML_CDATA_SECTION_NODE)) {
3596  deleteNode = cur;
3597  goto skip_children;
3598  }
3599 
3600  /*
3601  * Skip to next node. In case of a namespaced element children of
3602  * the stylesheet and not in the XSLT namespace and not an extension
3603  * element, ignore its content.
3604  */
3605  if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3606  (styleelem != NULL) && (cur->parent == styleelem) &&
3607  (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3608  (!xsltCheckExtURI(style, cur->ns->href))) {
3609  goto skip_children;
3610  } else if (cur->children != NULL) {
3611  if ((cur->children->type != XML_ENTITY_DECL) &&
3612  (cur->children->type != XML_ENTITY_REF_NODE) &&
3613  (cur->children->type != XML_ENTITY_NODE)) {
3614  cur = cur->children;
3615  continue;
3616  }
3617  }
3618 
3619 skip_children:
3620  if (cur->next != NULL) {
3621  cur = cur->next;
3622  continue;
3623  }
3624  do {
3625 
3626  cur = cur->parent;
3627  if (cur == NULL)
3628  break;
3629  if (cur == (xmlNodePtr) style->doc) {
3630  cur = NULL;
3631  break;
3632  }
3633  if (cur->next != NULL) {
3634  cur = cur->next;
3635  break;
3636  }
3637  } while (cur != NULL);
3638  }
3639  if (deleteNode != NULL) {
3640 #ifdef WITH_XSLT_DEBUG_PARSING
3642  "xsltPreprocessStylesheet: removing ignorable blank node\n");
3643 #endif
3644  xmlUnlinkNode(deleteNode);
3645  xmlFreeNode(deleteNode);
3646  }
3647 }
3648 #endif /* end of else XSLT_REFACTORED */
3649 
3658 static void
3660  xmlNodePtr cur;
3661  const xmlChar *URI;
3662 
3663  if (style == NULL)
3664  return;
3665  /*
3666  * TODO: basically if the stylesheet uses the same prefix for different
3667  * patterns, well they may be in problem, hopefully they will get
3668  * a warning first.
3669  */
3670  /*
3671  * TODO: Eliminate the use of the hash for XPath expressions.
3672  * An expression should be evaluated in the context of the in-scope
3673  * namespaces; eliminate the restriction of an XML document to contain
3674  * no duplicate prefixes for different namespace names.
3675  *
3676  */
3677  cur = xmlDocGetRootElement(style->doc);
3678  while (cur != NULL) {
3679  if (cur->type == XML_ELEMENT_NODE) {
3680  xmlNsPtr ns = cur->nsDef;
3681  while (ns != NULL) {
3682  if (ns->prefix != NULL) {
3683  if (style->nsHash == NULL) {
3684  style->nsHash = xmlHashCreate(10);
3685  if (style->nsHash == NULL) {
3687  "xsltGatherNamespaces: failed to create hash table\n");
3688  style->errors++;
3689  return;
3690  }
3691  }
3692  URI = xmlHashLookup(style->nsHash, ns->prefix);
3693  if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3695  "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3696  style->warnings++;
3697  } else if (URI == NULL) {
3698  xmlHashUpdateEntry(style->nsHash, ns->prefix,
3699  (void *) ns->href, NULL);
3700 
3701 #ifdef WITH_XSLT_DEBUG_PARSING
3703  "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3704 #endif
3705  }
3706  }
3707  ns = ns->next;
3708  }
3709  }
3710 
3711  /*
3712  * Skip to next node
3713  */
3714  if (cur->children != NULL) {
3715  if (cur->children->type != XML_ENTITY_DECL) {
3716  cur = cur->children;
3717  continue;
3718  }
3719  }
3720  if (cur->next != NULL) {
3721  cur = cur->next;
3722  continue;
3723  }
3724 
3725  do {
3726  cur = cur->parent;
3727  if (cur == NULL)
3728  break;
3729  if (cur == (xmlNodePtr) style->doc) {
3730  cur = NULL;
3731  break;
3732  }
3733  if (cur->next != NULL) {
3734  cur = cur->next;
3735  break;
3736  }
3737  } while (cur != NULL);
3738  }
3739 }
3740 
3741 #ifdef XSLT_REFACTORED
3742 
3743 static xsltStyleType
3744 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3745  xmlNodePtr node)
3746 {
3747  if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3748  (node->name == NULL))
3749  return(0);
3750 
3751  if (node->name[0] == 'a') {
3752  if (IS_XSLT_NAME(node, "apply-templates"))
3753  return(XSLT_FUNC_APPLYTEMPLATES);
3754  else if (IS_XSLT_NAME(node, "attribute"))
3755  return(XSLT_FUNC_ATTRIBUTE);
3756  else if (IS_XSLT_NAME(node, "apply-imports"))
3757  return(XSLT_FUNC_APPLYIMPORTS);
3758  else if (IS_XSLT_NAME(node, "attribute-set"))
3759  return(0);
3760 
3761  } else if (node->name[0] == 'c') {
3762  if (IS_XSLT_NAME(node, "choose"))
3763  return(XSLT_FUNC_CHOOSE);
3764  else if (IS_XSLT_NAME(node, "copy"))
3765  return(XSLT_FUNC_COPY);
3766  else if (IS_XSLT_NAME(node, "copy-of"))
3767  return(XSLT_FUNC_COPYOF);
3768  else if (IS_XSLT_NAME(node, "call-template"))
3769  return(XSLT_FUNC_CALLTEMPLATE);
3770  else if (IS_XSLT_NAME(node, "comment"))
3771  return(XSLT_FUNC_COMMENT);
3772 
3773  } else if (node->name[0] == 'd') {
3774  if (IS_XSLT_NAME(node, "document"))
3775  return(XSLT_FUNC_DOCUMENT);
3776  else if (IS_XSLT_NAME(node, "decimal-format"))
3777  return(0);
3778 
3779  } else if (node->name[0] == 'e') {
3780  if (IS_XSLT_NAME(node, "element"))
3781  return(XSLT_FUNC_ELEMENT);
3782 
3783  } else if (node->name[0] == 'f') {
3784  if (IS_XSLT_NAME(node, "for-each"))
3785  return(XSLT_FUNC_FOREACH);
3786  else if (IS_XSLT_NAME(node, "fallback"))
3787  return(XSLT_FUNC_FALLBACK);
3788 
3789  } else if (*(node->name) == 'i') {
3790  if (IS_XSLT_NAME(node, "if"))
3791  return(XSLT_FUNC_IF);
3792  else if (IS_XSLT_NAME(node, "include"))
3793  return(0);
3794  else if (IS_XSLT_NAME(node, "import"))
3795  return(0);
3796 
3797  } else if (*(node->name) == 'k') {
3798  if (IS_XSLT_NAME(node, "key"))
3799  return(0);
3800 
3801  } else if (*(node->name) == 'm') {
3802  if (IS_XSLT_NAME(node, "message"))
3803  return(XSLT_FUNC_MESSAGE);
3804 
3805  } else if (*(node->name) == 'n') {
3806  if (IS_XSLT_NAME(node, "number"))
3807  return(XSLT_FUNC_NUMBER);
3808  else if (IS_XSLT_NAME(node, "namespace-alias"))
3809  return(0);
3810 
3811  } else if (*(node->name) == 'o') {
3812  if (IS_XSLT_NAME(node, "otherwise"))
3813  return(XSLT_FUNC_OTHERWISE);
3814  else if (IS_XSLT_NAME(node, "output"))
3815  return(0);
3816 
3817  } else if (*(node->name) == 'p') {
3818  if (IS_XSLT_NAME(node, "param"))
3819  return(XSLT_FUNC_PARAM);
3820  else if (IS_XSLT_NAME(node, "processing-instruction"))
3821  return(XSLT_FUNC_PI);
3822  else if (IS_XSLT_NAME(node, "preserve-space"))
3823  return(0);
3824 
3825  } else if (*(node->name) == 's') {
3826  if (IS_XSLT_NAME(node, "sort"))
3827  return(XSLT_FUNC_SORT);
3828  else if (IS_XSLT_NAME(node, "strip-space"))
3829  return(0);
3830  else if (IS_XSLT_NAME(node, "stylesheet"))
3831  return(0);
3832 
3833  } else if (node->name[0] == 't') {
3834  if (IS_XSLT_NAME(node, "text"))
3835  return(XSLT_FUNC_TEXT);
3836  else if (IS_XSLT_NAME(node, "template"))
3837  return(0);
3838  else if (IS_XSLT_NAME(node, "transform"))
3839  return(0);
3840 
3841  } else if (*(node->name) == 'v') {
3842  if (IS_XSLT_NAME(node, "value-of"))
3843  return(XSLT_FUNC_VALUEOF);
3844  else if (IS_XSLT_NAME(node, "variable"))
3845  return(XSLT_FUNC_VARIABLE);
3846 
3847  } else if (*(node->name) == 'w') {
3848  if (IS_XSLT_NAME(node, "when"))
3849  return(XSLT_FUNC_WHEN);
3850  if (IS_XSLT_NAME(node, "with-param"))
3851  return(XSLT_FUNC_WITHPARAM);
3852  }
3853  return(0);
3854 }
3855 
3867 int
3868 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
3869 {
3870  if ((cctxt == NULL) || (elem == NULL) ||
3871  (elem->type != XML_ELEMENT_NODE))
3872  return(-1);
3873 
3874  elem->psvi = NULL;
3875 
3876  if (! (IS_XSLT_ELEM_FAST(elem)))
3877  return(-1);
3878  /*
3879  * Detection of handled content of extension instructions.
3880  */
3881  if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
3882  cctxt->inode->extContentHandled = 1;
3883  }
3884 
3885  xsltCompilerNodePush(cctxt, elem);
3886  /*
3887  * URGENT TODO: Find a way to speed up this annoying redundant
3888  * textual node-name and namespace comparison.
3889  */
3890  if (cctxt->inode->prev->curChildType != 0)
3891  cctxt->inode->type = cctxt->inode->prev->curChildType;
3892  else
3893  cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
3894  /*
3895  * Update the in-scope namespaces if needed.
3896  */
3897  if (elem->nsDef != NULL)
3898  cctxt->inode->inScopeNs =
3899  xsltCompilerBuildInScopeNsList(cctxt, elem);
3900  /*
3901  * xsltStylePreCompute():
3902  * This will compile the information found on the current
3903  * element's attributes. NOTE that this won't process the
3904  * children of the instruction.
3905  */
3906  xsltStylePreCompute(cctxt->style, elem);
3907  /*
3908  * TODO: How to react on errors in xsltStylePreCompute() ?
3909  */
3910 
3911  /*
3912  * Validate the content model of the XSLT-element.
3913  */
3914  switch (cctxt->inode->type) {
3916  /* EMPTY */
3917  goto empty_content;
3919  /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3920  goto apply_templates;
3921  case XSLT_FUNC_ATTRIBUTE:
3922  /* <!-- Content: template --> */
3923  goto sequence_constructor;
3925  /* <!-- Content: xsl:with-param* --> */
3926  goto call_template;
3927  case XSLT_FUNC_CHOOSE:
3928  /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3929  goto choose;
3930  case XSLT_FUNC_COMMENT:
3931  /* <!-- Content: template --> */
3932  goto sequence_constructor;
3933  case XSLT_FUNC_COPY:
3934  /* <!-- Content: template --> */
3935  goto sequence_constructor;
3936  case XSLT_FUNC_COPYOF:
3937  /* EMPTY */
3938  goto empty_content;
3939  case XSLT_FUNC_DOCUMENT: /* Extra one */
3940  /* ?? template ?? */
3941  goto sequence_constructor;
3942  case XSLT_FUNC_ELEMENT:
3943  /* <!-- Content: template --> */
3944  goto sequence_constructor;
3945  case XSLT_FUNC_FALLBACK:
3946  /* <!-- Content: template --> */
3947  goto sequence_constructor;
3948  case XSLT_FUNC_FOREACH:
3949  /* <!-- Content: (xsl:sort*, template) --> */
3950  goto for_each;
3951  case XSLT_FUNC_IF:
3952  /* <!-- Content: template --> */
3953  goto sequence_constructor;
3954  case XSLT_FUNC_OTHERWISE:
3955  /* <!-- Content: template --> */
3956  goto sequence_constructor;
3957  case XSLT_FUNC_MESSAGE:
3958  /* <!-- Content: template --> */
3959  goto sequence_constructor;
3960  case XSLT_FUNC_NUMBER:
3961  /* EMPTY */
3962  goto empty_content;
3963  case XSLT_FUNC_PARAM:
3964  /*
3965  * Check for redefinition.
3966  */
3967  if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3968  xsltVarInfoPtr ivar = cctxt->ivar;
3969 
3970  do {
3971  if ((ivar->name ==
3972  ((xsltStyleItemParamPtr) elem->psvi)->name) &&
3973  (ivar->nsName ==
3974  ((xsltStyleItemParamPtr) elem->psvi)->ns))
3975  {
3976  elem->psvi = NULL;
3977  xsltTransformError(NULL, cctxt->style, elem,
3978  "Redefinition of variable or parameter '%s'.\n",
3979  ivar->name);
3980  cctxt->style->errors++;
3981  goto error;
3982  }
3983  ivar = ivar->prev;
3984  } while (ivar != NULL);
3985  }
3986  /* <!-- Content: template --> */
3987  goto sequence_constructor;
3988  case XSLT_FUNC_PI:
3989  /* <!-- Content: template --> */
3990  goto sequence_constructor;
3991  case XSLT_FUNC_SORT:
3992  /* EMPTY */
3993  goto empty_content;
3994  case XSLT_FUNC_TEXT:
3995  /* <!-- Content: #PCDATA --> */
3996  goto text;
3997  case XSLT_FUNC_VALUEOF:
3998  /* EMPTY */
3999  goto empty_content;
4000  case XSLT_FUNC_VARIABLE:
4001  /*
4002  * Check for redefinition.
4003  */
4004  if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
4005  xsltVarInfoPtr ivar = cctxt->ivar;
4006 
4007  do {
4008  if ((ivar->name ==
4009  ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
4010  (ivar->nsName ==
4011  ((xsltStyleItemVariablePtr) elem->psvi)->ns))
4012  {
4013  elem->psvi = NULL;
4014  xsltTransformError(NULL, cctxt->style, elem,
4015  "Redefinition of variable or parameter '%s'.\n",
4016  ivar->name);
4017  cctxt->style->errors++;
4018  goto error;
4019  }
4020  ivar = ivar->prev;
4021  } while (ivar != NULL);
4022  }
4023  /* <!-- Content: template --> */
4024  goto sequence_constructor;
4025  case XSLT_FUNC_WHEN:
4026  /* <!-- Content: template --> */
4027  goto sequence_constructor;
4028  case XSLT_FUNC_WITHPARAM:
4029  /* <!-- Content: template --> */
4030  goto sequence_constructor;
4031  default:
4032 #ifdef WITH_XSLT_DEBUG_PARSING
4034  "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4035  elem->name);
4036 #endif
4037  xsltTransformError(NULL, cctxt->style, elem,
4038  "xsltParseXSLTNode: Internal error; "
4039  "unhandled XSLT element '%s'.\n", elem->name);
4040  cctxt->style->errors++;
4041  goto internal_err;
4042  }
4043 
4044 apply_templates:
4045  /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4046  if (elem->children != NULL) {
4047  xmlNodePtr child = elem->children;
4048  do {
4049  if (child->type == XML_ELEMENT_NODE) {
4050  if (IS_XSLT_ELEM_FAST(child)) {
4051  if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
4052  cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4053  xsltParseAnyXSLTElem(cctxt, child);
4054  } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
4055  cctxt->inode->curChildType = XSLT_FUNC_SORT;
4056  xsltParseAnyXSLTElem(cctxt, child);
4057  } else
4058  xsltParseContentError(cctxt->style, child);
4059  } else
4060  xsltParseContentError(cctxt->style, child);
4061  }
4062  child = child->next;
4063  } while (child != NULL);
4064  }
4065  goto exit;
4066 
4067 call_template:
4068  /* <!-- Content: xsl:with-param* --> */
4069  if (elem->children != NULL) {
4070  xmlNodePtr child = elem->children;
4071  do {
4072  if (child->type == XML_ELEMENT_NODE) {
4073  if (IS_XSLT_ELEM_FAST(child)) {
4075 
4076  type = xsltGetXSLTElementTypeByNode(cctxt, child);
4077  if (type == XSLT_FUNC_WITHPARAM) {
4078  cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4079  xsltParseAnyXSLTElem(cctxt, child);
4080  } else {
4081  xsltParseContentError(cctxt->style, child);
4082  }
4083  } else
4084  xsltParseContentError(cctxt->style, child);
4085  }
4086  child = child->next;
4087  } while (child != NULL);
4088  }
4089  goto exit;
4090 
4091 text:
4092  if (elem->children != NULL) {
4093  xmlNodePtr child = elem->children;
4094  do {
4095  if ((child->type != XML_TEXT_NODE) &&
4096  (child->type != XML_CDATA_SECTION_NODE))
4097  {
4098  xsltTransformError(NULL, cctxt->style, elem,
4099  "The XSLT 'text' element must have only character "
4100  "data as content.\n");
4101  }
4102  child = child->next;
4103  } while (child != NULL);
4104  }
4105  goto exit;
4106 
4107 empty_content:
4108  if (elem->children != NULL) {
4109  xmlNodePtr child = elem->children;
4110  /*
4111  * Relaxed behaviour: we will allow whitespace-only text-nodes.
4112  */
4113  do {
4114  if (((child->type != XML_TEXT_NODE) &&
4115  (child->type != XML_CDATA_SECTION_NODE)) ||
4116  (! IS_BLANK_NODE(child)))
4117  {
4118  xsltTransformError(NULL, cctxt->style, elem,
4119  "This XSLT element must have no content.\n");
4120  cctxt->style->errors++;
4121  break;
4122  }
4123  child = child->next;
4124  } while (child != NULL);
4125  }
4126  goto exit;
4127 
4128 choose:
4129  /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4130  /*
4131  * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4132  * The old behaviour did not check this.
4133  * NOTE: In XSLT 2.0 they are stripped beforehand
4134  * if whitespace-only (regardless of xml:space).
4135  */
4136  if (elem->children != NULL) {
4137  xmlNodePtr child = elem->children;
4138  int nbWhen = 0, nbOtherwise = 0, err = 0;
4139  do {
4140  if (child->type == XML_ELEMENT_NODE) {
4141  if (IS_XSLT_ELEM_FAST(child)) {
4143 
4144  type = xsltGetXSLTElementTypeByNode(cctxt, child);
4145  if (type == XSLT_FUNC_WHEN) {
4146  nbWhen++;
4147  if (nbOtherwise) {
4148  xsltParseContentError(cctxt->style, child);
4149  err = 1;
4150  break;
4151  }
4152  cctxt->inode->curChildType = XSLT_FUNC_WHEN;
4153  xsltParseAnyXSLTElem(cctxt, child);
4154  } else if (type == XSLT_FUNC_OTHERWISE) {
4155  if (! nbWhen) {
4156  xsltParseContentError(cctxt->style, child);
4157  err = 1;
4158  break;
4159  }
4160  if (nbOtherwise) {
4161  xsltTransformError(NULL, cctxt->style, elem,
4162  "The XSLT 'choose' element must not contain "
4163  "more than one XSLT 'otherwise' element.\n");
4164  cctxt->style->errors++;
4165  err = 1;
4166  break;
4167  }
4168  nbOtherwise++;
4169  cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
4170  xsltParseAnyXSLTElem(cctxt, child);
4171  } else
4172  xsltParseContentError(cctxt->style, child);
4173  } else
4174  xsltParseContentError(cctxt->style, child);
4175  }
4176  /*
4177  else
4178  xsltParseContentError(cctxt, child);
4179  */
4180  child = child->next;
4181  } while (child != NULL);
4182  if ((! err) && (! nbWhen)) {
4183  xsltTransformError(NULL, cctxt->style, elem,
4184  "The XSLT element 'choose' must contain at least one "
4185  "XSLT element 'when'.\n");
4186  cctxt->style->errors++;
4187  }
4188  }
4189  goto exit;
4190 
4191 for_each:
4192  /* <!-- Content: (xsl:sort*, template) --> */
4193  /*
4194  * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4195  * The old behaviour did not allow this, but it catched this
4196  * only at transformation-time.
4197  * In XSLT 2.0 they are stripped beforehand if whitespace-only
4198  * (regardless of xml:space).
4199  */
4200  if (elem->children != NULL) {
4201  xmlNodePtr child = elem->children;
4202  /*
4203  * Parse xsl:sort first.
4204  */
4205  do {
4206  if ((child->type == XML_ELEMENT_NODE) &&
4207  IS_XSLT_ELEM_FAST(child))
4208  {
4209  if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
4211  {
4212  cctxt->inode->curChildType = XSLT_FUNC_SORT;
4213  xsltParseAnyXSLTElem(cctxt, child);
4214  } else
4215  break;
4216  } else
4217  break;
4218  child = child->next;
4219  } while (child != NULL);
4220  /*
4221  * Parse the sequece constructor.
4222  */
4223  if (child != NULL)
4224  xsltParseSequenceConstructor(cctxt, child);
4225  }
4226  goto exit;
4227 
4228 sequence_constructor:
4229  /*
4230  * Parse the sequence constructor.
4231  */
4232  if (elem->children != NULL)
4233  xsltParseSequenceConstructor(cctxt, elem->children);
4234 
4235  /*
4236  * Register information for vars/params. Only needed if there
4237  * are any following siblings.
4238  */
4239  if ((elem->next != NULL) &&
4240  ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
4241  (cctxt->inode->type == XSLT_FUNC_PARAM)))
4242  {
4243  if ((elem->psvi != NULL) &&
4244  (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
4245  {
4246  xsltCompilerVarInfoPush(cctxt, elem,
4247  ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
4248  ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
4249  }
4250  }
4251 
4252 error:
4253 exit:
4254  xsltCompilerNodePop(cctxt, elem);
4255  return(0);
4256 
4257 internal_err:
4258  xsltCompilerNodePop(cctxt, elem);
4259  return(-1);
4260 }
4261 
4272 static xsltStyleItemUknownPtr
4273 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
4274 {
4275  xsltStyleItemUknownPtr item;
4276 
4277  item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
4278  if (item == NULL) {
4279  xsltTransformError(NULL, cctxt->style, NULL,
4280  "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4281  "Failed to allocate memory.\n");
4282  cctxt->style->errors++;
4283  return(NULL);
4284  }
4285  memset(item, 0, sizeof(xsltStyleItemUknown));
4286  item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
4287  /*
4288  * Store it in the stylesheet.
4289  */
4290  item->next = cctxt->style->preComps;
4291  cctxt->style->preComps = (xsltElemPreCompPtr) item;
4292  return(item);
4293 }
4294 
4309 static int
4310 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
4311  xmlNodePtr node)
4312 {
4313  if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
4314  return(-1);
4315 
4316  /*
4317  * Detection of handled content of extension instructions.
4318  */
4319  if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4320  cctxt->inode->extContentHandled = 1;
4321  }
4322  if (cctxt->inode->forwardsCompat == 0) {
4323  /*
4324  * We are not in forwards-compatible mode, so raise an error.
4325  */
4326  xsltTransformError(NULL, cctxt->style, node,
4327  "Unknown XSLT element '%s'.\n", node->name);
4328  cctxt->style->errors++;
4329  return(1);
4330  }
4331  /*
4332  * Forwards-compatible mode.
4333  * ------------------------
4334  *
4335  * Parse/compile xsl:fallback elements.
4336  *
4337  * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4338  * ANSWER: No, since in the stylesheet the fallback behaviour might
4339  * also be provided by using the XSLT function "element-available".
4340  */
4341  if (cctxt->unknownItem == NULL) {
4342  /*
4343  * Create a singleton for all unknown XSLT instructions.
4344  */
4345  cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
4346  if (cctxt->unknownItem == NULL) {
4347  node->psvi = NULL;
4348  return(-1);
4349  }
4350  }
4351  node->psvi = cctxt->unknownItem;
4352  if (node->children == NULL)
4353  return(0);
4354  else {
4355  xmlNodePtr child = node->children;
4356 
4357  xsltCompilerNodePush(cctxt, node);
4358  /*
4359  * Update the in-scope namespaces if needed.
4360  */
4361  if (node->nsDef != NULL)
4362  cctxt->inode->inScopeNs =
4363  xsltCompilerBuildInScopeNsList(cctxt, node);
4364  /*
4365  * Parse all xsl:fallback children.
4366  */
4367  do {
4368  if ((child->type == XML_ELEMENT_NODE) &&
4369  IS_XSLT_ELEM_FAST(child) &&
4370  IS_XSLT_NAME(child, "fallback"))
4371  {
4372  cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
4373  xsltParseAnyXSLTElem(cctxt, child);
4374  }
4375  child = child->next;
4376  } while (child != NULL);
4377 
4378  xsltCompilerNodePop(cctxt, node);
4379  }
4380  return(0);
4381 }
4382 
4392 void
4393 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
4394 {
4396  xmlNodePtr deleteNode = NULL;
4397 
4398  if (cctxt == NULL) {
4400  "xsltParseSequenceConstructor: Bad arguments\n");
4401  cctxt->style->errors++;
4402  return;
4403  }
4404  /*
4405  * Detection of handled content of extension instructions.
4406  */
4407  if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4408  cctxt->inode->extContentHandled = 1;
4409  }
4410  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
4411  return;
4412  /*
4413  * This is the content reffered to as a "template".
4414  * E.g. an xsl:element has such content model:
4415  * <xsl:element
4416  * name = { qname }
4417  * namespace = { uri-reference }
4418  * use-attribute-sets = qnames>
4419  * <!-- Content: template -->
4420  *
4421  * NOTE that in XSLT-2 the term "template" was abandoned due to
4422  * confusion with xsl:template and the term "sequence constructor"
4423  * was introduced instead.
4424  *
4425  * The following XSLT-instructions are allowed to appear:
4426  * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4427  * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4428  * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4429  * xsl:message, xsl:fallback,
4430  * xsl:processing-instruction, xsl:comment, xsl:element
4431  * xsl:attribute.
4432  * Additional allowed content:
4433  * 1) extension instructions
4434  * 2) literal result elements
4435  * 3) PCDATA
4436  *
4437  * NOTE that this content model does *not* allow xsl:param.
4438  */
4439  while (cur != NULL) {
4440  if (deleteNode != NULL) {
4441 #ifdef WITH_XSLT_DEBUG_BLANKS
4443  "xsltParseSequenceConstructor: removing xsl:text element\n");
4444 #endif
4445  xmlUnlinkNode(deleteNode);
4446  xmlFreeNode(deleteNode);
4447  deleteNode = NULL;
4448  }
4449  if (cur->type == XML_ELEMENT_NODE) {
4450 
4451  if (cur->psvi == xsltXSLTTextMarker) {
4452  /*
4453  * xsl:text elements
4454  * --------------------------------------------------------
4455  */
4456  xmlNodePtr tmp;
4457 
4458  cur->psvi = NULL;
4459  /*
4460  * Mark the xsl:text element for later deletion.
4461  */
4462  deleteNode = cur;
4463  /*
4464  * Validate content.
4465  */
4466  tmp = cur->children;
4467  if (tmp) {
4468  /*
4469  * We don't expect more than one text-node in the
4470  * content, since we already merged adjacent
4471  * text/CDATA-nodes and eliminated PI/comment-nodes.
4472  */
4473  if ((tmp->type == XML_TEXT_NODE) ||
4474  (tmp->next == NULL))
4475  {
4476  /*
4477  * Leave the contained text-node in the tree.
4478  */
4479  xmlUnlinkNode(tmp);
4480  xmlAddPrevSibling(cur, tmp);
4481  } else {
4482  tmp = NULL;
4483  xsltTransformError(NULL, cctxt->style, cur,
4484  "Element 'xsl:text': Invalid type "
4485  "of node found in content.\n");
4486  cctxt->style->errors++;
4487  }
4488  }
4489  if (cur->properties) {
4490  xmlAttrPtr attr;
4491  /*
4492  * TODO: We need to report errors for
4493  * invalid attrs.
4494  */
4495  attr = cur->properties;
4496  do {
4497  if ((attr->ns == NULL) &&
4498  (attr->name != NULL) &&
4499  (attr->name[0] == 'd') &&
4501  BAD_CAST "disable-output-escaping"))
4502  {
4503  /*
4504  * Attr "disable-output-escaping".
4505  * XSLT-2: This attribute is deprecated.
4506  */
4507  if ((attr->children != NULL) &&
4508  xmlStrEqual(attr->children->content,
4509  BAD_CAST "yes"))
4510  {
4511  /*
4512  * Disable output escaping for this
4513  * text node.
4514  */
4515  if (tmp)
4516  tmp->name = xmlStringTextNoenc;
4517  } else if ((attr->children == NULL) ||
4518  (attr->children->content == NULL) ||
4519  (!xmlStrEqual(attr->children->content,
4520  BAD_CAST "no")))
4521  {
4522  xsltTransformError(NULL, cctxt->style,
4523  cur,
4524  "Attribute 'disable-output-escaping': "
4525  "Invalid value. Expected is "
4526  "'yes' or 'no'.\n");
4527  cctxt->style->errors++;
4528  }
4529  break;
4530  }
4531  attr = attr->next;
4532  } while (attr != NULL);
4533  }
4534  } else if (IS_XSLT_ELEM_FAST(cur)) {
4535  /*
4536  * TODO: Using the XSLT-marker is still not stable yet.
4537  */
4538  /* if (cur->psvi == xsltXSLTElemMarker) { */
4539  /*
4540  * XSLT instructions
4541  * --------------------------------------------------------
4542  */
4543  cur->psvi = NULL;
4544  type = xsltGetXSLTElementTypeByNode(cctxt, cur);
4545  switch (type) {
4548  case XSLT_FUNC_ATTRIBUTE:
4550  case XSLT_FUNC_CHOOSE:
4551  case XSLT_FUNC_COMMENT:
4552  case XSLT_FUNC_COPY:
4553  case XSLT_FUNC_COPYOF:
4554  case XSLT_FUNC_DOCUMENT: /* Extra one */
4555  case XSLT_FUNC_ELEMENT:
4556  case XSLT_FUNC_FALLBACK:
4557  case XSLT_FUNC_FOREACH:
4558  case XSLT_FUNC_IF:
4559  case XSLT_FUNC_MESSAGE:
4560  case XSLT_FUNC_NUMBER:
4561  case XSLT_FUNC_PI:
4562  case XSLT_FUNC_TEXT:
4563  case XSLT_FUNC_VALUEOF:
4564  case XSLT_FUNC_VARIABLE:
4565  /*
4566  * Parse the XSLT element.
4567  */
4568  cctxt->inode->curChildType = type;
4569  xsltParseAnyXSLTElem(cctxt, cur);
4570  break;
4571  default:
4572  xsltParseUnknownXSLTElem(cctxt, cur);
4573  cur = cur->next;
4574  continue;
4575  }
4576  } else {
4577  /*
4578  * Non-XSLT elements
4579  * -----------------
4580  */
4581  xsltCompilerNodePush(cctxt, cur);
4582  /*
4583  * Update the in-scope namespaces if needed.
4584  */
4585  if (cur->nsDef != NULL)
4586  cctxt->inode->inScopeNs =
4587  xsltCompilerBuildInScopeNsList(cctxt, cur);
4588  /*
4589  * The current element is either a literal result element
4590  * or an extension instruction.
4591  *
4592  * Process attr "xsl:extension-element-prefixes".
4593  * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4594  * processed by the implementor of the extension function;
4595  * i.e., it won't be handled by the XSLT processor.
4596  */
4597  /* SPEC 1.0:
4598  * "exclude-result-prefixes" is only allowed on literal
4599  * result elements and "xsl:exclude-result-prefixes"
4600  * on xsl:stylesheet/xsl:transform.
4601  * SPEC 2.0:
4602  * "There are a number of standard attributes
4603  * that may appear on any XSLT element: specifically
4604  * version, exclude-result-prefixes,
4605  * extension-element-prefixes, xpath-default-namespace,
4606  * default-collation, and use-when."
4607  *
4608  * SPEC 2.0:
4609  * For literal result elements:
4610  * "xsl:version, xsl:exclude-result-prefixes,
4611  * xsl:extension-element-prefixes,
4612  * xsl:xpath-default-namespace,
4613  * xsl:default-collation, or xsl:use-when."
4614  */
4615  if (cur->properties)
4616  cctxt->inode->extElemNs =
4617  xsltParseExtElemPrefixes(cctxt,
4618  cur, cctxt->inode->extElemNs,
4619  XSLT_ELEMENT_CATEGORY_LRE);
4620  /*
4621  * Eval if we have an extension instruction here.
4622  */
4623  if ((cur->ns != NULL) &&
4624  (cctxt->inode->extElemNs != NULL) &&
4625  (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
4626  {
4627  /*
4628  * Extension instructions
4629  * ----------------------------------------------------
4630  * Mark the node information.
4631  */
4632  cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
4633  cctxt->inode->extContentHandled = 0;
4634  if (cur->psvi != NULL) {
4635  cur->psvi = NULL;
4636  /*
4637  * TODO: Temporary sanity check.
4638  */
4639  xsltTransformError(NULL, cctxt->style, cur,
4640  "Internal error in xsltParseSequenceConstructor(): "
4641  "Occupied PSVI field.\n");
4642  cctxt->style->errors++;
4643  cur = cur->next;
4644  continue;
4645  }
4646  cur->psvi = (void *)
4647  xsltPreComputeExtModuleElement(cctxt->style, cur);
4648 
4649  if (cur->psvi == NULL) {
4650  /*
4651  * OLD COMMENT: "Unknown element, maybe registered
4652  * at the context level. Mark it for later
4653  * recognition."
4654  * QUESTION: What does the xsltExtMarker mean?
4655  * ANSWER: It is used in
4656  * xsltApplySequenceConstructor() at
4657  * transformation-time to look out for extension
4658  * registered in the transformation context.
4659  */
4660  cur->psvi = (void *) xsltExtMarker;
4661  }
4662  /*
4663  * BIG NOTE: Now the ugly part. In previous versions
4664  * of Libxslt (until 1.1.16), all the content of an
4665  * extension instruction was processed and compiled without
4666  * the need of the extension-author to explicitely call
4667  * such a processing;.We now need to mimic this old
4668  * behaviour in order to avoid breaking old code
4669  * on the extension-author's side.
4670  * The mechanism:
4671  * 1) If the author does *not* set the
4672  * compile-time-flag @extContentHandled, then we'll
4673  * parse the content assuming that it's a "template"
4674  * (or "sequence constructor in XSLT 2.0 terms).
4675  * NOTE: If the extension is registered at
4676  * transformation-time only, then there's no way of
4677  * knowing that content shall be valid, and we'll
4678  * process the content the same way.
4679  * 2) If the author *does* set the flag, then we'll assume
4680  * that the author has handled the parsing him/herself
4681  * (e.g. called xsltParseSequenceConstructor(), etc.
4682  * explicitely in his/her code).
4683  */
4684  if ((cur->children != NULL) &&
4685  (cctxt->inode->extContentHandled == 0))
4686  {
4687  /*
4688  * Default parsing of the content using the
4689  * sequence-constructor model.
4690  */
4691  xsltParseSequenceConstructor(cctxt, cur->children);
4692  }
4693  } else {
4694  /*
4695  * Literal result element
4696  * ----------------------------------------------------
4697  * Allowed XSLT attributes:
4698  * xsl:extension-element-prefixes CDATA #IMPLIED
4699  * xsl:exclude-result-prefixes CDATA #IMPLIED
4700  * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4701  * xsl:version NMTOKEN #IMPLIED
4702  */
4703  cur->psvi = NULL;
4704  cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
4705  if (cur->properties != NULL) {
4706  xmlAttrPtr attr = cur->properties;
4707  /*
4708  * Attribute "xsl:exclude-result-prefixes".
4709  */
4710  cctxt->inode->exclResultNs =
4711  xsltParseExclResultPrefixes(cctxt, cur,
4712  cctxt->inode->exclResultNs,
4713  XSLT_ELEMENT_CATEGORY_LRE);
4714  /*
4715  * Attribute "xsl:version".
4716  */
4717  xsltParseAttrXSLTVersion(cctxt, cur,
4718  XSLT_ELEMENT_CATEGORY_LRE);
4719  /*
4720  * Report invalid XSLT attributes.
4721  * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4722  * next to xsl:version, xsl:exclude-result-prefixes and
4723  * xsl:extension-element-prefixes.
4724  *
4725  * Mark all XSLT attributes, in order to skip such
4726  * attributes when instantiating the LRE.
4727  */
4728  do {
4729  if ((attr->psvi != xsltXSLTAttrMarker) &&
4730  IS_XSLT_ATTR_FAST(attr))
4731  {
4732  if (! xmlStrEqual(attr->name,
4733  BAD_CAST "use-attribute-sets"))
4734  {
4735  xsltTransformError(NULL, cctxt->style,
4736  cur,
4737  "Unknown XSLT attribute '%s'.\n",
4738  attr->name);
4739  cctxt->style->errors++;
4740  } else {
4741  /*
4742  * XSLT attr marker.
4743  */
4744  attr->psvi = (void *) xsltXSLTAttrMarker;
4745  }
4746  }
4747  attr = attr->next;
4748  } while (attr != NULL);
4749  }
4750  /*
4751  * Create/reuse info for the literal result element.
4752  */
4753  if (cctxt->inode->nsChanged)
4754  xsltLREInfoCreate(cctxt, cur, 1);
4755  cur->psvi = cctxt->inode->litResElemInfo;
4756  /*
4757  * Apply ns-aliasing on the element and on its attributes.
4758  */
4759  if (cctxt->hasNsAliases)
4760  xsltLREBuildEffectiveNs(cctxt, cur);
4761  /*
4762  * Compile attribute value templates (AVT).
4763  */
4764  if (cur->properties) {
4765  xmlAttrPtr attr = cur->properties;
4766 
4767  while (attr != NULL) {
4768  xsltCompileAttr(cctxt->style, attr);
4769  attr = attr->next;
4770  }
4771  }
4772  /*
4773  * Parse the content, which is defined to be a "template"
4774  * (or "sequence constructor" in XSLT 2.0 terms).
4775  */
4776  if (cur->children != NULL) {
4777  xsltParseSequenceConstructor(cctxt, cur->children);
4778  }
4779  }
4780  /*
4781  * Leave the non-XSLT element.
4782  */
4783  xsltCompilerNodePop(cctxt, cur);
4784  }
4785  }
4786  cur = cur->next;
4787  }
4788  if (deleteNode != NULL) {
4789 #ifdef WITH_XSLT_DEBUG_BLANKS
4791  "xsltParseSequenceConstructor: removing xsl:text element\n");
4792 #endif
4793  xmlUnlinkNode(deleteNode);
4794  xmlFreeNode(deleteNode);
4795  deleteNode = NULL;
4796  }
4797 }
4798 
4813 void
4815  if ((style == NULL) || (templ == NULL) ||
4816  (templ->type == XML_NAMESPACE_DECL))
4817  return;
4818 
4819  /*
4820  * Detection of handled content of extension instructions.
4821  */
4822  if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4823  XSLT_CCTXT(style)->inode->extContentHandled = 1;
4824  }
4825 
4826  if (templ->children != NULL) {
4827  xmlNodePtr child = templ->children;
4828  /*
4829  * Process xsl:param elements, which can only occur as the
4830  * immediate children of xsl:template (well, and of any
4831  * user-defined extension instruction if needed).
4832  */
4833  do {
4834  if ((child->type == XML_ELEMENT_NODE) &&
4835  IS_XSLT_ELEM_FAST(child) &&
4836  IS_XSLT_NAME(child, "param"))
4837  {
4838  XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
4839  xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
4840  } else
4841  break;
4842  child = child->next;
4843  } while (child != NULL);
4844  /*
4845  * Parse the content and register the pattern.
4846  */
4847  xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
4848  }
4849 }
4850 
4851 #else /* XSLT_REFACTORED */
4852 
4862 void
4864  xmlNodePtr cur, delete;
4865 
4866  if ((style == NULL) || (templ == NULL) ||
4867  (templ->type == XML_NAMESPACE_DECL)) return;
4868 
4869  /*
4870  * This content comes from the stylesheet
4871  * For stylesheets, the set of whitespace-preserving
4872  * element names consists of just xsl:text.
4873  */
4874  cur = templ->children;
4875  delete = NULL;
4876  while (cur != NULL) {
4877  if (delete != NULL) {
4878 #ifdef WITH_XSLT_DEBUG_BLANKS
4880  "xsltParseTemplateContent: removing text\n");
4881 #endif
4882  xmlUnlinkNode(delete);
4883  xmlFreeNode(delete);
4884  delete = NULL;
4885  }
4886  if (IS_XSLT_ELEM(cur)) {
4887  xsltStylePreCompute(style, cur);
4888 
4889  if (IS_XSLT_NAME(cur, "text")) {
4890  /*
4891  * TODO: Processing of xsl:text should be moved to
4892  * xsltPreprocessStylesheet(), since otherwise this
4893  * will be performed for every multiply included
4894  * stylesheet; i.e. this here is not skipped with
4895  * the use of the style->nopreproc flag.
4896  */
4897  if (cur->children != NULL) {
4898  xmlChar *prop;
4899  xmlNodePtr text = cur->children, next;
4900  int noesc = 0;
4901 
4902  prop = xmlGetNsProp(cur,
4903  (const xmlChar *)"disable-output-escaping",
4904  NULL);
4905  if (prop != NULL) {
4906 #ifdef WITH_XSLT_DEBUG_PARSING
4908  "Disable escaping: %s\n", text->content);
4909 #endif
4910  if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4911  noesc = 1;
4912  } else if (!xmlStrEqual(prop,
4913  (const xmlChar *)"no")){
4915  "xsl:text: disable-output-escaping allows only yes or no\n");
4916  style->warnings++;
4917 
4918  }
4919  xmlFree(prop);
4920  }
4921 
4922  while (text != NULL) {
4923  if (text->type == XML_COMMENT_NODE) {
4924  text = text->next;
4925  continue;
4926  }
4927  if ((text->type != XML_TEXT_NODE) &&
4928  (text->type != XML_CDATA_SECTION_NODE)) {
4930  "xsltParseTemplateContent: xslt:text content problem\n");
4931  style->errors++;
4932  break;
4933  }
4934  if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4935  text->name = xmlStringTextNoenc;
4936  text = text->next;
4937  }
4938 
4939  /*
4940  * replace xsl:text by the list of childs
4941  */
4942  if (text == NULL) {
4943  text = cur->children;
4944  while (text != NULL) {
4945  if ((style->internalized) &&
4946  (text->content != NULL) &&
4947  (!xmlDictOwns(style->dict, text->content))) {
4948 
4949  /*
4950  * internalize the text string
4951  */
4952  if (text->doc->dict != NULL) {
4953  const xmlChar *tmp;
4954 
4955  tmp = xmlDictLookup(text->doc->dict,
4956  text->content, -1);
4957  if (tmp != text->content) {
4959  text->content = (xmlChar *) tmp;
4960  }
4961  }
4962  }
4963 
4964  next = text->next;
4966  xmlAddPrevSibling(cur, text);
4967  text = next;
4968  }
4969  }
4970  }
4971  delete = cur;
4972  goto skip_children;
4973  }
4974  }
4975  else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
4976  (xsltCheckExtPrefix(style, cur->ns->prefix)))
4977  {
4978  /*
4979  * okay this is an extension element compile it too
4980  */
4981  xsltStylePreCompute(style, cur);
4982  }
4983  else if (cur->type == XML_ELEMENT_NODE)
4984  {
4985  /*
4986  * This is an element which will be output as part of the
4987  * template exectution, precompile AVT if found.
4988  */
4989  if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
4990  cur->ns = xmlSearchNsByHref(cur->doc, cur,
4991  style->defaultAlias);
4992  }
4993  if (cur->properties != NULL) {
4994  xmlAttrPtr attr = cur->properties;
4995 
4996  while (attr != NULL) {
4998  attr = attr->next;
4999  }
5000  }
5001  }
5002  /*
5003  * Skip to next node
5004  */
5005  if (cur->children != NULL) {
5006  if (cur->children->type != XML_ENTITY_DECL) {
5007  cur = cur->children;
5008  continue;
5009  }
5010  }
5011 skip_children:
5012  if (cur->next != NULL) {
5013  cur = cur->next;
5014  continue;
5015  }
5016 
5017  do {
5018  cur = cur->parent;
5019  if (cur == NULL)
5020  break;
5021  if (cur == templ) {
5022  cur = NULL;
5023  break;
5024  }
5025  if (cur->next != NULL) {
5026  cur = cur->next;
5027  break;
5028  }
5029  } while (cur != NULL);
5030  }
5031  if (delete != NULL) {
5032 #ifdef WITH_XSLT_DEBUG_PARSING
5034  "xsltParseTemplateContent: removing text\n");
5035 #endif
5036  xmlUnlinkNode(delete);
5037  xmlFreeNode(delete);
5038  delete = NULL;
5039  }
5040 
5041  /*
5042  * Skip the first params
5043  */
5044  cur = templ->children;
5045  while (cur != NULL) {
5046  if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5047  break;
5048  cur = cur->next;
5049  }
5050 
5051  /*
5052  * Browse the remainder of the template
5053  */
5054  while (cur != NULL) {
5055  if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5056  xmlNodePtr param = cur;
5057 
5059  "xsltParseTemplateContent: ignoring misplaced param element\n");
5060  if (style != NULL) style->warnings++;
5061  cur = cur->next;
5063  xmlFreeNode(param);
5064  } else
5065  break;
5066  }
5067 }
5068 
5069 #endif /* else XSLT_REFACTORED */
5070 
5082 static void
5084  xmlChar *prop = NULL;
5085  xmlChar *use = NULL;
5086  xmlChar *match = NULL;
5087  xmlChar *name = NULL;
5088  xmlChar *nameURI = NULL;
5089 
5090  if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
5091  return;
5092 
5093  /*
5094  * Get arguments
5095  */
5096  prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5097  if (prop != NULL) {
5098  const xmlChar *URI;
5099 
5100  /*
5101  * TODO: Don't use xsltGetQNameURI().
5102  */
5103  URI = xsltGetQNameURI(key, &prop);
5104  if (prop == NULL) {
5105  if (style != NULL) style->errors++;
5106  goto error;
5107  } else {
5108  name = prop;
5109  if (URI != NULL)
5110  nameURI = xmlStrdup(URI);
5111  }
5112 #ifdef WITH_XSLT_DEBUG_PARSING
5114  "xsltParseStylesheetKey: name %s\n", name);
5115 #endif
5116  } else {
5118  "xsl:key : error missing name\n");
5119  if (style != NULL) style->errors++;
5120  goto error;
5121  }
5122 
5123  match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5124  if (match == NULL) {
5126  "xsl:key : error missing match\n");
5127  if (style != NULL) style->errors++;
5128  goto error;
5129  }
5130 
5131  use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5132  if (use == NULL) {
5134  "xsl:key : error missing use\n");
5135  if (style != NULL) style->errors++;
5136  goto error;
5137  }
5138 
5139  /*
5140  * register the keys
5141  */
5142  xsltAddKey(style, name, nameURI, match, use, key);
5143 
5144 
5145 error:
5146  if (use != NULL)
5147  xmlFree(use);
5148  if (match != NULL)
5149  xmlFree(match);
5150  if (name != NULL)
5151  xmlFree(name);
5152  if (nameURI != NULL)
5153  xmlFree(nameURI);
5154 
5155  if (key->children != NULL) {
5156  xsltParseContentError(style, key->children);
5157  }
5158 }
5159 
5160 #ifdef XSLT_REFACTORED
5161 
5174 static void
5175 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
5176  xsltTemplatePtr templ;
5177  xmlChar *prop;
5178  double priority;
5179 
5180  if ((cctxt == NULL) || (templNode == NULL) ||
5181  (templNode->type != XML_ELEMENT_NODE))
5182  return;
5183 
5184  /*
5185  * Create and link the structure
5186  */
5187  templ = xsltNewTemplate();
5188  if (templ == NULL)
5189  return;
5190 
5191  xsltCompilerNodePush(cctxt, templNode);
5192  if (templNode->nsDef != NULL)
5193  cctxt->inode->inScopeNs =
5194  xsltCompilerBuildInScopeNsList(cctxt, templNode);
5195 
5196  templ->next = cctxt->style->templates;
5197  cctxt->style->templates = templ;
5198  templ->style = cctxt->style;
5199 
5200  /*
5201  * Attribute "mode".
5202  */
5203  prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
5204  if (prop != NULL) {
5205  const xmlChar *modeURI;
5206 
5207  /*
5208  * TODO: We need a standardized function for extraction
5209  * of namespace names and local names from QNames.
5210  * Don't use xsltGetQNameURI() as it cannot channe´┐Ż
5211  * reports through the context.
5212  */
5213  modeURI = xsltGetQNameURI(templNode, &prop);
5214  if (prop == NULL) {
5215  cctxt->style->errors++;
5216  goto error;
5217  }
5218  templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
5219  xmlFree(prop);
5220  prop = NULL;
5221  if (xmlValidateNCName(templ->mode, 0)) {
5222  xsltTransformError(NULL, cctxt->style, templNode,
5223  "xsl:template: Attribute 'mode': The local part '%s' "
5224  "of the value is not a valid NCName.\n", templ->name);
5225  cctxt->style->errors++;
5226  goto error;
5227  }
5228  if (modeURI != NULL)
5229  templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
5230 #ifdef WITH_XSLT_DEBUG_PARSING
5232  "xsltParseXSLTTemplate: mode %s\n", templ->mode);
5233 #endif
5234  }
5235  /*
5236  * Attribute "match".
5237  */
5238  prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
5239  if (prop != NULL) {
5240  templ->match = prop;
5241  prop = NULL;
5242  }
5243  /*
5244  * Attribute "priority".
5245  */
5246  prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
5247  if (prop != NULL) {
5249  templ->priority = (float) priority;
5250  xmlFree(prop);
5251  prop = NULL;
5252  }
5253  /*
5254  * Attribute "name".
5255  */
5256  prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
5257  if (prop != NULL) {
5258  const xmlChar *nameURI;
5259  xsltTemplatePtr curTempl;
5260 
5261  /*
5262  * TODO: Don't use xsltGetQNameURI().
5263  */
5264  nameURI = xsltGetQNameURI(templNode, &prop);
5265  if (prop == NULL) {
5266  cctxt->style->errors++;
5267  goto error;
5268  }
5269  templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
5270  xmlFree(prop);
5271  prop = NULL;
5272  if (xmlValidateNCName(templ->name, 0)) {
5273  xsltTransformError(NULL, cctxt->style, templNode,
5274  "xsl:template: Attribute 'name': The local part '%s' of "
5275  "the value is not a valid NCName.\n", templ->name);
5276  cctxt->style->errors++;
5277  goto error;
5278  }
5279  if (nameURI != NULL)
5280  templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
5281  curTempl = templ->next;
5282  while (curTempl != NULL) {
5283  if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
5284  xmlStrEqual(curTempl->nameURI, nameURI) ) ||
5285  (nameURI == NULL && curTempl->nameURI == NULL &&
5286  xmlStrEqual(curTempl->name, templ->name)))
5287  {
5288  xsltTransformError(NULL, cctxt->style, templNode,
5289  "xsl:template: error duplicate name '%s'\n", templ->name);
5290  cctxt->style->errors++;
5291  goto error;
5292  }
5293  curTempl = curTempl->next;
5294  }
5295  }
5296  if (templNode->children != NULL) {
5297  xsltParseTemplateContent(cctxt->style, templNode);
5298  /*
5299  * MAYBE TODO: Custom behaviour: In order to stay compatible with
5300  * Xalan and MSXML(.NET), we could allow whitespace
5301  * to appear before an xml:param element; this whitespace
5302  * will additionally become part of the "template".
5303  * NOTE that this is totally deviates from the spec, but
5304  * is the de facto behaviour of Xalan and MSXML(.NET).
5305  * Personally I wouldn't allow this, since if we have:
5306  * <xsl:template ...xml:space="preserve">
5307  * <xsl:param name="foo"/>
5308  * <xsl:param name="bar"/>
5309  * <xsl:param name="zoo"/>
5310  * ... the whitespace between every xsl:param would be
5311  * added to the result tree.
5312  */
5313  }
5314 
5315  templ->elem = templNode;
5316  templ->content = templNode->children;
5317  xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
5318 
5319 error:
5320  xsltCompilerNodePop(cctxt, templNode);
5321  return;
5322 }
5323 
5324 #else /* XSLT_REFACTORED */
5325 
5334 static void
5337  xmlChar *prop;
5338  xmlChar *mode = NULL;
5339  xmlChar *modeURI = NULL;
5340  double priority;
5341 
5342  if ((style == NULL) || (template == NULL) ||
5343  (template->type != XML_ELEMENT_NODE))
5344  return;
5345 
5346  /*
5347  * Create and link the structure
5348  */
5349  ret = xsltNewTemplate();
5350  if (ret == NULL)
5351  return;
5352  ret->next = style->templates;
5353  style->templates = ret;
5354  ret->style = style;
5355 
5356  /*
5357  * Get inherited namespaces
5358  */
5359  /*
5360  * TODO: Apply the optimized in-scope-namespace mechanism
5361  * as for the other XSLT instructions.
5362  */
5363  xsltGetInheritedNsList(style, ret, template);
5364 
5365  /*
5366  * Get arguments
5367  */
5368  prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
5369  if (prop != NULL) {
5370  const xmlChar *URI;
5371 
5372  /*
5373  * TODO: Don't use xsltGetQNameURI().
5374  */
5375  URI = xsltGetQNameURI(template, &prop);
5376  if (prop == NULL) {
5377  if (style != NULL) style->errors++;
5378  goto error;
5379  } else {
5380  mode = prop;
5381  if (URI != NULL)
5382  modeURI = xmlStrdup(URI);
5383  }
5384  ret->mode = xmlDictLookup(style->dict, mode, -1);
5385  ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
5386 #ifdef WITH_XSLT_DEBUG_PARSING
5388  "xsltParseStylesheetTemplate: mode %s\n", mode);
5389 #endif
5390  if (mode != NULL) xmlFree(mode);
5391  if (modeURI != NULL) xmlFree(modeURI);
5392  }
5393  prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
5394  if (prop != NULL) {
5395  if (ret->match != NULL) xmlFree(ret->match);
5396  ret->match = prop;
5397  }
5398 
5399  prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
5400  if (prop != NULL) {
5402  ret->priority = (float) priority;
5403  xmlFree(prop);
5404  }
5405 
5406  prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
5407  if (prop != NULL) {
5408  const xmlChar *URI;
5409 
5410  /*
5411  * TODO: Don't use xsltGetQNameURI().
5412  */
5413  URI = xsltGetQNameURI(template, &prop);
5414  if (prop == NULL) {
5415  if (style != NULL) style->errors++;
5416  goto error;
5417  } else {
5418  if (xmlValidateNCName(prop,0)) {
5419  xsltTransformError(NULL, style, template,
5420  "xsl:template : error invalid name '%s'\n", prop);
5421  if (style != NULL) style->errors++;
5422  xmlFree(prop);
5423  goto error;
5424  }
5425  ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
5426  xmlFree(prop);
5427  prop = NULL;
5428  if (URI != NULL)
5429  ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
5430  else
5431  ret->nameURI = NULL;
5432  }
5433  }
5434 
5435  /*
5436  * parse the content and register the pattern
5437  */
5438  xsltParseTemplateContent(style, template);
5439  ret->elem = template;
5440  ret->content = template->children;
5441  xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
5442 
5443 error:
5444  return;
5445 }
5446 
5447 #endif /* else XSLT_REFACTORED */
5448 
5449 #ifdef XSLT_REFACTORED
5450 
5458 static xsltStyleItemIncludePtr
5459 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
5460  xsltStyleItemIncludePtr item;
5461 
5462  if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
5463  return(NULL);
5464 
5465  node->psvi = NULL;
5466  item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
5467  if (item == NULL) {
5468  xsltTransformError(NULL, cctxt->style, node,
5469  "xsltIncludeComp : malloc failed\n");
5470  cctxt->style->errors++;
5471  return(NULL);
5472  }
5473  memset(item, 0, sizeof(xsltStyleItemInclude));
5474 
5475  node->psvi = item;
5476  item->inst = node;
5477  item->type = XSLT_FUNC_INCLUDE;
5478 
5479  item->next = cctxt->style->preComps;
5480  cctxt->style->preComps = (xsltElemPreCompPtr) item;
5481 
5482  return(item);
5483 }
5484 
5488 static int
5489 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
5490  xmlNodePtr cur,
5491  const xmlChar *name,
5492  const xmlChar *namespaceURI,
5493  int breakOnOtherElem,
5494  xmlNodePtr *resultNode)
5495 {
5496  if (name == NULL)
5497  return(-1);
5498 
5499  *resultNode = NULL;
5500  while (cur != NULL) {
5501  if (cur->type == XML_ELEMENT_NODE) {
5502  if ((cur->ns != NULL) && (cur->name != NULL)) {
5503  if ((*(cur->name) == *name) &&
5504  xmlStrEqual(cur->name, name) &&
5505  xmlStrEqual(cur->ns->href, namespaceURI))
5506  {
5507  *resultNode = cur;
5508  return(1);
5509  }
5510  }
5511  if (breakOnOtherElem)
5512  break;
5513  }
5514  cur = cur->next;
5515  }
5516  *resultNode = cur;
5517  return(0);
5518 }
5519 
5520 static int
5521 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
5522  xmlNodePtr node,
5524 {
5525  int ret = 0;
5526 
5527  /*
5528  * TODO: The reason why this function exists:
5529  * due to historical reasons some of the
5530  * top-level declarations are processed by functions
5531  * in other files. Since we need still to set
5532  * up the node-info and generate information like
5533  * in-scope namespaces, this is a wrapper around
5534  * those old parsing functions.
5535  */
5536  xsltCompilerNodePush(cctxt, node);
5537  if (node->nsDef != NULL)
5538  cctxt->inode->inScopeNs =
5539  xsltCompilerBuildInScopeNsList(cctxt, node);
5540  cctxt->inode->type = type;
5541 
5542  switch (type) {
5543  case XSLT_FUNC_INCLUDE:
5544  {
5545  int oldIsInclude;
5546 
5547  if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
5548  goto exit;
5549