ReactOS  0.4.15-dev-5608-gafb953a
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
396 
398  if (cur == NULL) {
400  "xsltNewTemplate : malloc failed\n");
401  return(NULL);
402  }
403  memset(cur, 0, sizeof(xsltTemplate));
404  cur->priority = XSLT_PAT_NO_PRIORITY;
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
447 
448  while (template != NULL) {
449  cur = template;
450  template = template->next;
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) {
1379  xsltParseContentError(style, cur->children);
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) {
1512  xsltParseContentError(style, cur->children);
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) {
1578  xsltParseContentError(style, cur->children);
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. */
1610  (const xmlChar *)"extension-element-prefixes", NULL);
1611  } else {
1612  /* For literal result elements and extension instructions. */
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) {
1717  xsltParseContentError(style, cur->children);
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)
1747  (const xmlChar *)"exclude-result-prefixes", NULL);
1748  else
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) {
3590  xsltPreprocessStylesheet(style, cur->children);
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);
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  cur = cur->children;
3631  continue;
3632  }
3633 
3634 skip_children:
3635  if (cur->next != NULL) {
3636  cur = cur->next;
3637  continue;
3638  }
3639  do {
3640 
3641  cur = cur->parent;
3642  if (cur == NULL)
3643  break;
3644  if (cur == (xmlNodePtr) style->doc) {
3645  cur = NULL;
3646  break;
3647  }
3648  if (cur->next != NULL) {
3649  cur = cur->next;
3650  break;
3651  }
3652  } while (cur != NULL);
3653  }
3654  if (deleteNode != NULL) {
3655 #ifdef WITH_XSLT_DEBUG_PARSING
3657  "xsltPreprocessStylesheet: removing ignorable blank node\n");
3658 #endif
3659  xmlUnlinkNode(deleteNode);
3660  xmlFreeNode(deleteNode);
3661  }
3662 }
3663 #endif /* end of else XSLT_REFACTORED */
3664 
3673 static void
3675  xmlNodePtr cur;
3676  const xmlChar *URI;
3677 
3678  if (style == NULL)
3679  return;
3680  /*
3681  * TODO: basically if the stylesheet uses the same prefix for different
3682  * patterns, well they may be in problem, hopefully they will get
3683  * a warning first.
3684  */
3685  /*
3686  * TODO: Eliminate the use of the hash for XPath expressions.
3687  * An expression should be evaluated in the context of the in-scope
3688  * namespaces; eliminate the restriction of an XML document to contain
3689  * no duplicate prefixes for different namespace names.
3690  *
3691  */
3692  cur = xmlDocGetRootElement(style->doc);
3693  while (cur != NULL) {
3694  if (cur->type == XML_ELEMENT_NODE) {
3695  xmlNsPtr ns = cur->nsDef;
3696  while (ns != NULL) {
3697  if (ns->prefix != NULL) {
3698  if (style->nsHash == NULL) {
3699  style->nsHash = xmlHashCreate(10);
3700  if (style->nsHash == NULL) {
3702  "xsltGatherNamespaces: failed to create hash table\n");
3703  style->errors++;
3704  return;
3705  }
3706  }
3707  URI = xmlHashLookup(style->nsHash, ns->prefix);
3708  if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3710  "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3711  style->warnings++;
3712  } else if (URI == NULL) {
3713  xmlHashUpdateEntry(style->nsHash, ns->prefix,
3714  (void *) ns->href, NULL);
3715 
3716 #ifdef WITH_XSLT_DEBUG_PARSING
3718  "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3719 #endif
3720  }
3721  }
3722  ns = ns->next;
3723  }
3724  }
3725 
3726  /*
3727  * Skip to next node
3728  */
3729  if (cur->children != NULL) {
3730  if (cur->children->type != XML_ENTITY_DECL) {
3731  cur = cur->children;
3732  continue;
3733  }
3734  }
3735  if (cur->next != NULL) {
3736  cur = cur->next;
3737  continue;
3738  }
3739 
3740  do {
3741  cur = cur->parent;
3742  if (cur == NULL)
3743  break;
3744  if (cur == (xmlNodePtr) style->doc) {
3745  cur = NULL;
3746  break;
3747  }
3748  if (cur->next != NULL) {
3749  cur = cur->next;
3750  break;
3751  }
3752  } while (cur != NULL);
3753  }
3754 }
3755 
3756 #ifdef XSLT_REFACTORED
3757 
3758 static xsltStyleType
3759 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3760  xmlNodePtr node)
3761 {
3762  if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3763  (node->name == NULL))
3764  return(0);
3765 
3766  if (node->name[0] == 'a') {
3767  if (IS_XSLT_NAME(node, "apply-templates"))
3768  return(XSLT_FUNC_APPLYTEMPLATES);
3769  else if (IS_XSLT_NAME(node, "attribute"))
3770  return(XSLT_FUNC_ATTRIBUTE);
3771  else if (IS_XSLT_NAME(node, "apply-imports"))
3772  return(XSLT_FUNC_APPLYIMPORTS);
3773  else if (IS_XSLT_NAME(node, "attribute-set"))
3774  return(0);
3775 
3776  } else if (node->name[0] == 'c') {
3777  if (IS_XSLT_NAME(node, "choose"))
3778  return(XSLT_FUNC_CHOOSE);
3779  else if (IS_XSLT_NAME(node, "copy"))
3780  return(XSLT_FUNC_COPY);
3781  else if (IS_XSLT_NAME(node, "copy-of"))
3782  return(XSLT_FUNC_COPYOF);
3783  else if (IS_XSLT_NAME(node, "call-template"))
3784  return(XSLT_FUNC_CALLTEMPLATE);
3785  else if (IS_XSLT_NAME(node, "comment"))
3786  return(XSLT_FUNC_COMMENT);
3787 
3788  } else if (node->name[0] == 'd') {
3789  if (IS_XSLT_NAME(node, "document"))
3790  return(XSLT_FUNC_DOCUMENT);
3791  else if (IS_XSLT_NAME(node, "decimal-format"))
3792  return(0);
3793 
3794  } else if (node->name[0] == 'e') {
3795  if (IS_XSLT_NAME(node, "element"))
3796  return(XSLT_FUNC_ELEMENT);
3797 
3798  } else if (node->name[0] == 'f') {
3799  if (IS_XSLT_NAME(node, "for-each"))
3800  return(XSLT_FUNC_FOREACH);
3801  else if (IS_XSLT_NAME(node, "fallback"))
3802  return(XSLT_FUNC_FALLBACK);
3803 
3804  } else if (*(node->name) == 'i') {
3805  if (IS_XSLT_NAME(node, "if"))
3806  return(XSLT_FUNC_IF);
3807  else if (IS_XSLT_NAME(node, "include"))
3808  return(0);
3809  else if (IS_XSLT_NAME(node, "import"))
3810  return(0);
3811 
3812  } else if (*(node->name) == 'k') {
3813  if (IS_XSLT_NAME(node, "key"))
3814  return(0);
3815 
3816  } else if (*(node->name) == 'm') {
3817  if (IS_XSLT_NAME(node, "message"))
3818  return(XSLT_FUNC_MESSAGE);
3819 
3820  } else if (*(node->name) == 'n') {
3821  if (IS_XSLT_NAME(node, "number"))
3822  return(XSLT_FUNC_NUMBER);
3823  else if (IS_XSLT_NAME(node, "namespace-alias"))
3824  return(0);
3825 
3826  } else if (*(node->name) == 'o') {
3827  if (IS_XSLT_NAME(node, "otherwise"))
3828  return(XSLT_FUNC_OTHERWISE);
3829  else if (IS_XSLT_NAME(node, "output"))
3830  return(0);
3831 
3832  } else if (*(node->name) == 'p') {
3833  if (IS_XSLT_NAME(node, "param"))
3834  return(XSLT_FUNC_PARAM);
3835  else if (IS_XSLT_NAME(node, "processing-instruction"))
3836  return(XSLT_FUNC_PI);
3837  else if (IS_XSLT_NAME(node, "preserve-space"))
3838  return(0);
3839 
3840  } else if (*(node->name) == 's') {
3841  if (IS_XSLT_NAME(node, "sort"))
3842  return(XSLT_FUNC_SORT);
3843  else if (IS_XSLT_NAME(node, "strip-space"))
3844  return(0);
3845  else if (IS_XSLT_NAME(node, "stylesheet"))
3846  return(0);
3847 
3848  } else if (node->name[0] == 't') {
3849  if (IS_XSLT_NAME(node, "text"))
3850  return(XSLT_FUNC_TEXT);
3851  else if (IS_XSLT_NAME(node, "template"))
3852  return(0);
3853  else if (IS_XSLT_NAME(node, "transform"))
3854  return(0);
3855 
3856  } else if (*(node->name) == 'v') {
3857  if (IS_XSLT_NAME(node, "value-of"))
3858  return(XSLT_FUNC_VALUEOF);
3859  else if (IS_XSLT_NAME(node, "variable"))
3860  return(XSLT_FUNC_VARIABLE);
3861 
3862  } else if (*(node->name) == 'w') {
3863  if (IS_XSLT_NAME(node, "when"))
3864  return(XSLT_FUNC_WHEN);
3865  if (IS_XSLT_NAME(node, "with-param"))
3866  return(XSLT_FUNC_WITHPARAM);
3867  }
3868  return(0);
3869 }
3870 
3882 int
3883 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
3884 {
3885  if ((cctxt == NULL) || (elem == NULL) ||
3886  (elem->type != XML_ELEMENT_NODE))
3887  return(-1);
3888 
3889  elem->psvi = NULL;
3890 
3891  if (! (IS_XSLT_ELEM_FAST(elem)))
3892  return(-1);
3893  /*
3894  * Detection of handled content of extension instructions.
3895  */
3896  if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
3897  cctxt->inode->extContentHandled = 1;
3898  }
3899 
3900  xsltCompilerNodePush(cctxt, elem);
3901  /*
3902  * URGENT TODO: Find a way to speed up this annoying redundant
3903  * textual node-name and namespace comparison.
3904  */
3905  if (cctxt->inode->prev->curChildType != 0)
3906  cctxt->inode->type = cctxt->inode->prev->curChildType;
3907  else
3908  cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
3909  /*
3910  * Update the in-scope namespaces if needed.
3911  */
3912  if (elem->nsDef != NULL)
3913  cctxt->inode->inScopeNs =
3914  xsltCompilerBuildInScopeNsList(cctxt, elem);
3915  /*
3916  * xsltStylePreCompute():
3917  * This will compile the information found on the current
3918  * element's attributes. NOTE that this won't process the
3919  * children of the instruction.
3920  */
3921  xsltStylePreCompute(cctxt->style, elem);
3922  /*
3923  * TODO: How to react on errors in xsltStylePreCompute() ?
3924  */
3925 
3926  /*
3927  * Validate the content model of the XSLT-element.
3928  */
3929  switch (cctxt->inode->type) {
3931  /* EMPTY */
3932  goto empty_content;
3934  /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3935  goto apply_templates;
3936  case XSLT_FUNC_ATTRIBUTE:
3937  /* <!-- Content: template --> */
3938  goto sequence_constructor;
3940  /* <!-- Content: xsl:with-param* --> */
3941  goto call_template;
3942  case XSLT_FUNC_CHOOSE:
3943  /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3944  goto choose;
3945  case XSLT_FUNC_COMMENT:
3946  /* <!-- Content: template --> */
3947  goto sequence_constructor;
3948  case XSLT_FUNC_COPY:
3949  /* <!-- Content: template --> */
3950  goto sequence_constructor;
3951  case XSLT_FUNC_COPYOF:
3952  /* EMPTY */
3953  goto empty_content;
3954  case XSLT_FUNC_DOCUMENT: /* Extra one */
3955  /* ?? template ?? */
3956  goto sequence_constructor;
3957  case XSLT_FUNC_ELEMENT:
3958  /* <!-- Content: template --> */
3959  goto sequence_constructor;
3960  case XSLT_FUNC_FALLBACK:
3961  /* <!-- Content: template --> */
3962  goto sequence_constructor;
3963  case XSLT_FUNC_FOREACH:
3964  /* <!-- Content: (xsl:sort*, template) --> */
3965  goto for_each;
3966  case XSLT_FUNC_IF:
3967  /* <!-- Content: template --> */
3968  goto sequence_constructor;
3969  case XSLT_FUNC_OTHERWISE:
3970  /* <!-- Content: template --> */
3971  goto sequence_constructor;
3972  case XSLT_FUNC_MESSAGE:
3973  /* <!-- Content: template --> */
3974  goto sequence_constructor;
3975  case XSLT_FUNC_NUMBER:
3976  /* EMPTY */
3977  goto empty_content;
3978  case XSLT_FUNC_PARAM:
3979  /*
3980  * Check for redefinition.
3981  */
3982  if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3983  xsltVarInfoPtr ivar = cctxt->ivar;
3984 
3985  do {
3986  if ((ivar->name ==
3987  ((xsltStyleItemParamPtr) elem->psvi)->name) &&
3988  (ivar->nsName ==
3989  ((xsltStyleItemParamPtr) elem->psvi)->ns))
3990  {
3991  elem->psvi = NULL;
3992  xsltTransformError(NULL, cctxt->style, elem,
3993  "Redefinition of variable or parameter '%s'.\n",
3994  ivar->name);
3995  cctxt->style->errors++;
3996  goto error;
3997  }
3998  ivar = ivar->prev;
3999  } while (ivar != NULL);
4000  }
4001  /* <!-- Content: template --> */
4002  goto sequence_constructor;
4003  case XSLT_FUNC_PI:
4004  /* <!-- Content: template --> */
4005  goto sequence_constructor;
4006  case XSLT_FUNC_SORT:
4007  /* EMPTY */
4008  goto empty_content;
4009  case XSLT_FUNC_TEXT:
4010  /* <!-- Content: #PCDATA --> */
4011  goto text;
4012  case XSLT_FUNC_VALUEOF:
4013  /* EMPTY */
4014  goto empty_content;
4015  case XSLT_FUNC_VARIABLE:
4016  /*
4017  * Check for redefinition.
4018  */
4019  if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
4020  xsltVarInfoPtr ivar = cctxt->ivar;
4021 
4022  do {
4023  if ((ivar->name ==
4024  ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
4025  (ivar->nsName ==
4026  ((xsltStyleItemVariablePtr) elem->psvi)->ns))
4027  {
4028  elem->psvi = NULL;
4029  xsltTransformError(NULL, cctxt->style, elem,
4030  "Redefinition of variable or parameter '%s'.\n",
4031  ivar->name);
4032  cctxt->style->errors++;
4033  goto error;
4034  }
4035  ivar = ivar->prev;
4036  } while (ivar != NULL);
4037  }
4038  /* <!-- Content: template --> */
4039  goto sequence_constructor;
4040  case XSLT_FUNC_WHEN:
4041  /* <!-- Content: template --> */
4042  goto sequence_constructor;
4043  case XSLT_FUNC_WITHPARAM:
4044  /* <!-- Content: template --> */
4045  goto sequence_constructor;
4046  default:
4047 #ifdef WITH_XSLT_DEBUG_PARSING
4049  "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4050  elem->name);
4051 #endif
4052  xsltTransformError(NULL, cctxt->style, elem,
4053  "xsltParseXSLTNode: Internal error; "
4054  "unhandled XSLT element '%s'.\n", elem->name);
4055  cctxt->style->errors++;
4056  goto internal_err;
4057  }
4058 
4059 apply_templates:
4060  /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4061  if (elem->children != NULL) {
4062  xmlNodePtr child = elem->children;
4063  do {
4064  if (child->type == XML_ELEMENT_NODE) {
4065  if (IS_XSLT_ELEM_FAST(child)) {
4066  if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
4067  cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4068  xsltParseAnyXSLTElem(cctxt, child);
4069  } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
4070  cctxt->inode->curChildType = XSLT_FUNC_SORT;
4071  xsltParseAnyXSLTElem(cctxt, child);
4072  } else
4073  xsltParseContentError(cctxt->style, child);
4074  } else
4075  xsltParseContentError(cctxt->style, child);
4076  }
4077  child = child->next;
4078  } while (child != NULL);
4079  }
4080  goto exit;
4081 
4082 call_template:
4083  /* <!-- Content: xsl:with-param* --> */
4084  if (elem->children != NULL) {
4085  xmlNodePtr child = elem->children;
4086  do {
4087  if (child->type == XML_ELEMENT_NODE) {
4088  if (IS_XSLT_ELEM_FAST(child)) {
4090 
4091  type = xsltGetXSLTElementTypeByNode(cctxt, child);
4092  if (type == XSLT_FUNC_WITHPARAM) {
4093  cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4094  xsltParseAnyXSLTElem(cctxt, child);
4095  } else {
4096  xsltParseContentError(cctxt->style, child);
4097  }
4098  } else
4099  xsltParseContentError(cctxt->style, child);
4100  }
4101  child = child->next;
4102  } while (child != NULL);
4103  }
4104  goto exit;
4105 
4106 text:
4107  if (elem->children != NULL) {
4108  xmlNodePtr child = elem->children;
4109  do {
4110  if ((child->type != XML_TEXT_NODE) &&
4111  (child->type != XML_CDATA_SECTION_NODE))
4112  {
4113  xsltTransformError(NULL, cctxt->style, elem,
4114  "The XSLT 'text' element must have only character "
4115  "data as content.\n");
4116  }
4117  child = child->next;
4118  } while (child != NULL);
4119  }
4120  goto exit;
4121 
4122 empty_content:
4123  if (elem->children != NULL) {
4124  xmlNodePtr child = elem->children;
4125  /*
4126  * Relaxed behaviour: we will allow whitespace-only text-nodes.
4127  */
4128  do {
4129  if (((child->type != XML_TEXT_NODE) &&
4130  (child->type != XML_CDATA_SECTION_NODE)) ||
4131  (! IS_BLANK_NODE(child)))
4132  {
4133  xsltTransformError(NULL, cctxt->style, elem,
4134  "This XSLT element must have no content.\n");
4135  cctxt->style->errors++;
4136  break;
4137  }
4138  child = child->next;
4139  } while (child != NULL);
4140  }
4141  goto exit;
4142 
4143 choose:
4144  /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4145  /*
4146  * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4147  * The old behaviour did not check this.
4148  * NOTE: In XSLT 2.0 they are stripped beforehand
4149  * if whitespace-only (regardless of xml:space).
4150  */
4151  if (elem->children != NULL) {
4152  xmlNodePtr child = elem->children;
4153  int nbWhen = 0, nbOtherwise = 0, err = 0;
4154  do {
4155  if (child->type == XML_ELEMENT_NODE) {
4156  if (IS_XSLT_ELEM_FAST(child)) {
4158 
4159  type = xsltGetXSLTElementTypeByNode(cctxt, child);
4160  if (type == XSLT_FUNC_WHEN) {
4161  nbWhen++;
4162  if (nbOtherwise) {
4163  xsltParseContentError(cctxt->style, child);
4164  err = 1;
4165  break;
4166  }
4167  cctxt->inode->curChildType = XSLT_FUNC_WHEN;
4168  xsltParseAnyXSLTElem(cctxt, child);
4169  } else if (type == XSLT_FUNC_OTHERWISE) {
4170  if (! nbWhen) {
4171  xsltParseContentError(cctxt->style, child);
4172  err = 1;
4173  break;
4174  }
4175  if (nbOtherwise) {
4176  xsltTransformError(NULL, cctxt->style, elem,
4177  "The XSLT 'choose' element must not contain "
4178  "more than one XSLT 'otherwise' element.\n");
4179  cctxt->style->errors++;
4180  err = 1;
4181  break;
4182  }
4183  nbOtherwise++;
4184  cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
4185  xsltParseAnyXSLTElem(cctxt, child);
4186  } else
4187  xsltParseContentError(cctxt->style, child);
4188  } else
4189  xsltParseContentError(cctxt->style, child);
4190  }
4191  /*
4192  else
4193  xsltParseContentError(cctxt, child);
4194  */
4195  child = child->next;
4196  } while (child != NULL);
4197  if ((! err) && (! nbWhen)) {
4198  xsltTransformError(NULL, cctxt->style, elem,
4199  "The XSLT element 'choose' must contain at least one "
4200  "XSLT element 'when'.\n");
4201  cctxt->style->errors++;
4202  }
4203  }
4204  goto exit;
4205 
4206 for_each:
4207  /* <!-- Content: (xsl:sort*, template) --> */
4208  /*
4209  * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4210  * The old behaviour did not allow this, but it catched this
4211  * only at transformation-time.
4212  * In XSLT 2.0 they are stripped beforehand if whitespace-only
4213  * (regardless of xml:space).
4214  */
4215  if (elem->children != NULL) {
4216  xmlNodePtr child = elem->children;
4217  /*
4218  * Parse xsl:sort first.
4219  */
4220  do {
4221  if ((child->type == XML_ELEMENT_NODE) &&
4222  IS_XSLT_ELEM_FAST(child))
4223  {
4224  if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
4226  {
4227  cctxt->inode->curChildType = XSLT_FUNC_SORT;
4228  xsltParseAnyXSLTElem(cctxt, child);
4229  } else
4230  break;
4231  } else
4232  break;
4233  child = child->next;
4234  } while (child != NULL);
4235  /*
4236  * Parse the sequece constructor.
4237  */
4238  if (child != NULL)
4239  xsltParseSequenceConstructor(cctxt, child);
4240  }
4241  goto exit;
4242 
4243 sequence_constructor:
4244  /*
4245  * Parse the sequence constructor.
4246  */
4247  if (elem->children != NULL)
4248  xsltParseSequenceConstructor(cctxt, elem->children);
4249 
4250  /*
4251  * Register information for vars/params. Only needed if there
4252  * are any following siblings.
4253  */
4254  if ((elem->next != NULL) &&
4255  ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
4256  (cctxt->inode->type == XSLT_FUNC_PARAM)))
4257  {
4258  if ((elem->psvi != NULL) &&
4259  (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
4260  {
4261  xsltCompilerVarInfoPush(cctxt, elem,
4262  ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
4263  ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
4264  }
4265  }
4266 
4267 error:
4268 exit:
4269  xsltCompilerNodePop(cctxt, elem);
4270  return(0);
4271 
4272 internal_err:
4273  xsltCompilerNodePop(cctxt, elem);
4274  return(-1);
4275 }
4276 
4287 static xsltStyleItemUknownPtr
4288 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
4289 {
4290  xsltStyleItemUknownPtr item;
4291 
4292  item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
4293  if (item == NULL) {
4294  xsltTransformError(NULL, cctxt->style, NULL,
4295  "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4296  "Failed to allocate memory.\n");
4297  cctxt->style->errors++;
4298  return(NULL);
4299  }
4300  memset(item, 0, sizeof(xsltStyleItemUknown));
4301  item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
4302  /*
4303  * Store it in the stylesheet.
4304  */
4305  item->next = cctxt->style->preComps;
4306  cctxt->style->preComps = (xsltElemPreCompPtr) item;
4307  return(item);
4308 }
4309 
4324 static int
4325 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
4326  xmlNodePtr node)
4327 {
4328  if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
4329  return(-1);
4330 
4331  /*
4332  * Detection of handled content of extension instructions.
4333  */
4334  if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4335  cctxt->inode->extContentHandled = 1;
4336  }
4337  if (cctxt->inode->forwardsCompat == 0) {
4338  /*
4339  * We are not in forwards-compatible mode, so raise an error.
4340  */
4341  xsltTransformError(NULL, cctxt->style, node,
4342  "Unknown XSLT element '%s'.\n", node->name);
4343  cctxt->style->errors++;
4344  return(1);
4345  }
4346  /*
4347  * Forwards-compatible mode.
4348  * ------------------------
4349  *
4350  * Parse/compile xsl:fallback elements.
4351  *
4352  * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4353  * ANSWER: No, since in the stylesheet the fallback behaviour might
4354  * also be provided by using the XSLT function "element-available".
4355  */
4356  if (cctxt->unknownItem == NULL) {
4357  /*
4358  * Create a singleton for all unknown XSLT instructions.
4359  */
4360  cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
4361  if (cctxt->unknownItem == NULL) {
4362  node->psvi = NULL;
4363  return(-1);
4364  }
4365  }
4366  node->psvi = cctxt->unknownItem;
4367  if (node->children == NULL)
4368  return(0);
4369  else {
4370  xmlNodePtr child = node->children;
4371 
4372  xsltCompilerNodePush(cctxt, node);
4373  /*
4374  * Update the in-scope namespaces if needed.
4375  */
4376  if (node->nsDef != NULL)
4377  cctxt->inode->inScopeNs =
4378  xsltCompilerBuildInScopeNsList(cctxt, node);
4379  /*
4380  * Parse all xsl:fallback children.
4381  */
4382  do {
4383  if ((child->type == XML_ELEMENT_NODE) &&
4384  IS_XSLT_ELEM_FAST(child) &&
4385  IS_XSLT_NAME(child, "fallback"))
4386  {
4387  cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
4388  xsltParseAnyXSLTElem(cctxt, child);
4389  }
4390  child = child->next;
4391  } while (child != NULL);
4392 
4393  xsltCompilerNodePop(cctxt, node);
4394  }
4395  return(0);
4396 }
4397 
4407 void
4408 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
4409 {
4411  xmlNodePtr deleteNode = NULL;
4412 
4413  if (cctxt == NULL) {
4415  "xsltParseSequenceConstructor: Bad arguments\n");
4416  cctxt->style->errors++;
4417  return;
4418  }
4419  /*
4420  * Detection of handled content of extension instructions.
4421  */
4422  if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4423  cctxt->inode->extContentHandled = 1;
4424  }
4425  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
4426  return;
4427  /*
4428  * This is the content reffered to as a "template".
4429  * E.g. an xsl:element has such content model:
4430  * <xsl:element
4431  * name = { qname }
4432  * namespace = { uri-reference }
4433  * use-attribute-sets = qnames>
4434  * <!-- Content: template -->
4435  *
4436  * NOTE that in XSLT-2 the term "template" was abandoned due to
4437  * confusion with xsl:template and the term "sequence constructor"
4438  * was introduced instead.
4439  *
4440  * The following XSLT-instructions are allowed to appear:
4441  * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4442  * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4443  * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4444  * xsl:message, xsl:fallback,
4445  * xsl:processing-instruction, xsl:comment, xsl:element
4446  * xsl:attribute.
4447  * Additional allowed content:
4448  * 1) extension instructions
4449  * 2) literal result elements
4450  * 3) PCDATA
4451  *
4452  * NOTE that this content model does *not* allow xsl:param.
4453  */
4454  while (cur != NULL) {
4455  if (deleteNode != NULL) {
4456 #ifdef WITH_XSLT_DEBUG_BLANKS
4458  "xsltParseSequenceConstructor: removing xsl:text element\n");
4459 #endif
4460  xmlUnlinkNode(deleteNode);
4461  xmlFreeNode(deleteNode);
4462  deleteNode = NULL;
4463  }
4464  if (cur->type == XML_ELEMENT_NODE) {
4465 
4466  if (cur->psvi == xsltXSLTTextMarker) {
4467  /*
4468  * xsl:text elements
4469  * --------------------------------------------------------
4470  */
4471  xmlNodePtr tmp;
4472 
4473  cur->psvi = NULL;
4474  /*
4475  * Mark the xsl:text element for later deletion.
4476  */
4477  deleteNode = cur;
4478  /*
4479  * Validate content.
4480  */
4481  tmp = cur->children;
4482  if (tmp) {
4483  /*
4484  * We don't expect more than one text-node in the
4485  * content, since we already merged adjacent
4486  * text/CDATA-nodes and eliminated PI/comment-nodes.
4487  */
4488  if ((tmp->type == XML_TEXT_NODE) ||
4489  (tmp->next == NULL))
4490  {
4491  /*
4492  * Leave the contained text-node in the tree.
4493  */
4494  xmlUnlinkNode(tmp);
4495  xmlAddPrevSibling(cur, tmp);
4496  } else {
4497  tmp = NULL;
4498  xsltTransformError(NULL, cctxt->style, cur,
4499  "Element 'xsl:text': Invalid type "
4500  "of node found in content.\n");
4501  cctxt->style->errors++;
4502  }
4503  }
4504  if (cur->properties) {
4505  xmlAttrPtr attr;
4506  /*
4507  * TODO: We need to report errors for
4508  * invalid attrs.
4509  */
4510  attr = cur->properties;
4511  do {
4512  if ((attr->ns == NULL) &&
4513  (attr->name != NULL) &&
4514  (attr->name[0] == 'd') &&
4516  BAD_CAST "disable-output-escaping"))
4517  {
4518  /*
4519  * Attr "disable-output-escaping".
4520  * XSLT-2: This attribute is deprecated.
4521  */
4522  if ((attr->children != NULL) &&
4523  xmlStrEqual(attr->children->content,
4524  BAD_CAST "yes"))
4525  {
4526  /*
4527  * Disable output escaping for this
4528  * text node.
4529  */
4530  if (tmp)
4531  tmp->name = xmlStringTextNoenc;
4532  } else if ((attr->children == NULL) ||
4533  (attr->children->content == NULL) ||
4534  (!xmlStrEqual(attr->children->content,
4535  BAD_CAST "no")))
4536  {
4537  xsltTransformError(NULL, cctxt->style,
4538  cur,
4539  "Attribute 'disable-output-escaping': "
4540  "Invalid value. Expected is "
4541  "'yes' or 'no'.\n");
4542  cctxt->style->errors++;
4543  }
4544  break;
4545  }
4546  attr = attr->next;
4547  } while (attr != NULL);
4548  }
4549  } else if (IS_XSLT_ELEM_FAST(cur)) {
4550  /*
4551  * TODO: Using the XSLT-marker is still not stable yet.
4552  */
4553  /* if (cur->psvi == xsltXSLTElemMarker) { */
4554  /*
4555  * XSLT instructions
4556  * --------------------------------------------------------
4557  */
4558  cur->psvi = NULL;
4559  type = xsltGetXSLTElementTypeByNode(cctxt, cur);
4560  switch (type) {
4563  case XSLT_FUNC_ATTRIBUTE:
4565  case XSLT_FUNC_CHOOSE:
4566  case XSLT_FUNC_COMMENT:
4567  case XSLT_FUNC_COPY:
4568  case XSLT_FUNC_COPYOF:
4569  case XSLT_FUNC_DOCUMENT: /* Extra one */
4570  case XSLT_FUNC_ELEMENT:
4571  case XSLT_FUNC_FALLBACK:
4572  case XSLT_FUNC_FOREACH:
4573  case XSLT_FUNC_IF:
4574  case XSLT_FUNC_MESSAGE:
4575  case XSLT_FUNC_NUMBER:
4576  case XSLT_FUNC_PI:
4577  case XSLT_FUNC_TEXT:
4578  case XSLT_FUNC_VALUEOF:
4579  case XSLT_FUNC_VARIABLE:
4580  /*
4581  * Parse the XSLT element.
4582  */
4583  cctxt->inode->curChildType = type;
4584  xsltParseAnyXSLTElem(cctxt, cur);
4585  break;
4586  default:
4587  xsltParseUnknownXSLTElem(cctxt, cur);
4588  cur = cur->next;
4589  continue;
4590  }
4591  } else {
4592  /*
4593  * Non-XSLT elements
4594  * -----------------
4595  */
4596  xsltCompilerNodePush(cctxt, cur);
4597  /*
4598  * Update the in-scope namespaces if needed.
4599  */
4600  if (cur->nsDef != NULL)
4601  cctxt->inode->inScopeNs =
4602  xsltCompilerBuildInScopeNsList(cctxt, cur);
4603  /*
4604  * The current element is either a literal result element
4605  * or an extension instruction.
4606  *
4607  * Process attr "xsl:extension-element-prefixes".
4608  * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4609  * processed by the implementor of the extension function;
4610  * i.e., it won't be handled by the XSLT processor.
4611  */
4612  /* SPEC 1.0:
4613  * "exclude-result-prefixes" is only allowed on literal
4614  * result elements and "xsl:exclude-result-prefixes"
4615  * on xsl:stylesheet/xsl:transform.
4616  * SPEC 2.0:
4617  * "There are a number of standard attributes
4618  * that may appear on any XSLT element: specifically
4619  * version, exclude-result-prefixes,
4620  * extension-element-prefixes, xpath-default-namespace,
4621  * default-collation, and use-when."
4622  *
4623  * SPEC 2.0:
4624  * For literal result elements:
4625  * "xsl:version, xsl:exclude-result-prefixes,
4626  * xsl:extension-element-prefixes,
4627  * xsl:xpath-default-namespace,
4628  * xsl:default-collation, or xsl:use-when."
4629  */
4630  if (cur->properties)
4631  cctxt->inode->extElemNs =
4632  xsltParseExtElemPrefixes(cctxt,
4633  cur, cctxt->inode->extElemNs,
4634  XSLT_ELEMENT_CATEGORY_LRE);
4635  /*
4636  * Eval if we have an extension instruction here.
4637  */
4638  if ((cur->ns != NULL) &&
4639  (cctxt->inode->extElemNs != NULL) &&
4640  (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
4641  {
4642  /*
4643  * Extension instructions
4644  * ----------------------------------------------------
4645  * Mark the node information.
4646  */
4647  cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
4648  cctxt->inode->extContentHandled = 0;
4649  if (cur->psvi != NULL) {
4650  cur->psvi = NULL;
4651  /*
4652  * TODO: Temporary sanity check.
4653  */
4654  xsltTransformError(NULL, cctxt->style, cur,
4655  "Internal error in xsltParseSequenceConstructor(): "
4656  "Occupied PSVI field.\n");
4657  cctxt->style->errors++;
4658  cur = cur->next;
4659  continue;
4660  }
4661  cur->psvi = (void *)
4662  xsltPreComputeExtModuleElement(cctxt->style, cur);
4663 
4664  if (cur->psvi == NULL) {
4665  /*
4666  * OLD COMMENT: "Unknown element, maybe registered
4667  * at the context level. Mark it for later
4668  * recognition."
4669  * QUESTION: What does the xsltExtMarker mean?
4670  * ANSWER: It is used in
4671  * xsltApplySequenceConstructor() at
4672  * transformation-time to look out for extension
4673  * registered in the transformation context.
4674  */
4675  cur->psvi = (void *) xsltExtMarker;
4676  }
4677  /*
4678  * BIG NOTE: Now the ugly part. In previous versions
4679  * of Libxslt (until 1.1.16), all the content of an
4680  * extension instruction was processed and compiled without
4681  * the need of the extension-author to explicitely call
4682  * such a processing;.We now need to mimic this old
4683  * behaviour in order to avoid breaking old code
4684  * on the extension-author's side.
4685  * The mechanism:
4686  * 1) If the author does *not* set the
4687  * compile-time-flag @extContentHandled, then we'll
4688  * parse the content assuming that it's a "template"
4689  * (or "sequence constructor in XSLT 2.0 terms).
4690  * NOTE: If the extension is registered at
4691  * transformation-time only, then there's no way of
4692  * knowing that content shall be valid, and we'll
4693  * process the content the same way.
4694  * 2) If the author *does* set the flag, then we'll assume
4695  * that the author has handled the parsing him/herself
4696  * (e.g. called xsltParseSequenceConstructor(), etc.
4697  * explicitely in his/her code).
4698  */
4699  if ((cur->children != NULL) &&
4700  (cctxt->inode->extContentHandled == 0))
4701  {
4702  /*
4703  * Default parsing of the content using the
4704  * sequence-constructor model.
4705  */
4706  xsltParseSequenceConstructor(cctxt, cur->children);
4707  }
4708  } else {
4709  /*
4710  * Literal result element
4711  * ----------------------------------------------------
4712  * Allowed XSLT attributes:
4713  * xsl:extension-element-prefixes CDATA #IMPLIED
4714  * xsl:exclude-result-prefixes CDATA #IMPLIED
4715  * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4716  * xsl:version NMTOKEN #IMPLIED
4717  */
4718  cur->psvi = NULL;
4719  cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
4720  if (cur->properties != NULL) {
4721  xmlAttrPtr attr = cur->properties;
4722  /*
4723  * Attribute "xsl:exclude-result-prefixes".
4724  */
4725  cctxt->inode->exclResultNs =
4726  xsltParseExclResultPrefixes(cctxt, cur,
4727  cctxt->inode->exclResultNs,
4728  XSLT_ELEMENT_CATEGORY_LRE);
4729  /*
4730  * Attribute "xsl:version".
4731  */
4732  xsltParseAttrXSLTVersion(cctxt, cur,
4733  XSLT_ELEMENT_CATEGORY_LRE);
4734  /*
4735  * Report invalid XSLT attributes.
4736  * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4737  * next to xsl:version, xsl:exclude-result-prefixes and
4738  * xsl:extension-element-prefixes.
4739  *
4740  * Mark all XSLT attributes, in order to skip such
4741  * attributes when instantiating the LRE.
4742  */
4743  do {
4744  if ((attr->psvi != xsltXSLTAttrMarker) &&
4745  IS_XSLT_ATTR_FAST(attr))
4746  {
4747  if (! xmlStrEqual(attr->name,
4748  BAD_CAST "use-attribute-sets"))
4749  {
4750  xsltTransformError(NULL, cctxt->style,
4751  cur,
4752  "Unknown XSLT attribute '%s'.\n",
4753  attr->name);
4754  cctxt->style->errors++;
4755  } else {
4756  /*
4757  * XSLT attr marker.
4758  */
4759  attr->psvi = (void *) xsltXSLTAttrMarker;
4760  }
4761  }
4762  attr = attr->next;
4763  } while (attr != NULL);
4764  }
4765  /*
4766  * Create/reuse info for the literal result element.
4767  */
4768  if (cctxt->inode->nsChanged)
4769  xsltLREInfoCreate(cctxt, cur, 1);
4770  cur->psvi = cctxt->inode->litResElemInfo;
4771  /*
4772  * Apply ns-aliasing on the element and on its attributes.
4773  */
4774  if (cctxt->hasNsAliases)
4775  xsltLREBuildEffectiveNs(cctxt, cur);
4776  /*
4777  * Compile attribute value templates (AVT).
4778  */
4779  if (cur->properties) {
4780  xmlAttrPtr attr = cur->properties;
4781 
4782  while (attr != NULL) {
4783  xsltCompileAttr(cctxt->style, attr);
4784  attr = attr->next;
4785  }
4786  }
4787  /*
4788  * Parse the content, which is defined to be a "template"
4789  * (or "sequence constructor" in XSLT 2.0 terms).
4790  */
4791  if (cur->children != NULL) {
4792  xsltParseSequenceConstructor(cctxt, cur->children);
4793  }
4794  }
4795  /*
4796  * Leave the non-XSLT element.
4797  */
4798  xsltCompilerNodePop(cctxt, cur);
4799  }
4800  }
4801  cur = cur->next;
4802  }
4803  if (deleteNode != NULL) {
4804 #ifdef WITH_XSLT_DEBUG_BLANKS
4806  "xsltParseSequenceConstructor: removing xsl:text element\n");
4807 #endif
4808  xmlUnlinkNode(deleteNode);
4809  xmlFreeNode(deleteNode);
4810  deleteNode = NULL;
4811  }
4812 }
4813 
4828 void
4830  if ((style == NULL) || (templ == NULL) ||
4831  (templ->type == XML_NAMESPACE_DECL))
4832  return;
4833 
4834  /*
4835  * Detection of handled content of extension instructions.
4836  */
4837  if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4838  XSLT_CCTXT(style)->inode->extContentHandled = 1;
4839  }
4840 
4841  if (templ->children != NULL) {
4842  xmlNodePtr child = templ->children;
4843  /*
4844  * Process xsl:param elements, which can only occur as the
4845  * immediate children of xsl:template (well, and of any
4846  * user-defined extension instruction if needed).
4847  */
4848  do {
4849  if ((child->type == XML_ELEMENT_NODE) &&
4850  IS_XSLT_ELEM_FAST(child) &&
4851  IS_XSLT_NAME(child, "param"))
4852  {
4853  XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
4854  xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
4855  } else
4856  break;
4857  child = child->next;
4858  } while (child != NULL);
4859  /*
4860  * Parse the content and register the pattern.
4861  */
4862  xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
4863  }
4864 }
4865 
4866 #else /* XSLT_REFACTORED */
4867 
4877 void
4879  xmlNodePtr cur, delete;
4880 
4881  if ((style == NULL) || (templ == NULL) ||
4882  (templ->type == XML_NAMESPACE_DECL)) return;
4883 
4884  /*
4885  * This content comes from the stylesheet
4886  * For stylesheets, the set of whitespace-preserving
4887  * element names consists of just xsl:text.
4888  */
4889  cur = templ->children;
4890  delete = NULL;
4891  while (cur != NULL) {
4892  if (delete != NULL) {
4893 #ifdef WITH_XSLT_DEBUG_BLANKS
4895  "xsltParseTemplateContent: removing text\n");
4896 #endif
4897  xmlUnlinkNode(delete);
4898  xmlFreeNode(delete);
4899  delete = NULL;
4900  }
4901  if (IS_XSLT_ELEM(cur)) {
4903 
4904  if (IS_XSLT_NAME(cur, "text")) {
4905  /*
4906  * TODO: Processing of xsl:text should be moved to
4907  * xsltPreprocessStylesheet(), since otherwise this
4908  * will be performed for every multiply included
4909  * stylesheet; i.e. this here is not skipped with
4910  * the use of the style->nopreproc flag.
4911  */
4912  if (cur->children != NULL) {
4913  xmlChar *prop;
4914  xmlNodePtr text = cur->children, next;
4915  int noesc = 0;
4916 
4917  prop = xmlGetNsProp(cur,
4918  (const xmlChar *)"disable-output-escaping",
4919  NULL);
4920  if (prop != NULL) {
4921 #ifdef WITH_XSLT_DEBUG_PARSING
4923  "Disable escaping: %s\n", text->content);
4924 #endif
4925  if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4926  noesc = 1;
4927  } else if (!xmlStrEqual(prop,
4928  (const xmlChar *)"no")){
4930  "xsl:text: disable-output-escaping allows only yes or no\n");
4931  style->warnings++;
4932 
4933  }
4934  xmlFree(prop);
4935  }
4936 
4937  while (text != NULL) {
4938  if (text->type == XML_COMMENT_NODE) {
4939  text = text->next;
4940  continue;
4941  }
4942  if ((text->type != XML_TEXT_NODE) &&
4943  (text->type != XML_CDATA_SECTION_NODE)) {
4945  "xsltParseTemplateContent: xslt:text content problem\n");
4946  style->errors++;
4947  break;
4948  }
4949  if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4950  text->name = xmlStringTextNoenc;
4951  text = text->next;
4952  }
4953 
4954  /*
4955  * replace xsl:text by the list of childs
4956  */
4957  if (text == NULL) {
4958  text = cur->children;
4959  while (text != NULL) {
4960  if ((style->internalized) &&
4961  (text->content != NULL) &&
4962  (!xmlDictOwns(style->dict, text->content))) {
4963 
4964  /*
4965  * internalize the text string
4966  */
4967  if (text->doc->dict != NULL) {
4968  const xmlChar *tmp;
4969 
4970  tmp = xmlDictLookup(text->doc->dict,
4971  text->content, -1);
4972  if (tmp != text->content) {
4974  text->content = (xmlChar *) tmp;
4975  }
4976  }
4977  }
4978 
4979  next = text->next;
4981  xmlAddPrevSibling(cur, text);
4982  text = next;
4983  }
4984  }
4985  }
4986  delete = cur;
4987  goto skip_children;
4988  }
4989  }
4990  else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
4991  (xsltCheckExtPrefix(style, cur->ns->prefix)))
4992  {
4993  /*
4994  * okay this is an extension element compile it too
4995  */
4997  }
4998  else if (cur->type == XML_ELEMENT_NODE)
4999  {
5000  /*
5001  * This is an element which will be output as part of the
5002  * template exectution, precompile AVT if found.
5003  */
5004  if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
5005  cur->ns = xmlSearchNsByHref(cur->doc, cur,
5006  style->defaultAlias);
5007  }
5008  if (cur->properties != NULL) {
5009  xmlAttrPtr attr = cur->properties;
5010 
5011  while (attr != NULL) {
5013  attr = attr->next;
5014  }
5015  }
5016  }
5017  /*
5018  * Skip to next node
5019  */
5020  if (cur->children != NULL) {
5021  if (cur->children->type != XML_ENTITY_DECL) {
5022  cur = cur->children;
5023  continue;
5024  }
5025  }
5026 skip_children:
5027  if (cur->next != NULL) {
5028  cur = cur->next;
5029  continue;
5030  }
5031 
5032  do {
5033  cur = cur->parent;
5034  if (cur == NULL)
5035  break;
5036  if (cur == templ) {
5037  cur = NULL;
5038  break;
5039  }
5040  if (cur->next != NULL) {
5041  cur = cur->next;
5042  break;
5043  }
5044  } while (cur != NULL);
5045  }
5046  if (delete != NULL) {
5047 #ifdef WITH_XSLT_DEBUG_PARSING
5049  "xsltParseTemplateContent: removing text\n");
5050 #endif
5051  xmlUnlinkNode(delete);
5052  xmlFreeNode(delete);
5053  delete = NULL;
5054  }
5055 
5056  /*
5057  * Skip the first params
5058  */
5059  cur = templ->children;
5060  while (cur != NULL) {
5061  if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5062  break;
5063  cur = cur->next;
5064  }
5065 
5066  /*
5067  * Browse the remainder of the template
5068  */
5069  while (cur != NULL) {
5070  if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5071  xmlNodePtr param = cur;
5072 
5074  "xsltParseTemplateContent: ignoring misplaced param element\n");
5075  if (style != NULL) style->warnings++;
5076  cur = cur->next;
5078  xmlFreeNode(param);
5079  } else
5080  break;
5081  }
5082 }
5083 
5084 #endif /* else XSLT_REFACTORED */
5085 
5097 static void
5099  xmlChar *prop = NULL;
5100  xmlChar *use = NULL;
5101  xmlChar *match = NULL;
5102  xmlChar *name = NULL;
5103  xmlChar *nameURI = NULL;
5104 
5105  if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
5106  return;
5107 
5108  /*
5109  * Get arguments
5110  */
5111  prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5112  if (prop != NULL) {
5113  const xmlChar *URI;
5114 
5115  /*
5116  * TODO: Don't use xsltGetQNameURI().
5117  */
5118  URI = xsltGetQNameURI(key, &prop);
5119  if (prop == NULL) {
5120  if (style != NULL) style->errors++;
5121  goto error;
5122  } else {
5123  name = prop;
5124  if (URI != NULL)
5125  nameURI = xmlStrdup(URI);
5126  }
5127 #ifdef WITH_XSLT_DEBUG_PARSING
5129  "xsltParseStylesheetKey: name %s\n", name);
5130 #endif
5131  } else {
5133  "xsl:key : error missing name\n");
5134  if (style != NULL) style->errors++;
5135  goto error;
5136  }
5137 
5138  match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5139  if (match == NULL) {
5141  "xsl:key : error missing match\n");
5142  if (style != NULL) style->errors++;
5143  goto error;
5144  }
5145 
5146  use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5147  if (use == NULL) {
5149  "xsl:key : error missing use\n");
5150  if (style != NULL) style->errors++;
5151  goto error;
5152  }
5153 
5154  /*
5155  * register the keys
5156  */
5157  xsltAddKey(style, name, nameURI, match, use, key);
5158 
5159 
5160 error:
5161  if (use != NULL)
5162  xmlFree(use);
5163  if (match != NULL)
5164  xmlFree(match);
5165  if (name != NULL)
5166  xmlFree(name);
5167  if (nameURI != NULL)
5168  xmlFree(nameURI);
5169 
5170  if (key->children != NULL) {
5171  xsltParseContentError(style, key->children);
5172  }
5173 }
5174 
5175 #ifdef XSLT_REFACTORED
5176 
5189 static void
5190 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
5191  xsltTemplatePtr templ;
5192  xmlChar *prop;
5193  double priority;
5194 
5195  if ((cctxt == NULL) || (templNode == NULL) ||
5196  (templNode->type != XML_ELEMENT_NODE))
5197  return;
5198 
5199  /*
5200  * Create and link the structure
5201  */
5202  templ = xsltNewTemplate();
5203  if (templ == NULL)
5204  return;
5205 
5206  xsltCompilerNodePush(cctxt, templNode);
5207  if (templNode->nsDef != NULL)
5208  cctxt->inode->inScopeNs =
5209  xsltCompilerBuildInScopeNsList(cctxt, templNode);
5210 
5211  templ->next = cctxt->style->templates;
5212  cctxt->style->templates = templ;
5213  templ->style = cctxt->style;
5214 
5215  /*
5216  * Attribute "mode".
5217  */
5218  prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
5219  if (prop != NULL) {
5220  const xmlChar *modeURI;
5221 
5222  /*
5223  * TODO: We need a standardized function for extraction
5224  * of namespace names and local names from QNames.
5225  * Don't use xsltGetQNameURI() as it cannot channe´┐Ż
5226  * reports through the context.
5227  */
5228  modeURI = xsltGetQNameURI(templNode, &prop);
5229  if (prop == NULL) {
5230  cctxt->style->errors++;
5231  goto error;
5232  }
5233  templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
5234  xmlFree(prop);
5235  prop = NULL;
5236  if (xmlValidateNCName(templ->mode, 0)) {
5237  xsltTransformError(NULL, cctxt->style, templNode,
5238  "xsl:template: Attribute 'mode': The local part '%s' "
5239  "of the value is not a valid NCName.\n", templ->name);
5240  cctxt->style->errors++;
5241  goto error;
5242  }
5243  if (modeURI != NULL)
5244  templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
5245 #ifdef WITH_XSLT_DEBUG_PARSING
5247  "xsltParseXSLTTemplate: mode %s\n", templ->mode);
5248 #endif
5249  }
5250  /*
5251  * Attribute "match".
5252  */
5253  prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
5254  if (prop != NULL) {
5255  templ->match = prop;
5256  prop = NULL;
5257  }
5258  /*
5259  * Attribute "priority".
5260  */
5261  prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
5262  if (prop != NULL) {
5264  templ->priority = (float) priority;
5265  xmlFree(prop);
5266  prop = NULL;
5267  }
5268  /*
5269  * Attribute "name".
5270  */
5271  prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
5272  if (prop != NULL) {
5273  const xmlChar *nameURI;
5274  xsltTemplatePtr curTempl;
5275 
5276  /*
5277  * TODO: Don't use xsltGetQNameURI().
5278  */
5279  nameURI = xsltGetQNameURI(templNode, &prop);
5280  if (prop == NULL) {
5281  cctxt->style->errors++;
5282  goto error;
5283  }
5284  templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
5285  xmlFree(prop);
5286  prop = NULL;
5287  if (xmlValidateNCName(templ->name, 0)) {
5288  xsltTransformError(NULL, cctxt->style, templNode,
5289  "xsl:template: Attribute 'name': The local part '%s' of "
5290  "the value is not a valid NCName.\n", templ->name);
5291  cctxt->style->errors++;
5292  goto error;
5293  }
5294  if (nameURI != NULL)
5295  templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
5296  curTempl = templ->next;
5297  while (curTempl != NULL) {
5298  if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
5299  xmlStrEqual(curTempl->nameURI, nameURI) ) ||
5300  (nameURI == NULL && curTempl->nameURI == NULL &&
5301  xmlStrEqual(curTempl->name, templ->name)))
5302  {
5303  xsltTransformError(NULL, cctxt->style, templNode,
5304  "xsl:template: error duplicate name '%s'\n", templ->name);
5305  cctxt->style->errors++;
5306  goto error;
5307  }
5308  curTempl = curTempl->next;
5309  }
5310  }
5311  if (templNode->children != NULL) {
5312  xsltParseTemplateContent(cctxt->style, templNode);
5313  /*
5314  * MAYBE TODO: Custom behaviour: In order to stay compatible with
5315  * Xalan and MSXML(.NET), we could allow whitespace
5316  * to appear before an xml:param element; this whitespace
5317  * will additionally become part of the "template".
5318  * NOTE that this is totally deviates from the spec, but
5319  * is the de facto behaviour of Xalan and MSXML(.NET).
5320