ReactOS 0.4.16-dev-61-ge128cbc
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
29const 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*
42const 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*/
52const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
53
54/*
55* xsltXSLTAttrMarker:
56* Marker for XSLT attribute on Literal Result Elements.
57*/
58const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
59
60#endif
61
62#ifdef XSLT_LOCALE_WINAPI
63extern 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
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
96static 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
126static 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}
169static 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
193static int initialized = 0;
200void
201xsltInit (void) {
202 if (initialized == 0) {
203 initialized = 1;
204#ifdef XSLT_LOCALE_WINAPI
205 xsltLocaleMutex = xmlNewRMutex();
206#endif
208 }
209}
210
216void
218#ifdef XSLT_LOCALE_WINAPI
219 xmlFreeRMutex(xsltLocaleMutex);
220 xsltLocaleMutex = NULL;
221#endif
222 initialized = 0;
223}
224
233int
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
277static void
279{
280 if (self != NULL) {
281 if (self->digit)
282 xmlFree(self->digit);
283 if (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
307static void
309{
312
313 if (self == NULL)
314 return;
315
316 iter = self->decimalFormat;
317 while (iter != NULL) {
318 tmp = iter->next;
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
393static 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
414static 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
444static void
447
448 while (template != NULL) {
449 cur = template;
450 template = template->next;
452 }
453}
454
455#ifdef XSLT_REFACTORED
456
457static void
458xsltFreeNsAliasList(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
471static void
472xsltFreeNamespaceMap(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
484static xsltNsMapPtr
485xsltNewNamespaceMapItem(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
523static void
524xsltCompilerVarInfoFree(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
540static void
541xsltCompilationCtxtFree(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
583static xsltCompilerCtxtPtr
584xsltCompilationCtxtCreate(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
604internal_err:
605 xsltCompilationCtxtFree(ret);
606 return(NULL);
607}
608
609static void
610xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
611{
612 xsltEffectiveNsPtr tmp;
613
614 while (first != NULL) {
615 tmp = first;
616 first = first->nextInStore;
617 xmlFree(tmp);
618 }
619}
620
621static void
622xsltFreePrincipalStylesheetData(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
679static xsltPrincipalStylesheetDataPtr
680xsltNewPrincipalStylesheetData(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
714internal_err:
715
716 return(NULL);
717}
718
719#endif
720
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
781internal_err:
782 if (ret != NULL)
784 return(NULL);
785}
786
797}
798
808int
810{
811 return(style->extrasNr++);
812}
813
824int
826{
827 if (ctxt->extrasNr >= ctxt->extrasMax) {
828 int i;
829 if (ctxt->extrasNr == 0) {
830 ctxt->extrasMax = 20;
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;
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
872static void
875
876 while (style != NULL) {
877 next = style->next;
879 style = next;
880 }
881}
882
894static int
897{
898#if 0 /* TODO: Currently disabled, since probably not needed. */
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
927leave_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
949void
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
1085static int
1087 xsltTemplatePtr template,
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 }
1153skip_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
1180void
1182{
1183 xmlChar *elements,
1184 *prop;
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);
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");
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
1398static void
1400{
1401 xmlChar *prop;
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 }
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
1525static 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 }
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
1598static void
1600 int isXsltElem) {
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 }
1652}
1653#endif /* else of XSLT_REFACTORED */
1654
1664static 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 }
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
1734static int
1736 int isXsltElem)
1737{
1738 int nb = 0;
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 }
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*/
1806static xmlNsPtr
1807xsltTreeEnsureXMLDecl(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
1832#else
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*/
1855static xmlNsPtr
1856xsltTreeAcquireStoredNs(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
1902static int
1903xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
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
2073static int
2074xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2075 xsltStyleItemLRElementInfoPtr item,
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
2184add_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
2232skip_ns:
2233 {}
2234 }
2235 return(0);
2236}
2237
2238
2246static int
2247xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
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
2295static xsltVarInfoPtr
2296xsltCompilerVarInfoPush(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
2339static void
2340xsltCompilerVarInfoPop(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*/
2361static xsltCompilerNodeInfoPtr
2362xsltCompilerNodePush(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*/
2465static void
2466xsltCompilerNodePop(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
2499mismatch:
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*/
2552static xsltNsListContainerPtr
2553xsltCompilerBuildInScopeNsList(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
2655internal_err:
2656 if (list != NULL)
2657 xmlFree(list);
2658 cctxt->style->errors++;
2659 return(NULL);
2660}
2661
2662static int
2663xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2664 xsltPointerListPtr list,
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
2737internal_err:
2738 cctxt->style->errors++;
2739 return(-1);
2740}
2741
2753static xsltPointerListPtr
2754xsltCompilerUtilsCreateMergedList(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*/
2797static xsltPointerListPtr
2798xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2799 xsltPointerListPtr def,
2800 int instrCategory)
2801{
2802 xsltPointerListPtr list = NULL;
2803 xmlChar *value;
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",
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
2861exit:
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*/
2878static xsltPointerListPtr
2879xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2880 xsltPointerListPtr def,
2881 int instrCategory)
2882{
2883 xsltPointerListPtr list = NULL;
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",
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
2951exit:
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*/
2970static int
2971xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2972 int instrCategory)
2973{
2974 xmlChar *value;
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
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
3033static int
3034xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
3035{
3036 xmlNodePtr deleteNode, cur, txt, textNode = NULL;
3037 xmlDocPtr doc;
3039 int internalize = 0, findSpaceAttr;
3040 int xsltStylesheetElemDepth;
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
3230process_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
3384end_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) &&
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
3436next_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
3460internal_err:
3461 return(-1);
3462}
3463
3464#endif /* XSLT_REFACTORED */
3465
3466#ifdef XSLT_REFACTORED
3467#else
3468static 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;
3552 int i, moved;
3553
3555 if ((root != NULL) && (root != cur)) {
3556 while (ns != NULL) {
3557 moved = 0;
3558 next = ns->next;
3559 for (i = 0;i < style->exclPrefixNr;i++) {
3560 if ((ns->prefix != NULL) &&
3561 (xmlStrEqual(ns->href,
3562 style->exclPrefixTab[i]))) {
3563 /*
3564 * Move the namespace definition on the root
3565 * element to avoid duplicating it without
3566 * loosing it.
3567 */
3568 if (prev == NULL) {
3569 cur->nsDef = ns->next;
3570 } else {
3571 prev->next = ns->next;
3572 }
3573 ns->next = root->nsDef;
3574 root->nsDef = ns;
3575 moved = 1;
3576 break;
3577 }
3578 }
3579 if (moved == 0)
3580 prev = ns;
3581 ns = next;
3582 }
3583 }
3584 }
3585 /*
3586 * If we have prefixes locally, recurse and pop them up when
3587 * going back
3588 */
3589 if (exclPrefixes > 0) {
3591 for (;exclPrefixes > 0;exclPrefixes--)
3593 goto skip_children;
3594 }
3595 } else if (cur->type == XML_TEXT_NODE) {
3596 if (IS_BLANK_NODE(cur)) {
3597 if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
3598 deleteNode = cur;
3599 }
3600 } else if ((cur->content != NULL) && (internalize) &&
3601 (!xmlDictOwns(style->dict, cur->content))) {
3602 xmlChar *tmp;
3603
3604 /*
3605 * internalize the text string, goal is to speed
3606 * up operations and minimize used space by compiled
3607 * stylesheets.
3608 */
3609 tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
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
3634skip_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
3673static void
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 */
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) {
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
3758static xsltStyleType
3759xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
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"))
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
3882int
3883xsltParseAnyXSLTElem(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;
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;
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
4059apply_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
4082call_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
4106text:
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
4122empty_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
4143choose:
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
4206for_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
4243sequence_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
4267error:
4268exit:
4269 xsltCompilerNodePop(cctxt, elem);
4270 return(0);
4271
4272internal_err:
4273 xsltCompilerNodePop(cctxt, elem);
4274 return(-1);
4275}
4276
4287static xsltStyleItemUknownPtr
4288xsltForwardsCompatUnkownItemCreate(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
4324static int
4325xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
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
4407void
4408xsltParseSequenceConstructor(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) {
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) {
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
4828void
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
4877void
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