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