[REACTOS]
[reactos.git] / reactos / dll / 3rdparty / libxslt / xslt.c
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 #define IN_LIBXSLT
17 #include "libxslt.h"
18
19 #include <string.h>
20
21 #include <libxml/xmlmemory.h>
22 #include <libxml/parser.h>
23 #include <libxml/tree.h>
24 #include <libxml/valid.h>
25 #include <libxml/hash.h>
26 #include <libxml/uri.h>
27 #include <libxml/xmlerror.h>
28 #include <libxml/parserInternals.h>
29 #include <libxml/xpathInternals.h>
30 #include <libxml/xpath.h>
31 #include "xslt.h"
32 #include "xsltInternals.h"
33 #include "pattern.h"
34 #include "variables.h"
35 #include "namespaces.h"
36 #include "attributes.h"
37 #include "xsltutils.h"
38 #include "imports.h"
39 #include "keys.h"
40 #include "documents.h"
41 #include "extensions.h"
42 #include "preproc.h"
43 #include "extra.h"
44 #include "security.h"
45
46 #ifdef WITH_XSLT_DEBUG
47 #define WITH_XSLT_DEBUG_PARSING
48 /* #define WITH_XSLT_DEBUG_BLANKS */
49 #endif
50
51 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
52 const int xsltLibxsltVersion = LIBXSLT_VERSION;
53 const int xsltLibxmlVersion = LIBXML_VERSION;
54
55 #ifdef XSLT_REFACTORED
56
57 const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
58
59 #define XSLT_ELEMENT_CATEGORY_XSLT 0
60 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
61 #define XSLT_ELEMENT_CATEGORY_LRE 2
62
63 /*
64 * xsltLiteralResultMarker:
65 * Marker for Literal result elements, in order to avoid multiple attempts
66 * to recognize such elements in the stylesheet's tree.
67 * This marker is set on node->psvi during the initial traversal
68 * of a stylesheet's node tree.
69 *
70 const xmlChar *xsltLiteralResultMarker =
71 (const xmlChar *) "Literal Result Element";
72 */
73
74 /*
75 * xsltXSLTTextMarker:
76 * Marker for xsl:text elements. Used to recognize xsl:text elements
77 * for post-processing of the stylesheet's tree, where those
78 * elements are removed from the tree.
79 */
80 const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
81
82 /*
83 * xsltXSLTAttrMarker:
84 * Marker for XSLT attribute on Literal Result Elements.
85 */
86 const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
87
88 #endif
89
90 #ifdef XSLT_LOCALE_WINAPI
91 extern xmlRMutexPtr xsltLocaleMutex;
92 #endif
93 /*
94 * Harmless but avoiding a problem when compiling against a
95 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
96 */
97 #ifndef LIBXML_DEBUG_ENABLED
98 double xmlXPathStringEvalNumber(const xmlChar *str);
99 #endif
100 /*
101 * Useful macros
102 */
103
104 #ifdef IS_BLANK
105 #undef IS_BLANK
106 #endif
107 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
108 ((c) == 0x0D))
109
110 #ifdef IS_BLANK_NODE
111 #undef IS_BLANK_NODE
112 #endif
113 #define IS_BLANK_NODE(n) \
114 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
115
116 /**
117 * xsltParseContentError:
118 *
119 * @style: the stylesheet
120 * @node: the node where the error occured
121 *
122 * Compile-time error function.
123 */
124 static void
125 xsltParseContentError(xsltStylesheetPtr style,
126 xmlNodePtr node)
127 {
128 if ((style == NULL) || (node == NULL))
129 return;
130
131 if (IS_XSLT_ELEM(node))
132 xsltTransformError(NULL, style, node,
133 "The XSLT-element '%s' is not allowed at this position.\n",
134 node->name);
135 else
136 xsltTransformError(NULL, style, node,
137 "The element '%s' is not allowed at this position.\n",
138 node->name);
139 style->errors++;
140 }
141
142 #ifdef XSLT_REFACTORED
143 #else
144 /**
145 * exclPrefixPush:
146 * @style: the transformation stylesheet
147 * @value: the excluded namespace name to push on the stack
148 *
149 * Push an excluded namespace name on the stack
150 *
151 * Returns the new index in the stack or -1 if already present or
152 * in case of error
153 */
154 static int
155 exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
156 {
157 int i;
158
159 if (style->exclPrefixMax == 0) {
160 style->exclPrefixMax = 4;
161 style->exclPrefixTab =
162 (xmlChar * *)xmlMalloc(style->exclPrefixMax *
163 sizeof(style->exclPrefixTab[0]));
164 if (style->exclPrefixTab == NULL) {
165 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
166 return (-1);
167 }
168 }
169 /* do not push duplicates */
170 for (i = 0;i < style->exclPrefixNr;i++) {
171 if (xmlStrEqual(style->exclPrefixTab[i], value))
172 return(-1);
173 }
174 if (style->exclPrefixNr >= style->exclPrefixMax) {
175 style->exclPrefixMax *= 2;
176 style->exclPrefixTab =
177 (xmlChar * *)xmlRealloc(style->exclPrefixTab,
178 style->exclPrefixMax *
179 sizeof(style->exclPrefixTab[0]));
180 if (style->exclPrefixTab == NULL) {
181 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
182 return (-1);
183 }
184 }
185 style->exclPrefixTab[style->exclPrefixNr] = value;
186 style->exclPrefix = value;
187 return (style->exclPrefixNr++);
188 }
189 /**
190 * exclPrefixPop:
191 * @style: the transformation stylesheet
192 *
193 * Pop an excluded prefix value from the stack
194 *
195 * Returns the stored excluded prefix value
196 */
197 static xmlChar *
198 exclPrefixPop(xsltStylesheetPtr style)
199 {
200 xmlChar *ret;
201
202 if (style->exclPrefixNr <= 0)
203 return (0);
204 style->exclPrefixNr--;
205 if (style->exclPrefixNr > 0)
206 style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
207 else
208 style->exclPrefix = NULL;
209 ret = style->exclPrefixTab[style->exclPrefixNr];
210 style->exclPrefixTab[style->exclPrefixNr] = 0;
211 return (ret);
212 }
213 #endif
214
215 /************************************************************************
216 * *
217 * Helper functions *
218 * *
219 ************************************************************************/
220
221 static int initialized = 0;
222 /**
223 * xsltInit:
224 *
225 * Initializes the processor (e.g. registers built-in extensions,
226 * etc.)
227 */
228 void
229 xsltInit (void) {
230 if (initialized == 0) {
231 initialized = 1;
232 #ifdef XSLT_LOCALE_WINAPI
233 xsltLocaleMutex = xmlNewRMutex();
234 #endif
235 xsltRegisterAllExtras();
236 }
237 }
238
239 /**
240 * xsltUninit:
241 *
242 * Uninitializes the processor.
243 */
244 void
245 xsltUninit (void) {
246 #ifdef XSLT_LOCALE_WINAPI
247 xmlFreeRMutex(xsltLocaleMutex);
248 xsltLocaleMutex = NULL;
249 #endif
250 initialized = 0;
251 }
252
253 /**
254 * xsltIsBlank:
255 * @str: a string
256 *
257 * Check if a string is ignorable
258 *
259 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
260 */
261 int
262 xsltIsBlank(xmlChar *str) {
263 if (str == NULL)
264 return(1);
265 while (*str != 0) {
266 if (!(IS_BLANK(*str))) return(0);
267 str++;
268 }
269 return(1);
270 }
271
272 /************************************************************************
273 * *
274 * Routines to handle XSLT data structures *
275 * *
276 ************************************************************************/
277 static xsltDecimalFormatPtr
278 xsltNewDecimalFormat(xmlChar *name)
279 {
280 xsltDecimalFormatPtr self;
281 /* UTF-8 for 0x2030 */
282 static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
283
284 self = xmlMalloc(sizeof(xsltDecimalFormat));
285 if (self != NULL) {
286 self->next = NULL;
287 self->name = name;
288
289 /* Default values */
290 self->digit = xmlStrdup(BAD_CAST("#"));
291 self->patternSeparator = xmlStrdup(BAD_CAST(";"));
292 self->decimalPoint = xmlStrdup(BAD_CAST("."));
293 self->grouping = xmlStrdup(BAD_CAST(","));
294 self->percent = xmlStrdup(BAD_CAST("%"));
295 self->permille = xmlStrdup(BAD_CAST(permille));
296 self->zeroDigit = xmlStrdup(BAD_CAST("0"));
297 self->minusSign = xmlStrdup(BAD_CAST("-"));
298 self->infinity = xmlStrdup(BAD_CAST("Infinity"));
299 self->noNumber = xmlStrdup(BAD_CAST("NaN"));
300 }
301 return self;
302 }
303
304 static void
305 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
306 {
307 if (self != NULL) {
308 if (self->digit)
309 xmlFree(self->digit);
310 if (self->patternSeparator)
311 xmlFree(self->patternSeparator);
312 if (self->decimalPoint)
313 xmlFree(self->decimalPoint);
314 if (self->grouping)
315 xmlFree(self->grouping);
316 if (self->percent)
317 xmlFree(self->percent);
318 if (self->permille)
319 xmlFree(self->permille);
320 if (self->zeroDigit)
321 xmlFree(self->zeroDigit);
322 if (self->minusSign)
323 xmlFree(self->minusSign);
324 if (self->infinity)
325 xmlFree(self->infinity);
326 if (self->noNumber)
327 xmlFree(self->noNumber);
328 if (self->name)
329 xmlFree(self->name);
330 xmlFree(self);
331 }
332 }
333
334 static void
335 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
336 {
337 xsltDecimalFormatPtr iter;
338 xsltDecimalFormatPtr tmp;
339
340 if (self == NULL)
341 return;
342
343 iter = self->decimalFormat;
344 while (iter != NULL) {
345 tmp = iter->next;
346 xsltFreeDecimalFormat(iter);
347 iter = tmp;
348 }
349 }
350
351 /**
352 * xsltDecimalFormatGetByName:
353 * @style: the XSLT stylesheet
354 * @name: the decimal-format name to find
355 *
356 * Find decimal-format by name
357 *
358 * Returns the xsltDecimalFormatPtr
359 */
360 xsltDecimalFormatPtr
361 xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
362 {
363 xsltDecimalFormatPtr result = NULL;
364
365 if (name == NULL)
366 return style->decimalFormat;
367
368 while (style != NULL) {
369 for (result = style->decimalFormat->next;
370 result != NULL;
371 result = result->next) {
372 if (xmlStrEqual(name, result->name))
373 return result;
374 }
375 style = xsltNextImport(style);
376 }
377 return result;
378 }
379
380
381 /**
382 * xsltNewTemplate:
383 *
384 * Create a new XSLT Template
385 *
386 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
387 */
388 static xsltTemplatePtr
389 xsltNewTemplate(void) {
390 xsltTemplatePtr cur;
391
392 cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
393 if (cur == NULL) {
394 xsltTransformError(NULL, NULL, NULL,
395 "xsltNewTemplate : malloc failed\n");
396 return(NULL);
397 }
398 memset(cur, 0, sizeof(xsltTemplate));
399 cur->priority = XSLT_PAT_NO_PRIORITY;
400 return(cur);
401 }
402
403 /**
404 * xsltFreeTemplate:
405 * @template: an XSLT template
406 *
407 * Free up the memory allocated by @template
408 */
409 static void
410 xsltFreeTemplate(xsltTemplatePtr template) {
411 if (template == NULL)
412 return;
413 if (template->match) xmlFree(template->match);
414 /*
415 * NOTE: @name and @nameURI are put into the string dict now.
416 * if (template->name) xmlFree(template->name);
417 * if (template->nameURI) xmlFree(template->nameURI);
418 */
419 /*
420 if (template->mode) xmlFree(template->mode);
421 if (template->modeURI) xmlFree(template->modeURI);
422 */
423 if (template->inheritedNs) xmlFree(template->inheritedNs);
424
425 /* free profiling data */
426 if (template->templCalledTab) xmlFree(template->templCalledTab);
427 if (template->templCountTab) xmlFree(template->templCountTab);
428
429 memset(template, -1, sizeof(xsltTemplate));
430 xmlFree(template);
431 }
432
433 /**
434 * xsltFreeTemplateList:
435 * @template: an XSLT template list
436 *
437 * Free up the memory allocated by all the elements of @template
438 */
439 static void
440 xsltFreeTemplateList(xsltTemplatePtr template) {
441 xsltTemplatePtr cur;
442
443 while (template != NULL) {
444 cur = template;
445 template = template->next;
446 xsltFreeTemplate(cur);
447 }
448 }
449
450 #ifdef XSLT_REFACTORED
451
452 static void
453 xsltFreeNsAliasList(xsltNsAliasPtr item)
454 {
455 xsltNsAliasPtr tmp;
456
457 while (item) {
458 tmp = item;
459 item = item->next;
460 xmlFree(tmp);
461 }
462 return;
463 }
464
465 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
466 static void
467 xsltFreeNamespaceMap(xsltNsMapPtr item)
468 {
469 xsltNsMapPtr tmp;
470
471 while (item) {
472 tmp = item;
473 item = item->next;
474 xmlFree(tmp);
475 }
476 return;
477 }
478
479 static xsltNsMapPtr
480 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
481 xmlDocPtr doc,
482 xmlNsPtr ns,
483 xmlNodePtr elem)
484 {
485 xsltNsMapPtr ret;
486
487 if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
488 return(NULL);
489
490 ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
491 if (ret == NULL) {
492 xsltTransformError(NULL, cctxt->style, elem,
493 "Internal error: (xsltNewNamespaceMapItem) "
494 "memory allocation failed.\n");
495 return(NULL);
496 }
497 memset(ret, 0, sizeof(xsltNsMap));
498 ret->doc = doc;
499 ret->ns = ns;
500 ret->origNsName = ns->href;
501 /*
502 * Store the item at current stylesheet-level.
503 */
504 if (cctxt->psData->nsMap != NULL)
505 ret->next = cctxt->psData->nsMap;
506 cctxt->psData->nsMap = ret;
507
508 return(ret);
509 }
510 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
511
512 /**
513 * xsltCompilerVarInfoFree:
514 * @cctxt: the compilation context
515 *
516 * Frees the list of information for vars/params.
517 */
518 static void
519 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
520 {
521 xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
522
523 while (ivar) {
524 ivartmp = ivar;
525 ivar = ivar->next;
526 xmlFree(ivartmp);
527 }
528 }
529
530 /**
531 * xsltCompilerCtxtFree:
532 *
533 * Free an XSLT compiler context.
534 */
535 static void
536 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
537 {
538 if (cctxt == NULL)
539 return;
540 #ifdef WITH_XSLT_DEBUG_PARSING
541 xsltGenericDebug(xsltGenericDebugContext,
542 "Freeing compilation context\n");
543 xsltGenericDebug(xsltGenericDebugContext,
544 "### Max inodes: %d\n", cctxt->maxNodeInfos);
545 xsltGenericDebug(xsltGenericDebugContext,
546 "### Max LREs : %d\n", cctxt->maxLREs);
547 #endif
548 /*
549 * Free node-infos.
550 */
551 if (cctxt->inodeList != NULL) {
552 xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
553 while (cur != NULL) {
554 tmp = cur;
555 cur = cur->next;
556 xmlFree(tmp);
557 }
558 }
559 if (cctxt->tmpList != NULL)
560 xsltPointerListFree(cctxt->tmpList);
561 #ifdef XSLT_REFACTORED_XPATHCOMP
562 if (cctxt->xpathCtxt != NULL)
563 xmlXPathFreeContext(cctxt->xpathCtxt);
564 #endif
565 if (cctxt->nsAliases != NULL)
566 xsltFreeNsAliasList(cctxt->nsAliases);
567
568 if (cctxt->ivars)
569 xsltCompilerVarInfoFree(cctxt);
570
571 xmlFree(cctxt);
572 }
573
574 /**
575 * xsltCompilerCreate:
576 *
577 * Creates an XSLT compiler context.
578 *
579 * Returns the pointer to the created xsltCompilerCtxt or
580 * NULL in case of an internal error.
581 */
582 static xsltCompilerCtxtPtr
583 xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
584 xsltCompilerCtxtPtr ret;
585
586 ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
587 if (ret == NULL) {
588 xsltTransformError(NULL, style, NULL,
589 "xsltCompilerCreate: allocation of compiler "
590 "context failed.\n");
591 return(NULL);
592 }
593 memset(ret, 0, sizeof(xsltCompilerCtxt));
594
595 ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
596 ret->tmpList = xsltPointerListCreate(20);
597 if (ret->tmpList == NULL) {
598 goto internal_err;
599 }
600 #ifdef XSLT_REFACTORED_XPATHCOMP
601 /*
602 * Create the XPath compilation context in order
603 * to speed up precompilation of XPath expressions.
604 */
605 ret->xpathCtxt = xmlXPathNewContext(NULL);
606 if (ret->xpathCtxt == NULL)
607 goto internal_err;
608 #endif
609
610 return(ret);
611
612 internal_err:
613 xsltCompilationCtxtFree(ret);
614 return(NULL);
615 }
616
617 static void
618 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
619 {
620 xsltEffectiveNsPtr tmp;
621
622 while (first != NULL) {
623 tmp = first;
624 first = first->nextInStore;
625 xmlFree(tmp);
626 }
627 }
628
629 static void
630 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
631 {
632 if (data == NULL)
633 return;
634
635 if (data->inScopeNamespaces != NULL) {
636 int i;
637 xsltNsListContainerPtr nsi;
638 xsltPointerListPtr list =
639 (xsltPointerListPtr) data->inScopeNamespaces;
640
641 for (i = 0; i < list->number; i++) {
642 /*
643 * REVISIT TODO: Free info of in-scope namespaces.
644 */
645 nsi = (xsltNsListContainerPtr) list->items[i];
646 if (nsi->list != NULL)
647 xmlFree(nsi->list);
648 xmlFree(nsi);
649 }
650 xsltPointerListFree(list);
651 data->inScopeNamespaces = NULL;
652 }
653
654 if (data->exclResultNamespaces != NULL) {
655 int i;
656 xsltPointerListPtr list = (xsltPointerListPtr)
657 data->exclResultNamespaces;
658
659 for (i = 0; i < list->number; i++)
660 xsltPointerListFree((xsltPointerListPtr) list->items[i]);
661
662 xsltPointerListFree(list);
663 data->exclResultNamespaces = NULL;
664 }
665
666 if (data->extElemNamespaces != NULL) {
667 xsltPointerListPtr list = (xsltPointerListPtr)
668 data->extElemNamespaces;
669 int i;
670
671 for (i = 0; i < list->number; i++)
672 xsltPointerListFree((xsltPointerListPtr) list->items[i]);
673
674 xsltPointerListFree(list);
675 data->extElemNamespaces = NULL;
676 }
677 if (data->effectiveNs) {
678 xsltLREEffectiveNsNodesFree(data->effectiveNs);
679 data->effectiveNs = NULL;
680 }
681 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
682 xsltFreeNamespaceMap(data->nsMap);
683 #endif
684 xmlFree(data);
685 }
686
687 static xsltPrincipalStylesheetDataPtr
688 xsltNewPrincipalStylesheetData(void)
689 {
690 xsltPrincipalStylesheetDataPtr ret;
691
692 ret = (xsltPrincipalStylesheetDataPtr)
693 xmlMalloc(sizeof(xsltPrincipalStylesheetData));
694 if (ret == NULL) {
695 xsltTransformError(NULL, NULL, NULL,
696 "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
697 return(NULL);
698 }
699 memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
700
701 /*
702 * Global list of in-scope namespaces.
703 */
704 ret->inScopeNamespaces = xsltPointerListCreate(-1);
705 if (ret->inScopeNamespaces == NULL)
706 goto internal_err;
707 /*
708 * Global list of excluded result ns-decls.
709 */
710 ret->exclResultNamespaces = xsltPointerListCreate(-1);
711 if (ret->exclResultNamespaces == NULL)
712 goto internal_err;
713 /*
714 * Global list of extension instruction namespace names.
715 */
716 ret->extElemNamespaces = xsltPointerListCreate(-1);
717 if (ret->extElemNamespaces == NULL)
718 goto internal_err;
719
720 return(ret);
721
722 internal_err:
723
724 return(NULL);
725 }
726
727 #endif
728
729 /**
730 * xsltNewStylesheet:
731 *
732 * Create a new XSLT Stylesheet
733 *
734 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
735 */
736 xsltStylesheetPtr
737 xsltNewStylesheet(void) {
738 xsltStylesheetPtr ret = NULL;
739
740 ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
741 if (ret == NULL) {
742 xsltTransformError(NULL, NULL, NULL,
743 "xsltNewStylesheet : malloc failed\n");
744 goto internal_err;
745 }
746 memset(ret, 0, sizeof(xsltStylesheet));
747
748 ret->omitXmlDeclaration = -1;
749 ret->standalone = -1;
750 ret->decimalFormat = xsltNewDecimalFormat(NULL);
751 ret->indent = -1;
752 ret->errors = 0;
753 ret->warnings = 0;
754 ret->exclPrefixNr = 0;
755 ret->exclPrefixMax = 0;
756 ret->exclPrefixTab = NULL;
757 ret->extInfos = NULL;
758 ret->extrasNr = 0;
759 ret->internalized = 1;
760 ret->literal_result = 0;
761 ret->forwards_compatible = 0;
762 ret->dict = xmlDictCreate();
763 #ifdef WITH_XSLT_DEBUG
764 xsltGenericDebug(xsltGenericDebugContext,
765 "creating dictionary for stylesheet\n");
766 #endif
767
768 xsltInit();
769
770 return(ret);
771
772 internal_err:
773 if (ret != NULL)
774 xsltFreeStylesheet(ret);
775 return(NULL);
776 }
777
778 /**
779 * xsltAllocateExtra:
780 * @style: an XSLT stylesheet
781 *
782 * Allocate an extra runtime information slot statically while compiling
783 * the stylesheet and return its number
784 *
785 * Returns the number of the slot
786 */
787 int
788 xsltAllocateExtra(xsltStylesheetPtr style)
789 {
790 return(style->extrasNr++);
791 }
792
793 /**
794 * xsltAllocateExtraCtxt:
795 * @ctxt: an XSLT transformation context
796 *
797 * Allocate an extra runtime information slot at run-time
798 * and return its number
799 * This make sure there is a slot ready in the transformation context
800 *
801 * Returns the number of the slot
802 */
803 int
804 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
805 {
806 if (ctxt->extrasNr >= ctxt->extrasMax) {
807 int i;
808 if (ctxt->extrasNr == 0) {
809 ctxt->extrasMax = 20;
810 ctxt->extras = (xsltRuntimeExtraPtr)
811 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
812 if (ctxt->extras == NULL) {
813 xmlGenericError(xmlGenericErrorContext,
814 "xsltAllocateExtraCtxt: out of memory\n");
815 ctxt->state = XSLT_STATE_ERROR;
816 return(0);
817 }
818 for (i = 0;i < ctxt->extrasMax;i++) {
819 ctxt->extras[i].info = NULL;
820 ctxt->extras[i].deallocate = NULL;
821 ctxt->extras[i].val.ptr = NULL;
822 }
823
824 } else {
825 xsltRuntimeExtraPtr tmp;
826
827 ctxt->extrasMax += 100;
828 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
829 ctxt->extrasMax * sizeof(xsltRuntimeExtra));
830 if (tmp == NULL) {
831 xmlGenericError(xmlGenericErrorContext,
832 "xsltAllocateExtraCtxt: out of memory\n");
833 ctxt->state = XSLT_STATE_ERROR;
834 return(0);
835 }
836 ctxt->extras = tmp;
837 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
838 ctxt->extras[i].info = NULL;
839 ctxt->extras[i].deallocate = NULL;
840 ctxt->extras[i].val.ptr = NULL;
841 }
842 }
843 }
844 return(ctxt->extrasNr++);
845 }
846
847 /**
848 * xsltFreeStylesheetList:
849 * @style: an XSLT stylesheet list
850 *
851 * Free up the memory allocated by the list @style
852 */
853 static void
854 xsltFreeStylesheetList(xsltStylesheetPtr style) {
855 xsltStylesheetPtr next;
856
857 while (style != NULL) {
858 next = style->next;
859 xsltFreeStylesheet(style);
860 style = next;
861 }
862 }
863
864 /**
865 * xsltCleanupStylesheetTree:
866 *
867 * @doc: the document-node
868 * @node: the element where the stylesheet is rooted at
869 *
870 * Actually @node need not be the document-element, but
871 * currently Libxslt does not support embedded stylesheets.
872 *
873 * Returns 0 if OK, -1 on API or internal errors.
874 */
875 static int
876 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
877 xmlNodePtr rootElem ATTRIBUTE_UNUSED)
878 {
879 #if 0 /* TODO: Currently disabled, since probably not needed. */
880 xmlNodePtr cur;
881
882 if ((doc == NULL) || (rootElem == NULL) ||
883 (rootElem->type != XML_ELEMENT_NODE) ||
884 (doc != rootElem->doc))
885 return(-1);
886
887 /*
888 * Cleanup was suggested by Aleksey Sanin:
889 * Clear the PSVI field to avoid problems if the
890 * node-tree of the stylesheet is intended to be used for
891 * further processing by the user (e.g. for compiling it
892 * once again - although not recommended).
893 */
894
895 cur = rootElem;
896 while (cur != NULL) {
897 if (cur->type == XML_ELEMENT_NODE) {
898 /*
899 * Clear the PSVI field.
900 */
901 cur->psvi = NULL;
902 if (cur->children) {
903 cur = cur->children;
904 continue;
905 }
906 }
907
908 leave_node:
909 if (cur == rootElem)
910 break;
911 if (cur->next != NULL)
912 cur = cur->next;
913 else {
914 cur = cur->parent;
915 if (cur == NULL)
916 break;
917 goto leave_node;
918 }
919 }
920 #endif /* #if 0 */
921 return(0);
922 }
923
924 /**
925 * xsltFreeStylesheet:
926 * @style: an XSLT stylesheet
927 *
928 * Free up the memory allocated by @style
929 */
930 void
931 xsltFreeStylesheet(xsltStylesheetPtr style)
932 {
933 if (style == NULL)
934 return;
935
936 #ifdef XSLT_REFACTORED
937 /*
938 * Start with a cleanup of the main stylesheet's doc.
939 */
940 if ((style->principal == style) && (style->doc))
941 xsltCleanupStylesheetTree(style->doc,
942 xmlDocGetRootElement(style->doc));
943 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
944 /*
945 * Restore changed ns-decls before freeing the document.
946 */
947 if ((style->doc != NULL) &&
948 XSLT_HAS_INTERNAL_NSMAP(style))
949 {
950 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
951 style->doc);
952 }
953 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
954 #else
955 /*
956 * Start with a cleanup of the main stylesheet's doc.
957 */
958 if ((style->parent == NULL) && (style->doc))
959 xsltCleanupStylesheetTree(style->doc,
960 xmlDocGetRootElement(style->doc));
961 #endif /* XSLT_REFACTORED */
962
963 xsltFreeKeys(style);
964 xsltFreeExts(style);
965 xsltFreeTemplateHashes(style);
966 xsltFreeDecimalFormatList(style);
967 xsltFreeTemplateList(style->templates);
968 xsltFreeAttributeSetsHashes(style);
969 xsltFreeNamespaceAliasHashes(style);
970 xsltFreeStylePreComps(style);
971 /*
972 * Free documents of all included stylsheet modules of this
973 * stylesheet level.
974 */
975 xsltFreeStyleDocuments(style);
976 /*
977 * TODO: Best time to shutdown extension stuff?
978 */
979 xsltShutdownExts(style);
980
981 if (style->variables != NULL)
982 xsltFreeStackElemList(style->variables);
983 if (style->cdataSection != NULL)
984 xmlHashFree(style->cdataSection, NULL);
985 if (style->stripSpaces != NULL)
986 xmlHashFree(style->stripSpaces, NULL);
987 if (style->nsHash != NULL)
988 xmlHashFree(style->nsHash, NULL);
989 if (style->exclPrefixTab != NULL)
990 xmlFree(style->exclPrefixTab);
991 if (style->method != NULL)
992 xmlFree(style->method);
993 if (style->methodURI != NULL)
994 xmlFree(style->methodURI);
995 if (style->version != NULL)
996 xmlFree(style->version);
997 if (style->encoding != NULL)
998 xmlFree(style->encoding);
999 if (style->doctypePublic != NULL)
1000 xmlFree(style->doctypePublic);
1001 if (style->doctypeSystem != NULL)
1002 xmlFree(style->doctypeSystem);
1003 if (style->mediaType != NULL)
1004 xmlFree(style->mediaType);
1005 if (style->attVTs)
1006 xsltFreeAVTList(style->attVTs);
1007 if (style->imports != NULL)
1008 xsltFreeStylesheetList(style->imports);
1009
1010 #ifdef XSLT_REFACTORED
1011 /*
1012 * If this is the principal stylesheet, then
1013 * free its internal data.
1014 */
1015 if (style->principal == style) {
1016 if (style->principalData) {
1017 xsltFreePrincipalStylesheetData(style->principalData);
1018 style->principalData = NULL;
1019 }
1020 }
1021 #endif
1022 /*
1023 * Better to free the main document of this stylesheet level
1024 * at the end - so here.
1025 */
1026 if (style->doc != NULL) {
1027 xmlFreeDoc(style->doc);
1028 }
1029
1030 #ifdef WITH_XSLT_DEBUG
1031 xsltGenericDebug(xsltGenericDebugContext,
1032 "freeing dictionary from stylesheet\n");
1033 #endif
1034 xmlDictFree(style->dict);
1035
1036 memset(style, -1, sizeof(xsltStylesheet));
1037 xmlFree(style);
1038 }
1039
1040 /************************************************************************
1041 * *
1042 * Parsing of an XSLT Stylesheet *
1043 * *
1044 ************************************************************************/
1045
1046 #ifdef XSLT_REFACTORED
1047 /*
1048 * This is now performed in an optimized way in xsltParseXSLTTemplate.
1049 */
1050 #else
1051 /**
1052 * xsltGetInheritedNsList:
1053 * @style: the stylesheet
1054 * @template: the template
1055 * @node: the current node
1056 *
1057 * Search all the namespace applying to a given element except the ones
1058 * from excluded output prefixes currently in scope. Initialize the
1059 * template inheritedNs list with it.
1060 *
1061 * Returns the number of entries found
1062 */
1063 static int
1064 xsltGetInheritedNsList(xsltStylesheetPtr style,
1065 xsltTemplatePtr template,
1066 xmlNodePtr node)
1067 {
1068 xmlNsPtr cur;
1069 xmlNsPtr *ret = NULL;
1070 int nbns = 0;
1071 int maxns = 10;
1072 int i;
1073
1074 if ((style == NULL) || (template == NULL) || (node == NULL) ||
1075 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1076 return(0);
1077 while (node != NULL) {
1078 if (node->type == XML_ELEMENT_NODE) {
1079 cur = node->nsDef;
1080 while (cur != NULL) {
1081 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1082 goto skip_ns;
1083
1084 if ((cur->prefix != NULL) &&
1085 (xsltCheckExtPrefix(style, cur->prefix)))
1086 goto skip_ns;
1087 /*
1088 * Check if this namespace was excluded.
1089 * Note that at this point only the exclusions defined
1090 * on the topmost stylesheet element are in the exclusion-list.
1091 */
1092 for (i = 0;i < style->exclPrefixNr;i++) {
1093 if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1094 goto skip_ns;
1095 }
1096 if (ret == NULL) {
1097 ret =
1098 (xmlNsPtr *) xmlMalloc((maxns + 1) *
1099 sizeof(xmlNsPtr));
1100 if (ret == NULL) {
1101 xmlGenericError(xmlGenericErrorContext,
1102 "xsltGetInheritedNsList : out of memory!\n");
1103 return(0);
1104 }
1105 ret[nbns] = NULL;
1106 }
1107 /*
1108 * Skip shadowed namespace bindings.
1109 */
1110 for (i = 0; i < nbns; i++) {
1111 if ((cur->prefix == ret[i]->prefix) ||
1112 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
1113 break;
1114 }
1115 if (i >= nbns) {
1116 if (nbns >= maxns) {
1117 maxns *= 2;
1118 ret = (xmlNsPtr *) xmlRealloc(ret,
1119 (maxns +
1120 1) *
1121 sizeof(xmlNsPtr));
1122 if (ret == NULL) {
1123 xmlGenericError(xmlGenericErrorContext,
1124 "xsltGetInheritedNsList : realloc failed!\n");
1125 return(0);
1126 }
1127 }
1128 ret[nbns++] = cur;
1129 ret[nbns] = NULL;
1130 }
1131 skip_ns:
1132 cur = cur->next;
1133 }
1134 }
1135 node = node->parent;
1136 }
1137 if (nbns != 0) {
1138 #ifdef WITH_XSLT_DEBUG_PARSING
1139 xsltGenericDebug(xsltGenericDebugContext,
1140 "template has %d inherited namespaces\n", nbns);
1141 #endif
1142 template->inheritedNsNr = nbns;
1143 template->inheritedNs = ret;
1144 }
1145 return (nbns);
1146 }
1147 #endif /* else of XSLT_REFACTORED */
1148
1149 /**
1150 * xsltParseStylesheetOutput:
1151 * @style: the XSLT stylesheet
1152 * @cur: the "output" element
1153 *
1154 * parse an XSLT stylesheet output element and record
1155 * information related to the stylesheet output
1156 */
1157
1158 void
1159 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
1160 {
1161 xmlChar *elements,
1162 *prop;
1163 xmlChar *element,
1164 *end;
1165
1166 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1167 return;
1168
1169 prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1170 if (prop != NULL) {
1171 if (style->version != NULL)
1172 xmlFree(style->version);
1173 style->version = prop;
1174 }
1175
1176 prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1177 if (prop != NULL) {
1178 if (style->encoding != NULL)
1179 xmlFree(style->encoding);
1180 style->encoding = prop;
1181 }
1182
1183 /* relaxed to support xt:document
1184 * TODO KB: What does "relaxed to support xt:document" mean?
1185 */
1186 prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1187 if (prop != NULL) {
1188 const xmlChar *URI;
1189
1190 if (style->method != NULL)
1191 xmlFree(style->method);
1192 style->method = NULL;
1193 if (style->methodURI != NULL)
1194 xmlFree(style->methodURI);
1195 style->methodURI = NULL;
1196
1197 /*
1198 * TODO: Don't use xsltGetQNameURI().
1199 */
1200 URI = xsltGetQNameURI(cur, &prop);
1201 if (prop == NULL) {
1202 if (style != NULL) style->errors++;
1203 } else if (URI == NULL) {
1204 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1205 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1206 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1207 style->method = prop;
1208 } else {
1209 xsltTransformError(NULL, style, cur,
1210 "invalid value for method: %s\n", prop);
1211 if (style != NULL) style->warnings++;
1212 }
1213 } else {
1214 style->method = prop;
1215 style->methodURI = xmlStrdup(URI);
1216 }
1217 }
1218
1219 prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1220 if (prop != NULL) {
1221 if (style->doctypeSystem != NULL)
1222 xmlFree(style->doctypeSystem);
1223 style->doctypeSystem = prop;
1224 }
1225
1226 prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1227 if (prop != NULL) {
1228 if (style->doctypePublic != NULL)
1229 xmlFree(style->doctypePublic);
1230 style->doctypePublic = prop;
1231 }
1232
1233 prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1234 if (prop != NULL) {
1235 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1236 style->standalone = 1;
1237 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1238 style->standalone = 0;
1239 } else {
1240 xsltTransformError(NULL, style, cur,
1241 "invalid value for standalone: %s\n", prop);
1242 style->errors++;
1243 }
1244 xmlFree(prop);
1245 }
1246
1247 prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1248 if (prop != NULL) {
1249 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1250 style->indent = 1;
1251 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1252 style->indent = 0;
1253 } else {
1254 xsltTransformError(NULL, style, cur,
1255 "invalid value for indent: %s\n", prop);
1256 style->errors++;
1257 }
1258 xmlFree(prop);
1259 }
1260
1261 prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1262 if (prop != NULL) {
1263 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1264 style->omitXmlDeclaration = 1;
1265 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1266 style->omitXmlDeclaration = 0;
1267 } else {
1268 xsltTransformError(NULL, style, cur,
1269 "invalid value for omit-xml-declaration: %s\n",
1270 prop);
1271 style->errors++;
1272 }
1273 xmlFree(prop);
1274 }
1275
1276 elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1277 NULL);
1278 if (elements != NULL) {
1279 if (style->cdataSection == NULL)
1280 style->cdataSection = xmlHashCreate(10);
1281 if (style->cdataSection == NULL)
1282 return;
1283
1284 element = elements;
1285 while (*element != 0) {
1286 while (IS_BLANK(*element))
1287 element++;
1288 if (*element == 0)
1289 break;
1290 end = element;
1291 while ((*end != 0) && (!IS_BLANK(*end)))
1292 end++;
1293 element = xmlStrndup(element, end - element);
1294 if (element) {
1295 #ifdef WITH_XSLT_DEBUG_PARSING
1296 xsltGenericDebug(xsltGenericDebugContext,
1297 "add cdata section output element %s\n",
1298 element);
1299 #endif
1300 if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1301 xsltTransformError(NULL, style, cur,
1302 "Attribute 'cdata-section-elements': The value "
1303 "'%s' is not a valid QName.\n", element);
1304 xmlFree(element);
1305 style->errors++;
1306 } else {
1307 const xmlChar *URI;
1308
1309 /*
1310 * TODO: Don't use xsltGetQNameURI().
1311 */
1312 URI = xsltGetQNameURI(cur, &element);
1313 if (element == NULL) {
1314 /*
1315 * TODO: We'll report additionally an error
1316 * via the stylesheet's error handling.
1317 */
1318 xsltTransformError(NULL, style, cur,
1319 "Attribute 'cdata-section-elements': The value "
1320 "'%s' is not a valid QName.\n", element);
1321 style->errors++;
1322 } else {
1323 xmlNsPtr ns;
1324
1325 /*
1326 * XSLT-1.0 "Each QName is expanded into an
1327 * expanded-name using the namespace declarations in
1328 * effect on the xsl:output element in which the QName
1329 * occurs; if there is a default namespace, it is used
1330 * for QNames that do not have a prefix"
1331 * NOTE: Fix of bug #339570.
1332 */
1333 if (URI == NULL) {
1334 ns = xmlSearchNs(style->doc, cur, NULL);
1335 if (ns != NULL)
1336 URI = ns->href;
1337 }
1338 xmlHashAddEntry2(style->cdataSection, element, URI,
1339 (void *) "cdata");
1340 xmlFree(element);
1341 }
1342 }
1343 }
1344 element = end;
1345 }
1346 xmlFree(elements);
1347 }
1348
1349 prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1350 if (prop != NULL) {
1351 if (style->mediaType)
1352 xmlFree(style->mediaType);
1353 style->mediaType = prop;
1354 }
1355 if (cur->children != NULL) {
1356 xsltParseContentError(style, cur->children);
1357 }
1358 }
1359
1360 /**
1361 * xsltParseStylesheetDecimalFormat:
1362 * @style: the XSLT stylesheet
1363 * @cur: the "decimal-format" element
1364 *
1365 * <!-- Category: top-level-element -->
1366 * <xsl:decimal-format
1367 * name = qname, decimal-separator = char, grouping-separator = char,
1368 * infinity = string, minus-sign = char, NaN = string, percent = char
1369 * per-mille = char, zero-digit = char, digit = char,
1370 * pattern-separator = char />
1371 *
1372 * parse an XSLT stylesheet decimal-format element and
1373 * and record the formatting characteristics
1374 */
1375 static void
1376 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
1377 {
1378 xmlChar *prop;
1379 xsltDecimalFormatPtr format;
1380 xsltDecimalFormatPtr iter;
1381
1382 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1383 return;
1384
1385 format = style->decimalFormat;
1386
1387 prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1388 if (prop != NULL) {
1389 format = xsltDecimalFormatGetByName(style, prop);
1390 if (format != NULL) {
1391 xsltTransformError(NULL, style, cur,
1392 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1393 if (style != NULL) style->warnings++;
1394 return;
1395 }
1396 format = xsltNewDecimalFormat(prop);
1397 if (format == NULL) {
1398 xsltTransformError(NULL, style, cur,
1399 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1400 if (style != NULL) style->errors++;
1401 return;
1402 }
1403 /* Append new decimal-format structure */
1404 for (iter = style->decimalFormat; iter->next; iter = iter->next)
1405 ;
1406 if (iter)
1407 iter->next = format;
1408 }
1409
1410 prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1411 if (prop != NULL) {
1412 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1413 format->decimalPoint = prop;
1414 }
1415
1416 prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1417 if (prop != NULL) {
1418 if (format->grouping != NULL) xmlFree(format->grouping);
1419 format->grouping = prop;
1420 }
1421
1422 prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1423 if (prop != NULL) {
1424 if (format->infinity != NULL) xmlFree(format->infinity);
1425 format->infinity = prop;
1426 }
1427
1428 prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1429 if (prop != NULL) {
1430 if (format->minusSign != NULL) xmlFree(format->minusSign);
1431 format->minusSign = prop;
1432 }
1433
1434 prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1435 if (prop != NULL) {
1436 if (format->noNumber != NULL) xmlFree(format->noNumber);
1437 format->noNumber = prop;
1438 }
1439
1440 prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1441 if (prop != NULL) {
1442 if (format->percent != NULL) xmlFree(format->percent);
1443 format->percent = prop;
1444 }
1445
1446 prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1447 if (prop != NULL) {
1448 if (format->permille != NULL) xmlFree(format->permille);
1449 format->permille = prop;
1450 }
1451
1452 prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1453 if (prop != NULL) {
1454 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1455 format->zeroDigit = prop;
1456 }
1457
1458 prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1459 if (prop != NULL) {
1460 if (format->digit != NULL) xmlFree(format->digit);
1461 format->digit = prop;
1462 }
1463
1464 prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1465 if (prop != NULL) {
1466 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1467 format->patternSeparator = prop;
1468 }
1469 if (cur->children != NULL) {
1470 xsltParseContentError(style, cur->children);
1471 }
1472 }
1473
1474 /**
1475 * xsltParseStylesheetPreserveSpace:
1476 * @style: the XSLT stylesheet
1477 * @cur: the "preserve-space" element
1478 *
1479 * parse an XSLT stylesheet preserve-space element and record
1480 * elements needing preserving
1481 */
1482
1483 static void
1484 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1485 xmlChar *elements;
1486 xmlChar *element, *end;
1487
1488 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1489 return;
1490
1491 elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1492 if (elements == NULL) {
1493 xsltTransformError(NULL, style, cur,
1494 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1495 if (style != NULL) style->warnings++;
1496 return;
1497 }
1498
1499 if (style->stripSpaces == NULL)
1500 style->stripSpaces = xmlHashCreate(10);
1501 if (style->stripSpaces == NULL)
1502 return;
1503
1504 element = elements;
1505 while (*element != 0) {
1506 while (IS_BLANK(*element)) element++;
1507 if (*element == 0)
1508 break;
1509 end = element;
1510 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1511 element = xmlStrndup(element, end - element);
1512 if (element) {
1513 #ifdef WITH_XSLT_DEBUG_PARSING
1514 xsltGenericDebug(xsltGenericDebugContext,
1515 "add preserved space element %s\n", element);
1516 #endif
1517 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1518 style->stripAll = -1;
1519 } else {
1520 const xmlChar *URI;
1521
1522 /*
1523 * TODO: Don't use xsltGetQNameURI().
1524 */
1525 URI = xsltGetQNameURI(cur, &element);
1526
1527 xmlHashAddEntry2(style->stripSpaces, element, URI,
1528 (xmlChar *) "preserve");
1529 }
1530 xmlFree(element);
1531 }
1532 element = end;
1533 }
1534 xmlFree(elements);
1535 if (cur->children != NULL) {
1536 xsltParseContentError(style, cur->children);
1537 }
1538 }
1539
1540 #ifdef XSLT_REFACTORED
1541 #else
1542 /**
1543 * xsltParseStylesheetExtPrefix:
1544 * @style: the XSLT stylesheet
1545 * @template: the "extension-element-prefixes" prefix
1546 *
1547 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1548 * and register the namespaces of extension instruction.
1549 * SPEC "A namespace is designated as an extension namespace by using
1550 * an extension-element-prefixes attribute on:
1551 * 1) an xsl:stylesheet element
1552 * 2) an xsl:extension-element-prefixes attribute on a
1553 * literal result element
1554 * 3) an extension instruction."
1555 */
1556 static void
1557 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1558 int isXsltElem) {
1559 xmlChar *prefixes;
1560 xmlChar *prefix, *end;
1561
1562 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1563 return;
1564
1565 if (isXsltElem) {
1566 /* For xsl:stylesheet/xsl:transform. */
1567 prefixes = xmlGetNsProp(cur,
1568 (const xmlChar *)"extension-element-prefixes", NULL);
1569 } else {
1570 /* For literal result elements and extension instructions. */
1571 prefixes = xmlGetNsProp(cur,
1572 (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1573 }
1574 if (prefixes == NULL) {
1575 return;
1576 }
1577
1578 prefix = prefixes;
1579 while (*prefix != 0) {
1580 while (IS_BLANK(*prefix)) prefix++;
1581 if (*prefix == 0)
1582 break;
1583 end = prefix;
1584 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1585 prefix = xmlStrndup(prefix, end - prefix);
1586 if (prefix) {
1587 xmlNsPtr ns;
1588
1589 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1590 ns = xmlSearchNs(style->doc, cur, NULL);
1591 else
1592 ns = xmlSearchNs(style->doc, cur, prefix);
1593 if (ns == NULL) {
1594 xsltTransformError(NULL, style, cur,
1595 "xsl:extension-element-prefix : undefined namespace %s\n",
1596 prefix);
1597 if (style != NULL) style->warnings++;
1598 } else {
1599 #ifdef WITH_XSLT_DEBUG_PARSING
1600 xsltGenericDebug(xsltGenericDebugContext,
1601 "add extension prefix %s\n", prefix);
1602 #endif
1603 xsltRegisterExtPrefix(style, prefix, ns->href);
1604 }
1605 xmlFree(prefix);
1606 }
1607 prefix = end;
1608 }
1609 xmlFree(prefixes);
1610 }
1611 #endif /* else of XSLT_REFACTORED */
1612
1613 /**
1614 * xsltParseStylesheetStripSpace:
1615 * @style: the XSLT stylesheet
1616 * @cur: the "strip-space" element
1617 *
1618 * parse an XSLT stylesheet's strip-space element and record
1619 * the elements needing stripping
1620 */
1621
1622 static void
1623 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1624 xmlChar *elements;
1625 xmlChar *element, *end;
1626
1627 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1628 return;
1629
1630 elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1631 if (elements == NULL) {
1632 xsltTransformError(NULL, style, cur,
1633 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1634 if (style != NULL) style->warnings++;
1635 return;
1636 }
1637
1638 if (style->stripSpaces == NULL)
1639 style->stripSpaces = xmlHashCreate(10);
1640 if (style->stripSpaces == NULL)
1641 return;
1642
1643 element = elements;
1644 while (*element != 0) {
1645 while (IS_BLANK(*element)) element++;
1646 if (*element == 0)
1647 break;
1648 end = element;
1649 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1650 element = xmlStrndup(element, end - element);
1651 if (element) {
1652 #ifdef WITH_XSLT_DEBUG_PARSING
1653 xsltGenericDebug(xsltGenericDebugContext,
1654 "add stripped space element %s\n", element);
1655 #endif
1656 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1657 style->stripAll = 1;
1658 } else {
1659 const xmlChar *URI;
1660
1661 /*
1662 * TODO: Don't use xsltGetQNameURI().
1663 */
1664 URI = xsltGetQNameURI(cur, &element);
1665
1666 xmlHashAddEntry2(style->stripSpaces, element, URI,
1667 (xmlChar *) "strip");
1668 }
1669 xmlFree(element);
1670 }
1671 element = end;
1672 }
1673 xmlFree(elements);
1674 if (cur->children != NULL) {
1675 xsltParseContentError(style, cur->children);
1676 }
1677 }
1678
1679 #ifdef XSLT_REFACTORED
1680 #else
1681 /**
1682 * xsltParseStylesheetExcludePrefix:
1683 * @style: the XSLT stylesheet
1684 * @cur: the current point in the stylesheet
1685 *
1686 * parse an XSLT stylesheet exclude prefix and record
1687 * namespaces needing stripping
1688 *
1689 * Returns the number of Excluded prefixes added at that level
1690 */
1691
1692 static int
1693 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1694 int isXsltElem)
1695 {
1696 int nb = 0;
1697 xmlChar *prefixes;
1698 xmlChar *prefix, *end;
1699
1700 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1701 return(0);
1702
1703 if (isXsltElem)
1704 prefixes = xmlGetNsProp(cur,
1705 (const xmlChar *)"exclude-result-prefixes", NULL);
1706 else
1707 prefixes = xmlGetNsProp(cur,
1708 (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1709
1710 if (prefixes == NULL) {
1711 return(0);
1712 }
1713
1714 prefix = prefixes;
1715 while (*prefix != 0) {
1716 while (IS_BLANK(*prefix)) prefix++;
1717 if (*prefix == 0)
1718 break;
1719 end = prefix;
1720 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1721 prefix = xmlStrndup(prefix, end - prefix);
1722 if (prefix) {
1723 xmlNsPtr ns;
1724
1725 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1726 ns = xmlSearchNs(style->doc, cur, NULL);
1727 else
1728 ns = xmlSearchNs(style->doc, cur, prefix);
1729 if (ns == NULL) {
1730 xsltTransformError(NULL, style, cur,
1731 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1732 prefix);
1733 if (style != NULL) style->warnings++;
1734 } else {
1735 if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
1736 #ifdef WITH_XSLT_DEBUG_PARSING
1737 xsltGenericDebug(xsltGenericDebugContext,
1738 "exclude result prefix %s\n", prefix);
1739 #endif
1740 nb++;
1741 }
1742 }
1743 xmlFree(prefix);
1744 }
1745 prefix = end;
1746 }
1747 xmlFree(prefixes);
1748 return(nb);
1749 }
1750 #endif /* else of XSLT_REFACTORED */
1751
1752 #ifdef XSLT_REFACTORED
1753
1754 /*
1755 * xsltTreeEnsureXMLDecl:
1756 * @doc: the doc
1757 *
1758 * BIG NOTE:
1759 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1760 * Ensures that there is an XML namespace declaration on the doc.
1761 *
1762 * Returns the XML ns-struct or NULL on API and internal errors.
1763 */
1764 static xmlNsPtr
1765 xsltTreeEnsureXMLDecl(xmlDocPtr doc)
1766 {
1767 if (doc == NULL)
1768 return (NULL);
1769 if (doc->oldNs != NULL)
1770 return (doc->oldNs);
1771 {
1772 xmlNsPtr ns;
1773 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1774 if (ns == NULL) {
1775 xmlGenericError(xmlGenericErrorContext,
1776 "xsltTreeEnsureXMLDecl: Failed to allocate "
1777 "the XML namespace.\n");
1778 return (NULL);
1779 }
1780 memset(ns, 0, sizeof(xmlNs));
1781 ns->type = XML_LOCAL_NAMESPACE;
1782 /*
1783 * URGENT TODO: revisit this.
1784 */
1785 #ifdef LIBXML_NAMESPACE_DICT
1786 if (doc->dict)
1787 ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
1788 else
1789 ns->href = xmlStrdup(XML_XML_NAMESPACE);
1790 #else
1791 ns->href = xmlStrdup(XML_XML_NAMESPACE);
1792 #endif
1793 ns->prefix = xmlStrdup((const xmlChar *)"xml");
1794 doc->oldNs = ns;
1795 return (ns);
1796 }
1797 }
1798
1799 /*
1800 * xsltTreeAcquireStoredNs:
1801 * @doc: the doc
1802 * @nsName: the namespace name
1803 * @prefix: the prefix
1804 *
1805 * BIG NOTE:
1806 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1807 * Creates or reuses an xmlNs struct on doc->oldNs with
1808 * the given prefix and namespace name.
1809 *
1810 * Returns the aquired ns struct or NULL in case of an API
1811 * or internal error.
1812 */
1813 static xmlNsPtr
1814 xsltTreeAcquireStoredNs(xmlDocPtr doc,
1815 const xmlChar *nsName,
1816 const xmlChar *prefix)
1817 {
1818 xmlNsPtr ns;
1819
1820 if (doc == NULL)
1821 return (NULL);
1822 if (doc->oldNs != NULL)
1823 ns = doc->oldNs;
1824 else
1825 ns = xsltTreeEnsureXMLDecl(doc);
1826 if (ns == NULL)
1827 return (NULL);
1828 if (ns->next != NULL) {
1829 /* Reuse. */
1830 ns = ns->next;
1831 while (ns != NULL) {
1832 if ((ns->prefix == NULL) != (prefix == NULL)) {
1833 /* NOP */
1834 } else if (prefix == NULL) {
1835 if (xmlStrEqual(ns->href, nsName))
1836 return (ns);
1837 } else {
1838 if ((ns->prefix[0] == prefix[0]) &&
1839 xmlStrEqual(ns->prefix, prefix) &&
1840 xmlStrEqual(ns->href, nsName))
1841 return (ns);
1842
1843 }
1844 if (ns->next == NULL)
1845 break;
1846 ns = ns->next;
1847 }
1848 }
1849 /* Create. */
1850 ns->next = xmlNewNs(NULL, nsName, prefix);
1851 return (ns->next);
1852 }
1853
1854 /**
1855 * xsltLREBuildEffectiveNs:
1856 *
1857 * Apply ns-aliasing on the namespace of the given @elem and
1858 * its attributes.
1859 */
1860 static int
1861 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
1862 xmlNodePtr elem)
1863 {
1864 xmlNsPtr ns;
1865 xsltNsAliasPtr alias;
1866
1867 if ((cctxt == NULL) || (elem == NULL))
1868 return(-1);
1869 if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
1870 return(0);
1871
1872 alias = cctxt->nsAliases;
1873 while (alias != NULL) {
1874 if ( /* If both namespaces are NULL... */
1875 ( (elem->ns == NULL) &&
1876 ((alias->literalNs == NULL) ||
1877 (alias->literalNs->href == NULL)) ) ||
1878 /* ... or both namespace are equal */
1879 ( (elem->ns != NULL) &&
1880 (alias->literalNs != NULL) &&
1881 xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1882 {
1883 if ((alias->targetNs != NULL) &&
1884 (alias->targetNs->href != NULL))
1885 {
1886 /*
1887 * Convert namespace.
1888 */
1889 if (elem->doc == alias->docOfTargetNs) {
1890 /*
1891 * This is the nice case: same docs.
1892 * This will eventually assign a ns-decl which
1893 * is shadowed, but this has no negative effect on
1894 * the generation of the result tree.
1895 */
1896 elem->ns = alias->targetNs;
1897 } else {
1898 /*
1899 * This target xmlNs originates from a different
1900 * stylesheet tree. Try to locate it in the
1901 * in-scope namespaces.
1902 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1903 */
1904 ns = xmlSearchNs(elem->doc, elem,
1905 alias->targetNs->prefix);
1906 /*
1907 * If no matching ns-decl found, then assign a
1908 * ns-decl stored in xmlDoc.
1909 */
1910 if ((ns == NULL) ||
1911 (! xmlStrEqual(ns->href, alias->targetNs->href)))
1912 {
1913 /*
1914 * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1915 * is not very efficient, but currently I don't
1916 * see an other way of *safely* changing a node's
1917 * namespace, since the xmlNs struct in
1918 * alias->targetNs might come from an other
1919 * stylesheet tree. So we need to anchor it in the
1920 * current document, without adding it to the tree,
1921 * which would otherwise change the in-scope-ns
1922 * semantic of the tree.
1923 */
1924 ns = xsltTreeAcquireStoredNs(elem->doc,
1925 alias->targetNs->href,
1926 alias->targetNs->prefix);
1927
1928 if (ns == NULL) {
1929 xsltTransformError(NULL, cctxt->style, elem,
1930 "Internal error in "
1931 "xsltLREBuildEffectiveNs(): "
1932 "failed to acquire a stored "
1933 "ns-declaration.\n");
1934 cctxt->style->errors++;
1935 return(-1);
1936
1937 }
1938 }
1939 elem->ns = ns;
1940 }
1941 } else {
1942 /*
1943 * Move into or leave in the NULL namespace.
1944 */
1945 elem->ns = NULL;
1946 }
1947 break;
1948 }
1949 alias = alias->next;
1950 }
1951 /*
1952 * Same with attributes of literal result elements.
1953 */
1954 if (elem->properties != NULL) {
1955 xmlAttrPtr attr = elem->properties;
1956
1957 while (attr != NULL) {
1958 if (attr->ns == NULL) {
1959 attr = attr->next;
1960 continue;
1961 }
1962 alias = cctxt->nsAliases;
1963 while (alias != NULL) {
1964 if ( /* If both namespaces are NULL... */
1965 ( (elem->ns == NULL) &&
1966 ((alias->literalNs == NULL) ||
1967 (alias->literalNs->href == NULL)) ) ||
1968 /* ... or both namespace are equal */
1969 ( (elem->ns != NULL) &&
1970 (alias->literalNs != NULL) &&
1971 xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1972 {
1973 if ((alias->targetNs != NULL) &&
1974 (alias->targetNs->href != NULL))
1975 {
1976 if (elem->doc == alias->docOfTargetNs) {
1977 elem->ns = alias->targetNs;
1978 } else {
1979 ns = xmlSearchNs(elem->doc, elem,
1980 alias->targetNs->prefix);
1981 if ((ns == NULL) ||
1982 (! xmlStrEqual(ns->href, alias->targetNs->href)))
1983 {
1984 ns = xsltTreeAcquireStoredNs(elem->doc,
1985 alias->targetNs->href,
1986 alias->targetNs->prefix);
1987
1988 if (ns == NULL) {
1989 xsltTransformError(NULL, cctxt->style, elem,
1990 "Internal error in "
1991 "xsltLREBuildEffectiveNs(): "
1992 "failed to acquire a stored "
1993 "ns-declaration.\n");
1994 cctxt->style->errors++;
1995 return(-1);
1996
1997 }
1998 }
1999 elem->ns = ns;
2000 }
2001 } else {
2002 /*
2003 * Move into or leave in the NULL namespace.
2004 */
2005 elem->ns = NULL;
2006 }
2007 break;
2008 }
2009 alias = alias->next;
2010 }
2011
2012 attr = attr->next;
2013 }
2014 }
2015 return(0);
2016 }
2017
2018 /**
2019 * xsltLREBuildEffectiveNsNodes:
2020 *
2021 * Computes the effective namespaces nodes for a literal result
2022 * element.
2023 * @effectiveNs is the set of effective ns-nodes
2024 * on the literal result element, which will be added to the result
2025 * element if not already existing in the result tree.
2026 * This means that excluded namespaces (via exclude-result-prefixes,
2027 * extension-element-prefixes and the XSLT namespace) not added
2028 * to the set.
2029 * Namespace-aliasing was applied on the @effectiveNs.
2030 */
2031 static int
2032 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2033 xsltStyleItemLRElementInfoPtr item,
2034 xmlNodePtr elem,
2035 int isLRE)
2036 {
2037 xmlNsPtr ns, tmpns;
2038 xsltEffectiveNsPtr effNs, lastEffNs = NULL;
2039 int i, j, holdByElem;
2040 xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
2041 xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
2042
2043 if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
2044 (item == NULL) || (item->effectiveNs != NULL))
2045 return(-1);
2046
2047 if (item->inScopeNs == NULL)
2048 return(0);
2049
2050 extElemNs = cctxt->inode->extElemNs;
2051 exclResultNs = cctxt->inode->exclResultNs;
2052
2053 for (i = 0; i < item->inScopeNs->totalNumber; i++) {
2054 ns = item->inScopeNs->list[i];
2055 /*
2056 * Skip namespaces designated as excluded namespaces
2057 * -------------------------------------------------
2058 *
2059 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2060 * which are target namespaces of namespace-aliases
2061 * regardless if designated as excluded.
2062 *
2063 * Exclude the XSLT namespace.
2064 */
2065 if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2066 goto skip_ns;
2067
2068 /*
2069 * Apply namespace aliasing
2070 * ------------------------
2071 *
2072 * SPEC XSLT 2.0
2073 * "- A namespace node whose string value is a literal namespace
2074 * URI is not copied to the result tree.
2075 * - A namespace node whose string value is a target namespace URI
2076 * is copied to the result tree, whether or not the URI
2077 * identifies an excluded namespace."
2078 *
2079 * NOTE: The ns-aliasing machanism is non-cascading.
2080 * (checked with Saxon, Xalan and MSXML .NET).
2081 * URGENT TODO: is style->nsAliases the effective list of
2082 * ns-aliases, or do we need to lookup the whole
2083 * import-tree?
2084 * TODO: Get rid of import-tree lookup.
2085 */
2086 if (cctxt->hasNsAliases) {
2087 xsltNsAliasPtr alias;
2088 /*
2089 * First check for being a target namespace.
2090 */
2091 alias = cctxt->nsAliases;
2092 do {
2093 /*
2094 * TODO: Is xmlns="" handled already?
2095 */
2096 if ((alias->targetNs != NULL) &&
2097 (xmlStrEqual(alias->targetNs->href, ns->href)))
2098 {
2099 /*
2100 * Recognized as a target namespace; use it regardless
2101 * if excluded otherwise.
2102 */
2103 goto add_effective_ns;
2104 }
2105 alias = alias->next;
2106 } while (alias != NULL);
2107
2108 alias = cctxt->nsAliases;
2109 do {
2110 /*
2111 * TODO: Is xmlns="" handled already?
2112 */
2113 if ((alias->literalNs != NULL) &&
2114 (xmlStrEqual(alias->literalNs->href, ns->href)))
2115 {
2116 /*
2117 * Recognized as an namespace alias; do not use it.
2118 */
2119 goto skip_ns;
2120 }
2121 alias = alias->next;
2122 } while (alias != NULL);
2123 }
2124
2125 /*
2126 * Exclude excluded result namespaces.
2127 */
2128 if (exclResultNs) {
2129 for (j = 0; j < exclResultNs->number; j++)
2130 if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
2131 goto skip_ns;
2132 }
2133 /*
2134 * Exclude extension-element namespaces.
2135 */
2136 if (extElemNs) {
2137 for (j = 0; j < extElemNs->number; j++)
2138 if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
2139 goto skip_ns;
2140 }
2141
2142 add_effective_ns:
2143 /*
2144 * OPTIMIZE TODO: This information may not be needed.
2145 */
2146 if (isLRE && (elem->nsDef != NULL)) {
2147 holdByElem = 0;
2148 tmpns = elem->nsDef;
2149 do {
2150 if (tmpns == ns) {
2151 holdByElem = 1;
2152 break;
2153 }
2154 tmpns = tmpns->next;
2155 } while (tmpns != NULL);
2156 } else
2157 holdByElem = 0;
2158
2159
2160 /*
2161 * Add the effective namespace declaration.
2162 */
2163 effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
2164 if (effNs == NULL) {
2165 xsltTransformError(NULL, cctxt->style, elem,
2166 "Internal error in xsltLREBuildEffectiveNs(): "
2167 "failed to allocate memory.\n");
2168 cctxt->style->errors++;
2169 return(-1);
2170 }
2171 if (cctxt->psData->effectiveNs == NULL) {
2172 cctxt->psData->effectiveNs = effNs;
2173 effNs->nextInStore = NULL;
2174 } else {
2175 effNs->nextInStore = cctxt->psData->effectiveNs;
2176 cctxt->psData->effectiveNs = effNs;
2177 }
2178
2179 effNs->next = NULL;
2180 effNs->prefix = ns->prefix;
2181 effNs->nsName = ns->href;
2182 effNs->holdByElem = holdByElem;
2183
2184 if (lastEffNs == NULL)
2185 item->effectiveNs = effNs;
2186 else
2187 lastEffNs->next = effNs;
2188 lastEffNs = effNs;
2189
2190 skip_ns:
2191 {}
2192 }
2193 return(0);
2194 }
2195
2196
2197 /**
2198 * xsltLREInfoCreate:
2199 *
2200 * @isLRE: indicates if the given @elem is a literal result element
2201 *
2202 * Creates a new info for a literal result element.
2203 */
2204 static int
2205 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
2206 xmlNodePtr elem,
2207 int isLRE)
2208 {
2209 xsltStyleItemLRElementInfoPtr item;
2210
2211 if ((cctxt == NULL) || (cctxt->inode == NULL))
2212 return(-1);
2213
2214 item = (xsltStyleItemLRElementInfoPtr)
2215 xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
2216 if (item == NULL) {
2217 xsltTransformError(NULL, cctxt->style, NULL,
2218 "Internal error in xsltLREInfoCreate(): "
2219 "memory allocation failed.\n");
2220 cctxt->style->errors++;
2221 return(-1);
2222 }
2223 memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
2224 item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
2225 /*
2226 * Store it in the stylesheet.
2227 */
2228 item->next = cctxt->style->preComps;
2229 cctxt->style->preComps = (xsltElemPreCompPtr) item;
2230 /*
2231 * @inScopeNs are used for execution of XPath expressions
2232 * in AVTs.
2233 */
2234 item->inScopeNs = cctxt->inode->inScopeNs;
2235
2236 if (elem)
2237 xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
2238
2239 cctxt->inode->litResElemInfo = item;
2240 cctxt->inode->nsChanged = 0;
2241 cctxt->maxLREs++;
2242 return(0);
2243 }
2244
2245 /**
2246 * xsltCompilerVarInfoPush:
2247 * @cctxt: the compilation context
2248 *
2249 * Pushes a new var/param info onto the stack.
2250 *
2251 * Returns the acquired variable info.
2252 */
2253 static xsltVarInfoPtr
2254 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
2255 xmlNodePtr inst,
2256 const xmlChar *name,
2257 const xmlChar *nsName)
2258 {
2259 xsltVarInfoPtr ivar;
2260
2261 if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
2262 ivar = cctxt->ivar->next;
2263 } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
2264 ivar = cctxt->ivars;
2265 } else {
2266 ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
2267 if (ivar == NULL) {
2268 xsltTransformError(NULL, cctxt->style, inst,
2269 "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2270 cctxt->style->errors++;
2271 return(NULL);
2272 }
2273 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2274 if (cctxt->ivars == NULL) {
2275 cctxt->ivars = ivar;
2276 ivar->prev = NULL;
2277 } else {
2278 cctxt->ivar->next = ivar;
2279 ivar->prev = cctxt->ivar;
2280 }
2281 cctxt->ivar = ivar;
2282 ivar->next = NULL;
2283 }
2284 ivar->depth = cctxt->depth;
2285 ivar->name = name;
2286 ivar->nsName = nsName;
2287 return(ivar);
2288 }
2289
2290 /**
2291 * xsltCompilerVarInfoPop:
2292 * @cctxt: the compilation context
2293 *
2294 * Pops all var/param infos from the stack, which
2295 * have the current depth.
2296 */
2297 static void
2298 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
2299 {
2300
2301 while ((cctxt->ivar != NULL) &&
2302 (cctxt->ivar->depth > cctxt->depth))
2303 {
2304 cctxt->ivar = cctxt->ivar->prev;
2305 }
2306 }
2307
2308 /*
2309 * xsltCompilerNodePush:
2310 *
2311 * @cctxt: the compilation context
2312 * @node: the node to be pushed (this can also be the doc-node)
2313 *
2314 *
2315 *
2316 * Returns the current node info structure or
2317 * NULL in case of an internal error.
2318 */
2319 static xsltCompilerNodeInfoPtr
2320 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2321 {
2322 xsltCompilerNodeInfoPtr inode, iprev;
2323
2324 if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
2325 inode = cctxt->inode->next;
2326 } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
2327 inode = cctxt->inodeList;
2328 } else {
2329 /*
2330 * Create a new node-info.
2331 */
2332 inode = (xsltCompilerNodeInfoPtr)
2333 xmlMalloc(sizeof(xsltCompilerNodeInfo));
2334 if (inode == NULL) {
2335 xsltTransformError(NULL, cctxt->style, NULL,
2336 "xsltCompilerNodePush: malloc failed.\n");
2337 return(NULL);
2338 }
2339 memset(inode, 0, sizeof(xsltCompilerNodeInfo));
2340 if (cctxt->inodeList == NULL)
2341 cctxt->inodeList = inode;
2342 else {
2343 cctxt->inodeLast->next = inode;
2344 inode->prev = cctxt->inodeLast;
2345 }
2346 cctxt->inodeLast = inode;
2347 cctxt->maxNodeInfos++;
2348 if (cctxt->inode == NULL) {
2349 cctxt->inode = inode;
2350 /*
2351 * Create an initial literal result element info for
2352 * the root of the stylesheet.
2353 */
2354 xsltLREInfoCreate(cctxt, NULL, 0);
2355 }
2356 }
2357 cctxt->depth++;
2358 cctxt->inode = inode;
2359 /*
2360 * REVISIT TODO: Keep the reset always complete.
2361 * NOTE: Be carefull with the @node, since it might be
2362 * a doc-node.
2363 */
2364 inode->node = node;
2365 inode->depth = cctxt->depth;
2366 inode->templ = NULL;
2367 inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
2368 inode->type = 0;
2369 inode->item = NULL;
2370 inode->curChildType = 0;
2371 inode->extContentHandled = 0;
2372 inode->isRoot = 0;
2373
2374 if (inode->prev != NULL) {
2375 iprev = inode->prev;
2376 /*
2377 * Inherit the following information:
2378 * ---------------------------------
2379 *
2380 * In-scope namespaces
2381 */
2382 inode->inScopeNs = iprev->inScopeNs;
2383 /*
2384 * Info for literal result elements
2385 */
2386 inode->litResElemInfo = iprev->litResElemInfo;
2387 inode->nsChanged = iprev->nsChanged;
2388 /*
2389 * Excluded result namespaces
2390 */
2391 inode->exclResultNs = iprev->exclResultNs;
2392 /*
2393 * Extension instruction namespaces
2394 */
2395 inode->extElemNs = iprev->extElemNs;
2396 /*
2397 * Whitespace preservation
2398 */
2399 inode->preserveWhitespace = iprev->preserveWhitespace;
2400 /*
2401 * Forwards-compatible mode
2402 */
2403 inode->forwardsCompat = iprev->forwardsCompat;
2404 } else {
2405 inode->inScopeNs = NULL;
2406 inode->exclResultNs = NULL;
2407 inode->extElemNs = NULL;
2408 inode->preserveWhitespace = 0;
2409 inode->forwardsCompat = 0;
2410 }
2411
2412 return(inode);
2413 }
2414
2415 /*
2416 * xsltCompilerNodePop:
2417 *
2418 * @cctxt: the compilation context
2419 * @node: the node to be pushed (this can also be the doc-node)
2420 *
2421 * Pops the current node info.
2422 */
2423 static void
2424 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2425 {
2426 if (cctxt->inode == NULL) {
2427 xmlGenericError(xmlGenericErrorContext,
2428 "xsltCompilerNodePop: Top-node mismatch.\n");
2429 return;
2430 }
2431 /*
2432 * NOTE: Be carefull with the @node, since it might be
2433 * a doc-node.
2434 */
2435 if (cctxt->inode->node != node) {
2436 xmlGenericError(xmlGenericErrorContext,
2437 "xsltCompilerNodePop: Node mismatch.\n");
2438 goto mismatch;
2439 }
2440 if (cctxt->inode->depth != cctxt->depth) {
2441 xmlGenericError(xmlGenericErrorContext,
2442 "xsltCompilerNodePop: Depth mismatch.\n");
2443 goto mismatch;
2444 }
2445 cctxt->depth--;
2446 /*
2447 * Pop information of variables.
2448 */
2449 if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
2450 xsltCompilerVarInfoPop(cctxt);
2451
2452 cctxt->inode = cctxt->inode->prev;
2453 if (cctxt->inode != NULL)
2454 cctxt->inode->curChildType = 0;
2455 return;
2456
2457 mismatch:
2458 {
2459 const xmlChar *nsName = NULL, *name = NULL;
2460 const xmlChar *infnsName = NULL, *infname = NULL;
2461
2462 if (node) {
2463 if (node->type == XML_ELEMENT_NODE) {
2464 name = node->name;
2465 if (node->ns != NULL)
2466 nsName = node->ns->href;
2467 else
2468 nsName = BAD_CAST "";
2469 } else {
2470 name = BAD_CAST "#document";
2471 nsName = BAD_CAST "";
2472 }
2473 } else
2474 name = BAD_CAST "Not given";
2475
2476 if (cctxt->inode->node) {
2477 if (node->type == XML_ELEMENT_NODE) {
2478 infname = cctxt->inode->node->name;
2479 if (cctxt->inode->node->ns != NULL)
2480 infnsName = cctxt->inode->node->ns->href;
2481 else
2482 infnsName = BAD_CAST "";
2483 } else {
2484 infname = BAD_CAST "#document";
2485 infnsName = BAD_CAST "";
2486 }
2487 } else
2488 infname = BAD_CAST "Not given";
2489
2490
2491 xmlGenericError(xmlGenericErrorContext,
2492 "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2493 name, nsName);
2494 xmlGenericError(xmlGenericErrorContext,
2495 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2496 infname, infnsName);
2497 }
2498 }
2499
2500 /*
2501 * xsltCompilerBuildInScopeNsList:
2502 *
2503 * Create and store the list of in-scope namespaces for the given
2504 * node in the stylesheet. If there are no changes in the in-scope
2505 * namespaces then the last ns-info of the ancestor axis will be returned.
2506 * Compilation-time only.
2507 *
2508 * Returns the ns-info or NULL if there are no namespaces in scope.
2509 */
2510 static xsltNsListContainerPtr
2511 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2512 {
2513 xsltNsListContainerPtr nsi = NULL;
2514 xmlNsPtr *list = NULL, ns;
2515 int i, maxns = 5;
2516 /*
2517 * Create a new ns-list for this position in the node-tree.
2518 * xmlGetNsList() will return NULL, if there are no ns-decls in the
2519 * tree. Note that the ns-decl for the XML namespace is not added
2520 * to the resulting list; the XPath module handles the XML namespace
2521 * internally.
2522 */
2523 while (node != NULL) {
2524 if (node->type == XML_ELEMENT_NODE) {
2525 ns = node->nsDef;
2526 while (ns != NULL) {
2527 if (nsi == NULL) {
2528 nsi = (xsltNsListContainerPtr)
2529 xmlMalloc(sizeof(xsltNsListContainer));
2530 if (nsi == NULL) {
2531 xsltTransformError(NULL, cctxt->style, NULL,
2532 "xsltCompilerBuildInScopeNsList: "
2533 "malloc failed!\n");
2534 goto internal_err;
2535 }
2536 memset(nsi, 0, sizeof(xsltNsListContainer));
2537 nsi->list =
2538 (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
2539 if (nsi->list == NULL) {
2540 xsltTransformError(NULL, cctxt->style, NULL,
2541 "xsltCompilerBuildInScopeNsList: "
2542 "malloc failed!\n");
2543 goto internal_err;
2544 }
2545 nsi->list[0] = NULL;
2546 }
2547 /*
2548 * Skip shadowed namespace bindings.
2549 */
2550 for (i = 0; i < nsi->totalNumber; i++) {
2551 if ((ns->prefix == nsi->list[i]->prefix) ||
2552 (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
2553 break;
2554 }
2555 if (i >= nsi->totalNumber) {
2556 if (nsi->totalNumber +1 >= maxns) {
2557 maxns *= 2;
2558 nsi->list =
2559 (xmlNsPtr *) xmlRealloc(nsi->list,
2560 maxns * sizeof(xmlNsPtr));
2561 if (nsi->list == NULL) {
2562 xsltTransformError(NULL, cctxt->style, NULL,
2563 "xsltCompilerBuildInScopeNsList: "
2564 "realloc failed!\n");
2565 goto internal_err;
2566 }
2567 }
2568 nsi->list[nsi->totalNumber++] = ns;
2569 nsi->list[nsi->totalNumber] = NULL;
2570 }
2571
2572 ns = ns->next;
2573 }
2574 }
2575 node = node->parent;
2576 }
2577 if (nsi == NULL)
2578 return(NULL);
2579 /*
2580 * Move the default namespace to last position.
2581 */
2582 nsi->xpathNumber = nsi->totalNumber;
2583 for (i = 0; i < nsi->totalNumber; i++) {
2584 if (nsi->list[i]->prefix == NULL) {
2585 ns = nsi->list[i];
2586 nsi->list[i] = nsi->list[nsi->totalNumber-1];
2587 nsi->list[nsi->totalNumber-1] = ns;
2588 nsi->xpathNumber--;
2589 break;
2590 }
2591 }
2592 /*
2593 * Store the ns-list in the stylesheet.
2594 */
2595 if (xsltPointerListAddSize(
2596 (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
2597 (void *) nsi, 5) == -1)
2598 {
2599 xmlFree(nsi);
2600 nsi = NULL;
2601 xsltTransformError(NULL, cctxt->style, NULL,
2602 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2603 goto internal_err;
2604 }
2605 /*
2606 * Notify of change in status wrt namespaces.
2607 */
2608 if (cctxt->inode != NULL)
2609 cctxt->inode->nsChanged = 1;
2610
2611 return(nsi);
2612
2613 internal_err:
2614 if (list != NULL)
2615 xmlFree(list);
2616 cctxt->style->errors++;
2617 return(NULL);
2618 }
2619
2620 static int
2621 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2622 xsltPointerListPtr list,
2623 xmlNodePtr node,
2624 const xmlChar *value)
2625 {
2626 xmlChar *cur, *end;
2627 xmlNsPtr ns;
2628
2629 if ((cctxt == NULL) || (value == NULL) || (list == NULL))
2630 return(-1);
2631
2632 list->number = 0;
2633
2634 cur = (xmlChar *) value;
2635 while (*cur != 0) {
2636 while (IS_BLANK(*cur)) cur++;
2637 if (*cur == 0)
2638 break;
2639 end = cur;
2640 while ((*end != 0) && (!IS_BLANK(*end))) end++;
2641 cur = xmlStrndup(cur, end - cur);
2642 if (cur == NULL) {
2643 cur = end;
2644 continue;
2645 }
2646 /*
2647 * TODO: Export and use xmlSearchNsByPrefixStrict()
2648 * in Libxml2, tree.c, since xmlSearchNs() is in most
2649 * cases not efficient and in some cases not correct.
2650 *
2651 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2652 */
2653 if ((cur[0] == '#') &&
2654 xmlStrEqual(cur, (const xmlChar *)"#default"))
2655 ns = xmlSearchNs(cctxt->style->doc, node, NULL);
2656 else
2657 ns = xmlSearchNs(cctxt->style->doc, node, cur);
2658
2659 if (ns == NULL) {
2660 /*
2661 * TODO: Better to report the attr-node, otherwise
2662 * the user won't know which attribute was invalid.
2663 */
2664 xsltTransformError(NULL, cctxt->style, node,
2665 "No namespace binding in scope for prefix '%s'.\n", cur);
2666 /*
2667 * XSLT-1.0: "It is an error if there is no namespace
2668 * bound to the prefix on the element bearing the
2669 * exclude-result-prefixes or xsl:exclude-result-prefixes
2670 * attribute."
2671 */
2672 cctxt->style->errors++;
2673 } else {
2674 #ifdef WITH_XSLT_DEBUG_PARSING
2675 xsltGenericDebug(xsltGenericDebugContext,
2676 "resolved prefix '%s'\n", cur);
2677 #endif
2678 /*
2679 * Note that we put the namespace name into the dict.
2680 */
2681 if (xsltPointerListAddSize(list,
2682 (void *) xmlDictLookup(cctxt->style->dict,
2683 ns->href, -1), 5) == -1)
2684 {
2685 xmlFree(cur);
2686 goto internal_err;
2687 }
2688 }
2689 xmlFree(cur);
2690
2691 cur = end;
2692 }
2693 return(0);
2694
2695 internal_err:
2696 cctxt->style->errors++;
2697 return(-1);
2698 }
2699
2700 /**
2701 * xsltCompilerUtilsCreateMergedList:
2702 * @dest: the destination list (optional)
2703 * @first: the first list
2704 * @second: the second list (optional)
2705 *
2706 * Appends the content of @second to @first into @destination.
2707 * If @destination is NULL a new list will be created.
2708 *
2709 * Returns the merged list of items or NULL if there's nothing to merge.
2710 */
2711 static xsltPointerListPtr
2712 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
2713 xsltPointerListPtr second)
2714 {
2715 xsltPointerListPtr ret;
2716 size_t num;
2717
2718 if (first)
2719 num = first->number;
2720 else
2721 num = 0;
2722 if (second)
2723 num += second->number;
2724 if (num == 0)
2725 return(NULL);
2726 ret = xsltPointerListCreate(num);
2727 if (ret == NULL)
2728 return(NULL);
2729 /*
2730 * Copy contents.
2731 */
2732 if ((first != NULL) && (first->number != 0)) {
2733 memcpy(ret->items, first->items,
2734 first->number * sizeof(void *));
2735 if ((second != NULL) && (second->number != 0))
2736 memcpy(ret->items + first->number, second->items,
2737 second->number * sizeof(void *));
2738 } else if ((second != NULL) && (second->number != 0))
2739 memcpy(ret->items, (void *) second->items,
2740 second->number * sizeof(void *));
2741 ret->number = num;
2742 return(ret);
2743 }
2744
2745 /*
2746 * xsltParseExclResultPrefixes:
2747 *
2748 * Create and store the list of in-scope namespaces for the given
2749 * node in the stylesheet. If there are no changes in the in-scope
2750 * namespaces then the last ns-info of the ancestor axis will be returned.
2751 * Compilation-time only.
2752 *
2753 * Returns the ns-info or NULL if there are no namespaces in scope.
2754 */
2755 static xsltPointerListPtr
2756 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2757 xsltPointerListPtr def,
2758 int instrCategory)
2759 {
2760 xsltPointerListPtr list = NULL;
2761 xmlChar *value;
2762 xmlAttrPtr attr;
2763
2764 if ((cctxt == NULL) || (node == NULL))
2765 return(NULL);
2766
2767 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2768 attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
2769 else
2770 attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
2771 XSLT_NAMESPACE);
2772 if (attr == NULL)
2773 return(def);
2774
2775 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2776 /*
2777 * Mark the XSLT attr.
2778 */
2779 attr->psvi = (void *) xsltXSLTAttrMarker;
2780 }
2781
2782 if ((attr->children != NULL) &&
2783 (attr->children->content != NULL))
2784 value = attr->children->content;
2785 else {
2786 xsltTransformError(NULL, cctxt->style, node,
2787 "Attribute 'exclude-result-prefixes': Invalid value.\n");
2788 cctxt->style->errors++;
2789 return(def);
2790 }
2791
2792 if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2793 BAD_CAST value) != 0)
2794 goto exit;
2795 if (cctxt->tmpList->number == 0)
2796 goto exit;
2797 /*
2798 * Merge the list with the inherited list.
2799 */
2800 list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2801 if (list == NULL)
2802 goto exit;
2803 /*
2804 * Store the list in the stylesheet/compiler context.
2805 */
2806 if (xsltPointerListAddSize(
2807 cctxt->psData->exclResultNamespaces, list, 5) == -1)
2808 {
2809 xsltPointerListFree(list);
2810 list = NULL;
2811 goto exit;
2812 }
2813 /*
2814 * Notify of change in status wrt namespaces.
2815 */
2816 if (cctxt->inode != NULL)
2817 cctxt->inode->nsChanged = 1;
2818
2819 exit:
2820 if (list != NULL)
2821 return(list);
2822 else
2823 return(def);
2824 }
2825
2826 /*
2827 * xsltParseExtElemPrefixes:
2828 *
2829 * Create and store the list of in-scope namespaces for the given
2830 * node in the stylesheet. If there are no changes in the in-scope
2831 * namespaces then the last ns-info of the ancestor axis will be returned.
2832 * Compilation-time only.
2833 *
2834 * Returns the ns-info or NULL if there are no namespaces in scope.
2835 */
2836 static xsltPointerListPtr
2837 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2838 xsltPointerListPtr def,
2839 int instrCategory)
2840 {
2841 xsltPointerListPtr list = NULL;
2842 xmlAttrPtr attr;
2843 xmlChar *value;
2844 int i;
2845
2846 if ((cctxt == NULL) || (node == NULL))
2847 return(NULL);
2848
2849 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2850 attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
2851 else
2852 attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
2853 XSLT_NAMESPACE);
2854 if (attr == NULL)
2855 return(def);
2856
2857 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2858 /*
2859 * Mark the XSLT attr.
2860 */
2861 attr->psvi = (void *) xsltXSLTAttrMarker;
2862 }
2863
2864 if ((attr->children != NULL) &&
2865 (attr->children->content != NULL))
2866 value = attr->children->content;
2867 else {
2868 xsltTransformError(NULL, cctxt->style, node,
2869 "Attribute 'extension-element-prefixes': Invalid value.\n");
2870 cctxt->style->errors++;
2871 return(def);
2872 }
2873
2874
2875 if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2876 BAD_CAST value) != 0)
2877 goto exit;
2878
2879 if (cctxt->tmpList->number == 0)
2880 goto exit;
2881 /*
2882 * REVISIT: Register the extension namespaces.
2883 */
2884 for (i = 0; i < cctxt->tmpList->number; i++)
2885 xsltRegisterExtPrefix(cctxt->style, NULL,
2886 BAD_CAST cctxt->tmpList->items[i]);
2887 /*
2888 * Merge the list with the inherited list.
2889 */
2890 list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2891 if (list == NULL)
2892 goto exit;
2893 /*
2894 * Store the list in the stylesheet.
2895 */
2896 if (xsltPointerListAddSize(
2897 cctxt->psData->extElemNamespaces, list, 5) == -1)
2898 {
2899 xsltPointerListFree(list);
2900 list = NULL;
2901 goto exit;
2902 }
2903 /*
2904 * Notify of change in status wrt namespaces.
2905 */
2906 if (cctxt->inode != NULL)
2907 cctxt->inode->nsChanged = 1;
2908
2909 exit:
2910 if (list != NULL)
2911 return(list);
2912 else
2913 return(def);
2914 }
2915
2916 /*
2917 * xsltParseAttrXSLTVersion:
2918 *
2919 * @cctxt: the compilation context
2920 * @node: the element-node
2921 * @isXsltElem: whether this is an XSLT element
2922 *
2923 * Parses the attribute xsl:version.
2924 *
2925 * Returns 1 if there was such an attribute, 0 if not and
2926 * -1 if an internal or API error occured.
2927 */
2928 static int
2929 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2930 int instrCategory)
2931 {
2932 xmlChar *value;
2933 xmlAttrPtr attr;
2934
2935 if ((cctxt == NULL) || (node == NULL))
2936 return(-1);
2937
2938 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2939 attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
2940 else
2941 attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
2942
2943 if (attr == NULL)
2944 return(0);
2945
2946 attr->psvi = (void *) xsltXSLTAttrMarker;
2947
2948 if ((attr->children != NULL) &&
2949 (attr->children->content != NULL))
2950 value = attr->children->content;
2951 else {
2952 xsltTransformError(NULL, cctxt->style, node,
2953 "Attribute 'version': Invalid value.\n");
2954 cctxt->style->errors++;
2955 return(1);
2956 }
2957
2958 if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
2959 cctxt->inode->forwardsCompat = 1;
2960 /*
2961 * TODO: To what extent do we support the
2962 * forwards-compatible mode?
2963 */
2964 /*
2965 * Report this only once per compilation episode.
2966 */
2967 if (! cctxt->hasForwardsCompat) {
2968 cctxt->hasForwardsCompat = 1;
2969 cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
2970 xsltTransformError(NULL, cctxt->style, node,
2971 "Warning: the attribute xsl:version specifies a value "
2972 "different from '1.0'. Switching to forwards-compatible "
2973 "mode. Only features of XSLT 1.0 are supported by this "
2974 "processor.\n");
2975 cctxt->style->warnings++;
2976 cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
2977 }
2978 } else {
2979 cctxt->inode->forwardsCompat = 0;
2980 }
2981
2982 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2983 /*
2984 * Set a marker on XSLT attributes.
2985 */
2986 attr->psvi = (void *) xsltXSLTAttrMarker;
2987 }
2988 return(1);
2989 }
2990
2991 static int
2992 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2993 {
2994 xmlNodePtr deleteNode, cur, txt, textNode = NULL;
2995 xmlDocPtr doc;
2996 xsltStylesheetPtr style;
2997 int internalize = 0, findSpaceAttr;
2998 int xsltStylesheetElemDepth;
2999 xmlAttrPtr attr;
3000 xmlChar *value;
3001 const xmlChar *name, *nsNameXSLT = NULL;
3002 int strictWhitespace, inXSLText = 0;
3003 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3004 xsltNsMapPtr nsMapItem;
3005 #endif
3006
3007 if ((cctxt == NULL) || (cctxt->style == NULL) ||
3008 (node == NULL) || (node->type != XML_ELEMENT_NODE))
3009 return(-1);
3010
3011 doc = node->doc;
3012 if (doc == NULL)
3013 goto internal_err;
3014
3015 style = cctxt->style;
3016 if ((style->dict != NULL) && (doc->dict == style->dict))
3017 internalize = 1;
3018 else
3019 style->internalized = 0;
3020
3021 /*
3022 * Init value of xml:space. Since this might be an embedded
3023 * stylesheet, this is needed to be performed on the element
3024 * where the stylesheet is rooted at, taking xml:space of
3025 * ancestors into account.
3026 */
3027 if (! cctxt->simplified)
3028 xsltStylesheetElemDepth = cctxt->depth +1;
3029 else
3030 xsltStylesheetElemDepth = 0;
3031
3032 if (xmlNodeGetSpacePreserve(node) != 1)
3033 cctxt->inode->preserveWhitespace = 0;
3034 else
3035 cctxt->inode->preserveWhitespace = 1;
3036
3037 /*
3038 * Eval if we should keep the old incorrect behaviour.
3039 */
3040 strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
3041
3042 nsNameXSLT = xsltConstNamespaceNameXSLT;
3043
3044 deleteNode = NULL;
3045 cur = node;
3046 while (cur != NULL) {
3047 if (deleteNode != NULL) {
3048
3049 #ifdef WITH_XSLT_DEBUG_BLANKS
3050 xsltGenericDebug(xsltGenericDebugContext,
3051 "xsltParsePreprocessStylesheetTree: removing node\n");
3052 #endif
3053 xmlUnlinkNode(deleteNode);
3054 xmlFreeNode(deleteNode);
3055 deleteNode = NULL;
3056 }
3057 if (cur->type == XML_ELEMENT_NODE) {
3058
3059 /*
3060 * Clear the PSVI field.
3061 */
3062 cur->psvi = NULL;
3063
3064 xsltCompilerNodePush(cctxt, cur);
3065
3066 inXSLText = 0;
3067 textNode = NULL;
3068 findSpaceAttr = 1;
3069 cctxt->inode->stripWhitespace = 0;
3070 /*
3071 * TODO: I'd love to use a string pointer comparison here :-/
3072 */
3073 if (IS_XSLT_ELEM(cur)) {
3074 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3075 if (cur->ns->href != nsNameXSLT) {
3076 nsMapItem = xsltNewNamespaceMapItem(cctxt,
3077 doc, cur->ns, cur);
3078 if (nsMapItem == NULL)
3079 goto internal_err;
3080 cur->ns->href = nsNameXSLT;
3081 }
3082 #endif
3083
3084 if (cur->name == NULL)
3085 goto process_attributes;
3086 /*
3087 * Mark the XSLT element for later recognition.
3088 * TODO: Using the marker is still too dangerous, since if
3089 * the parsing mechanism leaves out an XSLT element, then
3090 * this might hit the transformation-mechanism, which
3091 * will break if it doesn't expect such a marker.
3092 */
3093 /* cur->psvi = (void *) xsltXSLTElemMarker; */
3094
3095 /*
3096 * XSLT 2.0: "Any whitespace text node whose parent is
3097 * one of the following elements is removed from the "
3098 * tree, regardless of any xml:space attributes:..."
3099 * xsl:apply-imports,
3100 * xsl:apply-templates,
3101 * xsl:attribute-set,
3102 * xsl:call-template,
3103 * xsl:choose,
3104 * xsl:stylesheet, xsl:transform.
3105 * XSLT 2.0: xsl:analyze-string,
3106 * xsl:character-map,
3107 * xsl:next-match
3108 *
3109 * TODO: I'd love to use a string pointer comparison here :-/
3110 */
3111 name = cur->name;
3112 switch (*name) {
3113 case 't':
3114 if ((name[0] == 't') && (name[1] == 'e') &&
3115 (name[2] == 'x') && (name[3] == 't') &&
3116 (name[4] == 0))
3117 {
3118 /*
3119 * Process the xsl:text element.
3120 * ----------------------------
3121 * Mark it for later recognition.
3122 */
3123 cur->psvi = (void *) xsltXSLTTextMarker;
3124 /*
3125 * For stylesheets, the set of
3126 * whitespace-preserving element names
3127 * consists of just xsl:text.
3128 */
3129 findSpaceAttr = 0;
3130 cctxt->inode->preserveWhitespace = 1;
3131 inXSLText = 1;
3132 }
3133 break;
3134 case 'c':
3135 if (xmlStrEqual(name, BAD_CAST "choose") ||
3136 xmlStrEqual(name, BAD_CAST "call-template"))
3137 cctxt->inode->stripWhitespace = 1;
3138 break;
3139 case 'a':
3140 if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
3141 xmlStrEqual(name, BAD_CAST "apply-imports") ||
3142 xmlStrEqual(name, BAD_CAST "attribute-set"))
3143
3144 cctxt->inode->stripWhitespace = 1;
3145 break;
3146 default:
3147 if (xsltStylesheetElemDepth == cctxt->depth) {
3148 /*
3149 * This is a xsl:stylesheet/xsl:transform.
3150 */
3151 cctxt->inode->stripWhitespace = 1;
3152 break;
3153 }
3154
3155 if ((cur->prev != NULL) &&
3156 (cur->prev->type == XML_TEXT_NODE))
3157 {
3158 /*
3159 * XSLT 2.0 : "Any whitespace text node whose
3160 * following-sibling node is an xsl:param or
3161 * xsl:sort element is removed from the tree,
3162 * regardless of any xml:space attributes."
3163 */
3164 if (((*name == 'p') || (*name == 's')) &&
3165 (xmlStrEqual(name, BAD_CAST "param") ||
3166 xmlStrEqual(name, BAD_CAST "sort")))
3167 {
3168 do {
3169 if (IS_BLANK_NODE(cur->prev)) {
3170 txt = cur->prev;
3171 xmlUnlinkNode(txt);
3172 xmlFreeNode(txt);
3173 } else {
3174 /*
3175 * This will result in a content
3176 * error, when hitting the parsing
3177 * functions.
3178 */
3179 break;
3180 }
3181 } while (cur->prev);
3182 }
3183 }
3184 break;
3185 }
3186 }
3187
3188 process_attributes:
3189 /*
3190 * Process attributes.
3191 * ------------------
3192 */
3193 if (cur->properties != NULL) {
3194 if (cur->children == NULL)
3195 findSpaceAttr = 0;
3196 attr = cur->properties;
3197 do {
3198 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3199 if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
3200 xmlStrEqual(attr->ns->href, nsNameXSLT))
3201 {
3202 nsMapItem = xsltNewNamespaceMapItem(cctxt,
3203 doc, attr->ns, cur);
3204 if (nsMapItem == NULL)
3205 goto internal_err;
3206 attr->ns->href = nsNameXSLT;
3207 }
3208 #endif
3209 if (internalize) {
3210 /*
3211 * Internalize the attribute's value; the goal is to
3212 * speed up operations and minimize used space by
3213 * compiled stylesheets.
3214 */
3215 txt = attr->children;
3216 /*
3217 * NOTE that this assumes only one
3218 * text-node in the attribute's content.
3219 */
3220 if ((txt != NULL) && (txt->content != NULL) &&
3221 (!xmlDictOwns(style->dict, txt->content)))
3222 {
3223 value = (xmlChar *) xmlDictLookup(style->dict,
3224 txt->content, -1);
3225 xmlNodeSetContent(txt, NULL);
3226 txt->content = value;
3227 }
3228 }
3229 /*
3230 * Process xml:space attributes.
3231 * ----------------------------
3232 */
3233 if ((findSpaceAttr != 0) &&
3234 (attr->ns != NULL) &&
3235 (attr->name != NULL) &&
3236 (attr->name[0] == 's') &&
3237 (attr->ns->prefix != NULL) &&
3238 (attr->ns->prefix[0] == 'x') &&
3239 (attr->ns->prefix[1] == 'm') &&
3240 (attr->ns->prefix[2] == 'l') &&
3241 (attr->ns->prefix[3] == 0))
3242 {
3243 value = xmlGetNsProp(cur, BAD_CAST "space",
3244 XML_XML_NAMESPACE);
3245 if (value != NULL) {
3246 if (xmlStrEqual(value, BAD_CAST "preserve")) {
3247 cctxt->inode->preserveWhitespace = 1;
3248 } else if (xmlStrEqual(value, BAD_CAST "default")) {
3249 cctxt->inode->preserveWhitespace = 0;
3250 } else {
3251 /* Invalid value for xml:space. */
3252 xsltTransformError(NULL, style, cur,
3253 "Attribute xml:space: Invalid value.\n");
3254 cctxt->style->warnings++;
3255 }
3256 findSpaceAttr = 0;
3257 xmlFree(value);
3258 }
3259
3260 }
3261 attr = attr->next;
3262 } while (attr != NULL);
3263 }
3264 /*
3265 * We'll descend into the children of element nodes only.
3266 */
3267 if (cur->children != NULL) {
3268 cur = cur->children;
3269 continue;
3270 }
3271 } else if ((cur->type == XML_TEXT_NODE) ||
3272 (cur->type == XML_CDATA_SECTION_NODE))
3273 {
3274 /*
3275 * Merge adjacent text/CDATA-section-nodes
3276 * ---------------------------------------
3277 * In order to avoid breaking of existing stylesheets,
3278 * if the old behaviour is wanted (strictWhitespace == 0),
3279 * then we *won't* merge adjacent text-nodes
3280 * (except in xsl:text); this will ensure that whitespace-only
3281 * text nodes are (incorrectly) not stripped in some cases.
3282 *
3283 * Example: : <foo> <!-- bar -->zoo</foo>
3284 * Corrent (strict) result: <foo> zoo</foo>
3285 * Incorrect (old) result : <foo>zoo</foo>
3286 *
3287 * NOTE that we *will* merge adjacent text-nodes if
3288 * they are in xsl:text.
3289 * Example, the following:
3290 * <xsl:text> <!-- bar -->zoo<xsl:text>
3291 * will result in both cases in:
3292 * <xsl:text> zoo<xsl:text>
3293 */
3294 cur->type = XML_TEXT_NODE;
3295 if ((strictWhitespace != 0) || (inXSLText != 0)) {
3296 /*
3297 * New behaviour; merge nodes.
3298 */
3299 if (textNode == NULL)
3300 textNode = cur;
3301 else {
3302 if (cur->content != NULL)
3303 xmlNodeAddContent(textNode, cur->content);
3304 deleteNode = cur;
3305 }
3306 if ((cur->next == NULL) ||
3307 (cur->next->type == XML_ELEMENT_NODE))
3308 goto end_of_text;
3309 else
3310 goto next_sibling;
3311 } else {
3312 /*
3313 * Old behaviour.
3314 */
3315 if (textNode == NULL)
3316 textNode = cur;
3317 goto end_of_text;
3318 }
3319 } else if ((cur->type == XML_COMMENT_NODE) ||
3320 (cur->type == XML_PI_NODE))
3321 {
3322 /*
3323 * Remove processing instructions and comments.
3324 */
3325 deleteNode = cur;
3326 if ((cur->next == NULL) ||
3327 (cur->next->type == XML_ELEMENT_NODE))
3328 goto end_of_text;
3329 else
3330 goto next_sibling;
3331 } else {
3332 textNode = NULL;
3333 /*
3334 * Invalid node-type for this data-model.
3335 */
3336 xsltTransformError(NULL, style, cur,
3337 "Invalid type of node for the XSLT data model.\n");
3338 cctxt->style->errors++;
3339 goto next_sibling;
3340 }
3341
3342 end_of_text:
3343 if (textNode) {
3344 value = textNode->content;
3345 /*
3346 * At this point all adjacent text/CDATA-section nodes
3347 * have been merged.
3348 *
3349 * Strip whitespace-only text-nodes.
3350 * (cctxt->inode->stripWhitespace)
3351 */
3352 if ((value == NULL) || (*value == 0) ||
3353 (((cctxt->inode->stripWhitespace) ||
3354 (! cctxt->inode->preserveWhitespace)) &&
3355 IS_BLANK(*value) &&
3356 xsltIsBlank(value)))
3357 {
3358 if (textNode != cur) {
3359 xmlUnlinkNode(textNode);
3360 xmlFreeNode(textNode);
3361 } else
3362 deleteNode = textNode;
3363 textNode = NULL;
3364 goto next_sibling;
3365 }
3366 /*
3367 * Convert CDATA-section nodes to text-nodes.
3368 * TODO: Can this produce problems?
3369 */
3370 if (textNode->type != XML_TEXT_NODE) {
3371 textNode->type = XML_TEXT_NODE;
3372 textNode->name = xmlStringText;
3373 }
3374 if (internalize &&
3375 (textNode->content != NULL) &&
3376 (!xmlDictOwns(style->dict, textNode->content)))
3377 {
3378 /*
3379 * Internalize the string.
3380 */
3381 value = (xmlChar *) xmlDictLookup(style->dict,
3382 textNode->content, -1);
3383 xmlNodeSetContent(textNode, NULL);
3384 textNode->content = value;
3385 }
3386 textNode = NULL;
3387 /*
3388 * Note that "disable-output-escaping" of the xsl:text
3389 * element will be applied at a later level, when
3390 * XSLT elements are processed.
3391 */
3392 }
3393
3394 next_sibling:
3395 if (cur->type == XML_ELEMENT_NODE) {
3396 xsltCompilerNodePop(cctxt, cur);
3397 }
3398 if (cur == node)
3399 break;
3400 if (cur->next != NULL) {
3401 cur = cur->next;
3402 } else {
3403 cur = cur->parent;
3404 inXSLText = 0;
3405 goto next_sibling;
3406 };
3407 }
3408 if (deleteNode != NULL) {
3409 #ifdef WITH_XSLT_DEBUG_PARSING
3410 xsltGenericDebug(xsltGenericDebugContext,
3411 "xsltParsePreprocessStylesheetTree: removing node\n");
3412 #endif
3413 xmlUnlinkNode(deleteNode);
3414 xmlFreeNode(deleteNode);
3415 }
3416 return(0);
3417
3418 internal_err:
3419 return(-1);
3420 }
3421
3422 #endif /* XSLT_REFACTORED */
3423
3424 #ifdef XSLT_REFACTORED
3425 #else
3426 static void
3427 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
3428 {
3429 xmlNodePtr deleteNode, styleelem;
3430 int internalize = 0;
3431
3432 if ((style == NULL) || (cur == NULL))
3433 return;
3434
3435 if ((cur->doc != NULL) && (style->dict != NULL) &&
3436 (cur->doc->dict == style->dict))
3437 internalize = 1;
3438 else
3439 style->internalized = 0;
3440
3441 if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3442 (IS_XSLT_NAME(cur, "stylesheet"))) {
3443 styleelem = cur;
3444 } else {
3445 styleelem = NULL;
3446 }
3447
3448 /*
3449 * This content comes from the stylesheet
3450 * For stylesheets, the set of whitespace-preserving
3451 * element names consists of just xsl:text.
3452 */
3453 deleteNode = NULL;
3454 while (cur != NULL) {
3455 if (deleteNode != NULL) {
3456 #ifdef WITH_XSLT_DEBUG_BLANKS
3457 xsltGenericDebug(xsltGenericDebugContext,
3458 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3459 #endif
3460 xmlUnlinkNode(deleteNode);
3461 xmlFreeNode(deleteNode);
3462 deleteNode = NULL;
3463 }
3464 if (cur->type == XML_ELEMENT_NODE) {
3465 int exclPrefixes;
3466 /*
3467 * Internalize attributes values.
3468 */
3469 if ((internalize) && (cur->properties != NULL)) {
3470 xmlAttrPtr attr = cur->properties;
3471 xmlNodePtr txt;
3472
3473 while (attr != NULL) {
3474 txt = attr->children;
3475 if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3476 (txt->content != NULL) &&
3477 (!xmlDictOwns(style->dict, txt->content)))
3478 {
3479 xmlChar *tmp;
3480
3481 /*
3482 * internalize the text string, goal is to speed
3483 * up operations and minimize used space by compiled
3484 * stylesheets.
3485 */
3486 tmp = (xmlChar *) xmlDictLookup(style->dict,
3487 txt->content, -1);
3488 if (tmp != txt->content) {
3489 xmlNodeSetContent(txt, NULL);
3490 txt->content = tmp;
3491 }
3492 }
3493 attr = attr->next;
3494 }
3495 }
3496 if (IS_XSLT_ELEM(cur)) {
3497 exclPrefixes = 0;
3498 xsltStylePreCompute(style, cur);
3499 if (IS_XSLT_NAME(cur, "text")) {
3500 for (;exclPrefixes > 0;exclPrefixes--)
3501 exclPrefixPop(style);
3502 goto skip_children;
3503 }
3504 } else {
3505 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3506 }
3507
3508 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3509 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3510 xmlNodePtr root = NULL;
3511 int i, moved;
3512
3513 root = xmlDocGetRootElement(cur->doc);
3514 if ((root != NULL) && (root != cur)) {
3515 while (ns != NULL) {
3516 moved = 0;
3517 next = ns->next;
3518 for (i = 0;i < style->exclPrefixNr;i++) {
3519 if ((ns->prefix != NULL) &&
3520 (xmlStrEqual(ns->href,
3521 style->exclPrefixTab[i]))) {
3522 /*
3523 * Move the namespace definition on the root
3524 * element to avoid duplicating it without
3525 * loosing it.
3526 */
3527 if (prev == NULL) {
3528 cur->nsDef = ns->next;
3529 } else {
3530 prev->next = ns->next;
3531 }
3532 ns->next = root->nsDef;
3533 root->nsDef = ns;
3534 moved = 1;
3535 break;
3536 }
3537 }
3538 if (moved == 0)
3539 prev = ns;
3540 ns = next;
3541 }
3542 }
3543 }
3544 /*
3545 * If we have prefixes locally, recurse and pop them up when
3546 * going back
3547 */
3548 if (exclPrefixes > 0) {
3549 xsltPrecomputeStylesheet(style, cur->children);
3550 for (;exclPrefixes > 0;exclPrefixes--)
3551 exclPrefixPop(style);
3552 goto skip_children;
3553 }
3554 } else if (cur->type == XML_TEXT_NODE) {
3555 if (IS_BLANK_NODE(cur)) {
3556 if (xmlNodeGetSpacePreserve(cur) != 1) {
3557 deleteNode = cur;
3558 }
3559 } else if ((cur->content != NULL) && (internalize) &&
3560 (!xmlDictOwns(style->dict, cur->content))) {
3561 xmlChar *tmp;
3562
3563 /*
3564 * internalize the text string, goal is to speed
3565 * up operations and minimize used space by compiled
3566 * stylesheets.
3567 */
3568 tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3569 xmlNodeSetContent(cur, NULL);
3570 cur->content = tmp;
3571 }
3572 } else if ((cur->type != XML_ELEMENT_NODE) &&
3573 (cur->type != XML_CDATA_SECTION_NODE)) {
3574 deleteNode = cur;
3575 goto skip_children;
3576 }
3577
3578 /*
3579 * Skip to next node. In case of a namespaced element children of
3580 * the stylesheet and not in the XSLT namespace and not an extension
3581 * element, ignore its content.
3582 */
3583 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3584 (styleelem != NULL) && (cur->parent == styleelem) &&
3585 (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3586 (!xsltCheckExtURI(style, cur->ns->href))) {
3587 goto skip_children;
3588 } else if (cur->children != NULL) {
3589 if ((cur->children->type != XML_ENTITY_DECL) &&
3590 (cur->children->type != XML_ENTITY_REF_NODE) &&
3591 (cur->children->type != XML_ENTITY_NODE)) {
3592 cur = cur->children;
3593 continue;
3594 }
3595 }
3596
3597 skip_children:
3598 if (cur->next != NULL) {
3599 cur = cur->next;
3600 continue;
3601 }
3602 do {
3603
3604 cur = cur->parent;
3605 if (cur == NULL)
3606 break;
3607 if (cur == (xmlNodePtr) style->doc) {
3608 cur = NULL;
3609 break;
3610 }
3611 if (cur->next != NULL) {
3612 cur = cur->next;
3613 break;
3614 }
3615 } while (cur != NULL);
3616 }
3617 if (deleteNode != NULL) {
3618 #ifdef WITH_XSLT_DEBUG_PARSING
3619 xsltGenericDebug(xsltGenericDebugContext,
3620 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3621 #endif
3622 xmlUnlinkNode(deleteNode);
3623 xmlFreeNode(deleteNode);
3624 }
3625 }
3626 #endif /* end of else XSLT_REFACTORED */
3627
3628 /**
3629 * xsltGatherNamespaces:
3630 * @style: the XSLT stylesheet
3631 *
3632 * Browse the stylesheet and build the namspace hash table which
3633 * will be used for XPath interpretation. If needed do a bit of normalization
3634 */
3635
3636 static void
3637 xsltGatherNamespaces(xsltStylesheetPtr style) {
3638 xmlNodePtr cur;
3639 const xmlChar *URI;
3640
3641 if (style == NULL)
3642 return;
3643 /*
3644 * TODO: basically if the stylesheet uses the same prefix for different
3645 * patterns, well they may be in problem, hopefully they will get
3646 * a warning first.
3647 */
3648 /*
3649 * TODO: Eliminate the use of the hash for XPath expressions.
3650 * An expression should be evaluated in the context of the in-scope
3651 * namespaces; eliminate the restriction of an XML document to contain
3652 * no duplicate prefixes for different namespace names.
3653 *
3654 */
3655 cur = xmlDocGetRootElement(style->doc);
3656 while (cur != NULL) {
3657 if (cur->type == XML_ELEMENT_NODE) {
3658 xmlNsPtr ns = cur->nsDef;
3659 while (ns != NULL) {
3660 if (ns->prefix != NULL) {
3661 if (style->nsHash == NULL) {
3662 style->nsHash = xmlHashCreate(10);
3663 if (style->nsHash == NULL) {
3664 xsltTransformError(NULL, style, cur,
3665 "xsltGatherNamespaces: failed to create hash table\n");
3666 style->errors++;
3667 return;
3668 }
3669 }
3670 URI = xmlHashLookup(style->nsHash, ns->prefix);
3671 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3672 xsltTransformError(NULL, style, cur,
3673 "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3674 style->warnings++;
3675 } else if (URI == NULL) {
3676 xmlHashUpdateEntry(style->nsHash, ns->prefix,
3677 (void *) ns->href, (xmlHashDeallocator)xmlFree);
3678
3679 #ifdef WITH_XSLT_DEBUG_PARSING
3680 xsltGenericDebug(xsltGenericDebugContext,
3681 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3682 #endif
3683 }
3684 }
3685 ns = ns->next;
3686 }
3687 }
3688
3689 /*
3690 * Skip to next node
3691 */
3692 if (cur->children != NULL) {
3693 if (cur->children->type != XML_ENTITY_DECL) {
3694 cur = cur->children;
3695 continue;
3696 }
3697 }
3698 if (cur->next != NULL) {
3699 cur = cur->next;
3700 continue;
3701 }
3702
3703 do {
3704 cur = cur->parent;
3705 if (cur == NULL)
3706 break;
3707 if (cur == (xmlNodePtr) style->doc) {
3708 cur = NULL;
3709 break;
3710 }
3711 if (cur->next != NULL) {
3712 cur = cur->next;
3713 break;
3714 }
3715 } while (cur != NULL);
3716 }
3717 }
3718
3719 #ifdef XSLT_REFACTORED
3720
3721 static xsltStyleType
3722 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3723 xmlNodePtr node)
3724 {
3725 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3726 (node->name == NULL))
3727 return(0);
3728
3729 if (node->name[0] == 'a') {
3730 if (IS_XSLT_NAME(node, "apply-templates"))
3731 return(XSLT_FUNC_APPLYTEMPLATES);
3732 else if (IS_XSLT_NAME(node, "attribute"))
3733 return(XSLT_FUNC_ATTRIBUTE);
3734 else if (IS_XSLT_NAME(node, "apply-imports"))
3735 return(XSLT_FUNC_APPLYIMPORTS);
3736 else if (IS_XSLT_NAME(node, "attribute-set"))
3737 return(0);
3738
3739 } else if (node->name[0] == 'c') {
3740 if (IS_XSLT_NAME(node, "choose"))
3741 return(XSLT_FUNC_CHOOSE);
3742 else if (IS_XSLT_NAME(node, "copy"))
3743 return(XSLT_FUNC_COPY);
3744 else if (IS_XSLT_NAME(node, "copy-of"))
3745 return(XSLT_FUNC_COPYOF);
3746 else if (IS_XSLT_NAME(node, "call-template"))
3747 return(XSLT_FUNC_CALLTEMPLATE);
3748 else if (IS_XSLT_NAME(node, "comment"))
3749 return(XSLT_FUNC_COMMENT);
3750
3751 } else if (node->name[0] == 'd') {
3752 if (IS_XSLT_NAME(node, "document"))
3753 return(XSLT_FUNC_DOCUMENT);
3754 else if (IS_XSLT_NAME(node, "decimal-format"))
3755 return(0);
3756
3757 } else if (node->name[0] == 'e') {
3758 if (IS_XSLT_NAME(node, "element"))
3759 return(XSLT_FUNC_ELEMENT);
3760
3761 } else if (node->name[0] == 'f') {
3762 if (IS_XSLT_NAME(node, "for-each"))
3763 return(XSLT_FUNC_FOREACH);
3764 else if (IS_XSLT_NAME(node, "fallback"))
3765 return(XSLT_FUNC_FALLBACK);
3766
3767 } else if (*(node->name) == 'i') {
3768 if (IS_XSLT_NAME(node, "if"))
3769 return(XSLT_FUNC_IF);
3770 else if (IS_XSLT_NAME(node, "include"))
3771 return(0);
3772 else if (IS_XSLT_NAME(node, "import"))
3773 return(0);
3774
3775 } else if (*(node->name) == 'k') {
3776 if (IS_XSLT_NAME(node, "key"))
3777 return(0);
3778
3779 } else if (*(node->name) == 'm') {
3780 if (IS_XSLT_NAME(node, "message"))
3781 return(XSLT_FUNC_MESSAGE);
3782
3783 } else if (*(node->name) == 'n') {
3784 if (IS_XSLT_NAME(node, "number"))
3785 return(XSLT_FUNC_NUMBER);
3786 else if (IS_XSLT_NAME(node, "namespace-alias"))
3787 return(0);
3788
3789 } else if (*(node->name) == 'o') {
3790 if (IS_XSLT_NAME(node, "otherwise"))
3791 return(XSLT_FUNC_OTHERWISE);
3792 else if (IS_XSLT_NAME(node, "output"))
3793 return(0);
3794
3795 } else if (*(node->name) == 'p') {
3796 if (IS_XSLT_NAME(node, "param"))
3797 return(XSLT_FUNC_PARAM);
3798 else if (IS_XSLT_NAME(node, "processing-instruction"))
3799 return(XSLT_FUNC_PI);
3800 else if (IS_XSLT_NAME(node, "preserve-space"))
3801 return(0);
3802
3803 } else if (*(node->name) == 's') {
3804 if (IS_XSLT_NAME(node, "sort"))
3805 return(XSLT_FUNC_SORT);
3806 else if (IS_XSLT_NAME(node, "strip-space"))
3807 return(0);
3808 else if (IS_XSLT_NAME(node, "stylesheet"))
3809 return(0);
3810
3811 } else if (node->name[0] == 't') {
3812 if (IS_XSLT_NAME(node, "text"))
3813 return(XSLT_FUNC_TEXT);
3814 else if (IS_XSLT_NAME(node, "template"))
3815 return(0);
3816 else if (IS_XSLT_NAME(node, "transform"))
3817 return(0);
3818
3819 } else if (*(node->name) == 'v') {
3820 if (IS_XSLT_NAME(node, "value-of"))
3821 return(XSLT_FUNC_VALUEOF);
3822 else if (IS_XSLT_NAME(node, "variable"))
3823 return(XSLT_FUNC_VARIABLE);
3824
3825 } else if (*(node->name) == 'w') {
3826 if (IS_XSLT_NAME(node, "when"))
3827 return(XSLT_FUNC_WHEN);
3828 if (IS_XSLT_NAME(node, "with-param"))
3829 return(XSLT_FUNC_WITHPARAM);
3830 }
3831 return(0);
3832 }
3833
3834 /**
3835 * xsltParseAnyXSLTElem:
3836 *
3837 * @cctxt: the compilation context
3838 * @elem: the element node of the XSLT instruction
3839 *
3840 * Parses, validates the content models and compiles XSLT instructions.
3841 *
3842 * Returns 0 if everything's fine;
3843 * -1 on API or internal errors.
3844 */
3845 int
3846 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
3847 {
3848 if ((cctxt == NULL) || (elem == NULL) ||
3849 (elem->type != XML_ELEMENT_NODE))
3850 return(-1);
3851
3852 elem->psvi = NULL;
3853
3854 if (! (IS_XSLT_ELEM_FAST(elem)))
3855 return(-1);
3856 /*
3857 * Detection of handled content of extension instructions.
3858 */
3859 if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
3860 cctxt->inode->extContentHandled = 1;
3861 }
3862
3863 xsltCompilerNodePush(cctxt, elem);
3864 /*
3865 * URGENT TODO: Find a way to speed up this annoying redundant
3866 * textual node-name and namespace comparison.
3867 */
3868 if (cctxt->inode->prev->curChildType != 0)
3869 cctxt->inode->type = cctxt->inode->prev->curChildType;
3870 else
3871 cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
3872 /*
3873 * Update the in-scope namespaces if needed.
3874 */
3875 if (elem->nsDef != NULL)
3876 cctxt->inode->inScopeNs =
3877 xsltCompilerBuildInScopeNsList(cctxt, elem);
3878 /*
3879 * xsltStylePreCompute():
3880 * This will compile the information found on the current
3881 * element's attributes. NOTE that this won't process the
3882 * children of the instruction.
3883 */
3884 xsltStylePreCompute(cctxt->style, elem);
3885 /*
3886 * TODO: How to react on errors in xsltStylePreCompute() ?
3887 */
3888
3889 /*
3890 * Validate the content model of the XSLT-element.
3891 */
3892 switch (cctxt->inode->type) {
3893 case XSLT_FUNC_APPLYIMPORTS:
3894 /* EMPTY */
3895 goto empty_content;
3896 case XSLT_FUNC_APPLYTEMPLATES:
3897 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3898 goto apply_templates;
3899 case XSLT_FUNC_ATTRIBUTE:
3900 /* <!-- Content: template --> */
3901 goto sequence_constructor;
3902 case XSLT_FUNC_CALLTEMPLATE:
3903 /* <!-- Content: xsl:with-param* --> */
3904 goto call_template;
3905 case XSLT_FUNC_CHOOSE:
3906 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3907 goto choose;
3908 case XSLT_FUNC_COMMENT:
3909 /* <!-- Content: template --> */
3910 goto sequence_constructor;
3911 case XSLT_FUNC_COPY:
3912 /* <!-- Content: template --> */
3913 goto sequence_constructor;
3914 case XSLT_FUNC_COPYOF:
3915 /* EMPTY */
3916 goto empty_content;
3917 case XSLT_FUNC_DOCUMENT: /* Extra one */
3918 /* ?? template ?? */
3919 goto sequence_constructor;
3920 case XSLT_FUNC_ELEMENT:
3921 /* <!-- Content: template --> */
3922 goto sequence_constructor;
3923 case XSLT_FUNC_FALLBACK:
3924 /* <!-- Content: template --> */
3925 goto sequence_constructor;
3926 case XSLT_FUNC_FOREACH:
3927 /* <!-- Content: (xsl:sort*, template) --> */
3928 goto for_each;
3929 case XSLT_FUNC_IF:
3930 /* <!-- Content: template --> */
3931 goto sequence_constructor;
3932 case XSLT_FUNC_OTHERWISE:
3933 /* <!-- Content: template --> */
3934 goto sequence_constructor;
3935 case XSLT_FUNC_MESSAGE:
3936 /* <!-- Content: template --> */
3937 goto sequence_constructor;
3938 case XSLT_FUNC_NUMBER:
3939 /* EMPTY */
3940 goto empty_content;
3941 case XSLT_FUNC_PARAM:
3942 /*
3943 * Check for redefinition.
3944 */
3945 if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3946 xsltVarInfoPtr ivar = cctxt->ivar;
3947
3948 do {
3949 if ((ivar->name ==
3950 ((xsltStyleItemParamPtr) elem->psvi)->name) &&
3951 (ivar->nsName ==
3952 ((xsltStyleItemParamPtr) elem->psvi)->ns))
3953 {
3954 elem->psvi = NULL;
3955 xsltTransformError(NULL, cctxt->style, elem,
3956 "Redefinition of variable or parameter '%s'.\n",
3957 ivar->name);
3958 cctxt->style->errors++;
3959 goto error;
3960 }
3961 ivar = ivar->prev;
3962 } while (ivar != NULL);
3963 }
3964 /* <!-- Content: template --> */
3965 goto sequence_constructor;
3966 case XSLT_FUNC_PI:
3967 /* <!-- Content: template --> */
3968 goto sequence_constructor;
3969 case XSLT_FUNC_SORT:
3970 /* EMPTY */
3971 goto empty_content;
3972 case XSLT_FUNC_TEXT:
3973 /* <!-- Content: #PCDATA --> */
3974 goto text;
3975 case XSLT_FUNC_VALUEOF:
3976 /* EMPTY */
3977 goto empty_content;
3978 case XSLT_FUNC_VARIABLE:
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 ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
3988 (ivar->nsName ==
3989 ((xsltStyleItemVariablePtr) 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_WHEN:
4004 /* <!-- Content: template --> */
4005 goto sequence_constructor;
4006 case XSLT_FUNC_WITHPARAM:
4007 /* <!-- Content: template --> */
4008 goto sequence_constructor;
4009 default:
4010 #ifdef WITH_XSLT_DEBUG_PARSING
4011 xsltGenericDebug(xsltGenericDebugContext,
4012 "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4013 elem->name);
4014 #endif
4015 xsltTransformError(NULL, cctxt->style, elem,
4016 "xsltParseXSLTNode: Internal error; "
4017 "unhandled XSLT element '%s'.\n", elem->name);
4018 cctxt->style->errors++;
4019 goto internal_err;
4020 }
4021
4022 apply_templates:
4023 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4024 if (elem->children != NULL) {
4025 xmlNodePtr child = elem->children;
4026 do {
4027 if (child->type == XML_ELEMENT_NODE) {
4028 if (IS_XSLT_ELEM_FAST(child)) {
4029 if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
4030 cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4031 xsltParseAnyXSLTElem(cctxt, child);
4032 } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
4033 cctxt->inode->curChildType = XSLT_FUNC_SORT;
4034 xsltParseAnyXSLTElem(cctxt, child);
4035 } else
4036 xsltParseContentError(cctxt->style, child);
4037 } else
4038 xsltParseContentError(cctxt->style, child);
4039 }
4040 child = child->next;
4041 } while (child != NULL);
4042 }
4043 goto exit;
4044
4045 call_template:
4046 /* <!-- Content: xsl:with-param* --> */
4047 if (elem->children != NULL) {
4048 xmlNodePtr child = elem->children;
4049 do {
4050 if (child->type == XML_ELEMENT_NODE) {
4051 if (IS_XSLT_ELEM_FAST(child)) {
4052 xsltStyleType type;
4053
4054 type = xsltGetXSLTElementTypeByNode(cctxt, child);
4055 if (type == XSLT_FUNC_WITHPARAM) {
4056 cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4057 xsltParseAnyXSLTElem(cctxt, child);
4058 } else {
4059 xsltParseContentError(cctxt->style, child);
4060 }
4061 } else
4062 xsltParseContentError(cctxt->style, child);
4063 }
4064 child = child->next;
4065 } while (child != NULL);
4066 }
4067 goto exit;
4068
4069 text:
4070 if (elem->children != NULL) {
4071 xmlNodePtr child = elem->children;
4072 do {
4073 if ((child->type != XML_TEXT_NODE) &&
4074 (child->type != XML_CDATA_SECTION_NODE))
4075 {
4076 xsltTransformError(NULL, cctxt->style, elem,
4077 "The XSLT 'text' element must have only character "
4078 "data as content.\n");
4079 }
4080 child = child->next;
4081 } while (child != NULL);
4082 }
4083 goto exit;
4084
4085 empty_content:
4086 if (elem->children != NULL) {
4087 xmlNodePtr child = elem->children;
4088 /*
4089 * Relaxed behaviour: we will allow whitespace-only text-nodes.
4090 */
4091 do {
4092 if (((child->type != XML_TEXT_NODE) &&
4093 (child->type != XML_CDATA_SECTION_NODE)) ||
4094 (! IS_BLANK_NODE(child)))
4095 {
4096 xsltTransformError(NULL, cctxt->style, elem,
4097 "This XSLT element must have no content.\n");
4098 cctxt->style->errors++;
4099 break;
4100 }
4101 child = child->next;
4102 } while (child != NULL);
4103 }
4104 goto exit;
4105
4106 choose:
4107 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4108 /*
4109 * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4110 * The old behaviour did not check this.
4111 * NOTE: In XSLT 2.0 they are stripped beforehand
4112 * if whitespace-only (regardless of xml:space).
4113 */
4114 if (elem->children != NULL) {
4115 xmlNodePtr child = elem->children;
4116 int nbWhen = 0, nbOtherwise = 0, err = 0;
4117 do {
4118 if (child->type == XML_ELEMENT_NODE) {
4119 if (IS_XSLT_ELEM_FAST(child)) {
4120 xsltStyleType type;
4121
4122 type = xsltGetXSLTElementTypeByNode(cctxt, child);
4123 if (type == XSLT_FUNC_WHEN) {
4124 nbWhen++;
4125 if (nbOtherwise) {
4126 xsltParseContentError(cctxt->style, child);
4127 err = 1;
4128 break;
4129 }
4130 cctxt->inode->curChildType = XSLT_FUNC_WHEN;
4131 xsltParseAnyXSLTElem(cctxt, child);
4132 } else if (type == XSLT_FUNC_OTHERWISE) {
4133 if (! nbWhen) {
4134 xsltParseContentError(cctxt->style, child);
4135 err = 1;
4136 break;
4137 }
4138 if (nbOtherwise) {
4139 xsltTransformError(NULL, cctxt->style, elem,
4140 "The XSLT 'choose' element must not contain "
4141 "more than one XSLT 'otherwise' element.\n");
4142 cctxt->style->errors++;
4143 err = 1;
4144 break;
4145 }
4146 nbOtherwise++;
4147 cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
4148 xsltParseAnyXSLTElem(cctxt, child);
4149 } else
4150 xsltParseContentError(cctxt->style, child);
4151 } else
4152 xsltParseContentError(cctxt->style, child);
4153 }
4154 /*
4155 else
4156 xsltParseContentError(cctxt, child);
4157 */
4158 child = child->next;
4159 } while (child != NULL);
4160 if ((! err) && (! nbWhen)) {
4161 xsltTransformError(NULL, cctxt->style, elem,
4162 "The XSLT element 'choose' must contain at least one "
4163 "XSLT element 'when'.\n");
4164 cctxt->style->errors++;
4165 }
4166 }
4167 goto exit;
4168
4169 for_each:
4170 /* <!-- Content: (xsl:sort*, template) --> */
4171 /*
4172 * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4173 * The old behaviour did not allow this, but it catched this
4174 * only at transformation-time.
4175 * In XSLT 2.0 they are stripped beforehand if whitespace-only
4176 * (regardless of xml:space).
4177 */
4178 if (elem->children != NULL) {
4179 xmlNodePtr child = elem->children;
4180 /*
4181 * Parse xsl:sort first.
4182 */
4183 do {
4184 if ((child->type == XML_ELEMENT_NODE) &&
4185 IS_XSLT_ELEM_FAST(child))
4186 {
4187 if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
4188 XSLT_FUNC_SORT)
4189 {
4190 cctxt->inode->curChildType = XSLT_FUNC_SORT;
4191 xsltParseAnyXSLTElem(cctxt, child);
4192 } else
4193 break;
4194 } else
4195 break;
4196 child = child->next;
4197 } while (child != NULL);
4198 /*
4199 * Parse the sequece constructor.
4200 */
4201 if (child != NULL)
4202 xsltParseSequenceConstructor(cctxt, child);
4203 }
4204 goto exit;
4205
4206 sequence_constructor:
4207 /*
4208 * Parse the sequence constructor.
4209 */
4210 if (elem->children != NULL)
4211 xsltParseSequenceConstructor(cctxt, elem->children);
4212
4213 /*
4214 * Register information for vars/params. Only needed if there
4215 * are any following siblings.
4216 */
4217 if ((elem->next != NULL) &&
4218 ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
4219 (cctxt->inode->type == XSLT_FUNC_PARAM)))
4220 {
4221 if ((elem->psvi != NULL) &&
4222 (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
4223 {
4224 xsltCompilerVarInfoPush(cctxt, elem,
4225 ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
4226 ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
4227 }
4228 }
4229
4230 error:
4231 exit:
4232 xsltCompilerNodePop(cctxt, elem);
4233 return(0);
4234
4235 internal_err:
4236 xsltCompilerNodePop(cctxt, elem);
4237 return(-1);
4238 }
4239
4240 /**
4241 * xsltForwardsCompatUnkownItemCreate:
4242 *
4243 * @cctxt: the compilation context
4244 *
4245 * Creates a compiled representation of the unknown
4246 * XSLT instruction.
4247 *
4248 * Returns the compiled representation.
4249 */
4250 static xsltStyleItemUknownPtr
4251 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
4252 {
4253 xsltStyleItemUknownPtr item;
4254
4255 item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
4256 if (item == NULL) {
4257 xsltTransformError(NULL, cctxt->style, NULL,
4258 "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4259 "Failed to allocate memory.\n");
4260 cctxt->style->errors++;
4261 return(NULL);
4262 }
4263 memset(item, 0, sizeof(xsltStyleItemUknown));
4264 item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
4265 /*
4266 * Store it in the stylesheet.
4267 */
4268 item->next = cctxt->style->preComps;
4269 cctxt->style->preComps = (xsltElemPreCompPtr) item;
4270 return(item);
4271 }
4272
4273 /**
4274 * xsltParseUnknownXSLTElem:
4275 *
4276 * @cctxt: the compilation context
4277 * @node: the element of the unknown XSLT instruction
4278 *
4279 * Parses an unknown XSLT element.
4280 * If forwards compatible mode is enabled this will allow
4281 * such an unknown XSLT and; otherwise it is rejected.
4282 *
4283 * Returns 1 in the unknown XSLT instruction is rejected,
4284 * 0 if everything's fine and
4285 * -1 on API or internal errors.
4286 */
4287 static int
4288 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
4289 xmlNodePtr node)
4290 {
4291 if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
4292 return(-1);
4293
4294 /*
4295 * Detection of handled content of extension instructions.
4296 */
4297 if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4298 cctxt->inode->extContentHandled = 1;
4299 }
4300 if (cctxt->inode->forwardsCompat == 0) {
4301 /*
4302 * We are not in forwards-compatible mode, so raise an error.
4303 */
4304 xsltTransformError(NULL, cctxt->style, node,
4305 "Unknown XSLT element '%s'.\n", node->name);
4306 cctxt->style->errors++;
4307 return(1);
4308 }
4309 /*
4310 * Forwards-compatible mode.
4311 * ------------------------
4312 *
4313 * Parse/compile xsl:fallback elements.
4314 *
4315 * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4316 * ANSWER: No, since in the stylesheet the fallback behaviour might
4317 * also be provided by using the XSLT function "element-available".
4318 */
4319 if (cctxt->unknownItem == NULL) {
4320 /*
4321 * Create a singleton for all unknown XSLT instructions.
4322 */
4323 cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
4324 if (cctxt->unknownItem == NULL) {
4325 node->psvi = NULL;
4326 return(-1);
4327 }
4328 }
4329 node->psvi = cctxt->unknownItem;
4330 if (node->children == NULL)
4331 return(0);
4332 else {
4333 xmlNodePtr child = node->children;
4334
4335 xsltCompilerNodePush(cctxt, node);
4336 /*
4337 * Update the in-scope namespaces if needed.
4338 */
4339 if (node->nsDef != NULL)
4340 cctxt->inode->inScopeNs =
4341 xsltCompilerBuildInScopeNsList(cctxt, node);
4342 /*
4343 * Parse all xsl:fallback children.
4344 */
4345 do {
4346 if ((child->type == XML_ELEMENT_NODE) &&
4347 IS_XSLT_ELEM_FAST(child) &&
4348 IS_XSLT_NAME(child, "fallback"))
4349 {
4350 cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
4351 xsltParseAnyXSLTElem(cctxt, child);
4352 }
4353 child = child->next;
4354 } while (child != NULL);
4355
4356 xsltCompilerNodePop(cctxt, node);
4357 }
4358 return(0);
4359 }
4360
4361 /**
4362 * xsltParseSequenceConstructor:
4363 *
4364 * @cctxt: the compilation context
4365 * @cur: the start-node of the content to be parsed
4366 *
4367 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4368 * This will additionally remove xsl:text elements from the tree.
4369 */
4370 void
4371 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
4372 {
4373 xsltStyleType type;
4374 xmlNodePtr deleteNode = NULL;
4375
4376 if (cctxt == NULL) {
4377 xmlGenericError(xmlGenericErrorContext,
4378 "xsltParseSequenceConstructor: Bad arguments\n");
4379 cctxt->style->errors++;
4380 return;
4381 }
4382 /*
4383 * Detection of handled content of extension instructions.
4384 */
4385 if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4386 cctxt->inode->extContentHandled = 1;
4387 }
4388 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
4389 return;
4390 /*
4391 * This is the content reffered to as a "template".
4392 * E.g. an xsl:element has such content model:
4393 * <xsl:element
4394 * name = { qname }
4395 * namespace = { uri-reference }
4396 * use-attribute-sets = qnames>
4397 * <!-- Content: template -->
4398 *
4399 * NOTE that in XSLT-2 the term "template" was abandoned due to
4400 * confusion with xsl:template and the term "sequence constructor"
4401 * was introduced instead.
4402 *
4403 * The following XSLT-instructions are allowed to appear:
4404 * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4405 * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4406 * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4407 * xsl:message, xsl:fallback,
4408 * xsl:processing-instruction, xsl:comment, xsl:element
4409 * xsl:attribute.
4410 * Additional allowed content:
4411 * 1) extension instructions
4412 * 2) literal result elements
4413 * 3) PCDATA
4414 *
4415 * NOTE that this content model does *not* allow xsl:param.
4416 */
4417 while (cur != NULL) {
4418 if (deleteNode != NULL) {
4419 #ifdef WITH_XSLT_DEBUG_BLANKS
4420 xsltGenericDebug(xsltGenericDebugContext,
4421 "xsltParseSequenceConstructor: removing xsl:text element\n");
4422 #endif
4423 xmlUnlinkNode(deleteNode);
4424 xmlFreeNode(deleteNode);
4425 deleteNode = NULL;
4426 }
4427 if (cur->type == XML_ELEMENT_NODE) {
4428
4429 if (cur->psvi == xsltXSLTTextMarker) {
4430 /*
4431 * xsl:text elements
4432 * --------------------------------------------------------
4433 */
4434 xmlNodePtr tmp;
4435
4436 cur->psvi = NULL;
4437 /*
4438 * Mark the xsl:text element for later deletion.
4439 */
4440 deleteNode = cur;
4441 /*
4442 * Validate content.
4443 */
4444 tmp = cur->children;
4445 if (tmp) {
4446 /*
4447 * We don't expect more than one text-node in the
4448 * content, since we already merged adjacent
4449 * text/CDATA-nodes and eliminated PI/comment-nodes.
4450 */
4451 if ((tmp->type == XML_TEXT_NODE) ||
4452 (tmp->next == NULL))
4453 {
4454 /*
4455 * Leave the contained text-node in the tree.
4456 */
4457 xmlUnlinkNode(tmp);
4458 xmlAddPrevSibling(cur, tmp);
4459 } else {
4460 tmp = NULL;
4461 xsltTransformError(NULL, cctxt->style, cur,
4462 "Element 'xsl:text': Invalid type "
4463 "of node found in content.\n");
4464 cctxt->style->errors++;
4465 }
4466 }
4467 if (cur->properties) {
4468 xmlAttrPtr attr;
4469 /*
4470 * TODO: We need to report errors for
4471 * invalid attrs.
4472 */
4473 attr = cur->properties;
4474 do {
4475 if ((attr->ns == NULL) &&
4476 (attr->name != NULL) &&
4477 (attr->name[0] == 'd') &&
4478 xmlStrEqual(attr->name,
4479 BAD_CAST "disable-output-escaping"))
4480 {
4481 /*
4482 * Attr "disable-output-escaping".
4483 * XSLT-2: This attribute is deprecated.
4484 */
4485 if ((attr->children != NULL) &&
4486 xmlStrEqual(attr->children->content,
4487 BAD_CAST "yes"))
4488 {
4489 /*
4490 * Disable output escaping for this
4491 * text node.
4492 */
4493 if (tmp)
4494 tmp->name = xmlStringTextNoenc;
4495 } else if ((attr->children == NULL) ||
4496 (attr->children->content == NULL) ||
4497 (!xmlStrEqual(attr->children->content,
4498 BAD_CAST "no")))
4499 {
4500 xsltTransformError(NULL, cctxt->style,
4501 cur,
4502 "Attribute 'disable-output-escaping': "
4503 "Invalid value. Expected is "
4504 "'yes' or 'no'.\n");
4505 cctxt->style->errors++;
4506 }
4507 break;
4508 }
4509 attr = attr->next;
4510 } while (attr != NULL);
4511 }
4512 } else if (IS_XSLT_ELEM_FAST(cur)) {
4513 /*
4514 * TODO: Using the XSLT-marker is still not stable yet.
4515 */
4516 /* if (cur->psvi == xsltXSLTElemMarker) { */
4517 /*
4518 * XSLT instructions
4519 * --------------------------------------------------------
4520 */
4521 cur->psvi = NULL;
4522 type = xsltGetXSLTElementTypeByNode(cctxt, cur);
4523 switch (type) {
4524 case XSLT_FUNC_APPLYIMPORTS:
4525 case XSLT_FUNC_APPLYTEMPLATES:
4526 case XSLT_FUNC_ATTRIBUTE:
4527 case XSLT_FUNC_CALLTEMPLATE:
4528 case XSLT_FUNC_CHOOSE:
4529 case XSLT_FUNC_COMMENT:
4530 case XSLT_FUNC_COPY:
4531 case XSLT_FUNC_COPYOF:
4532 case XSLT_FUNC_DOCUMENT: /* Extra one */
4533 case XSLT_FUNC_ELEMENT:
4534 case XSLT_FUNC_FALLBACK:
4535 case XSLT_FUNC_FOREACH:
4536 case XSLT_FUNC_IF:
4537 case XSLT_FUNC_MESSAGE:
4538 case XSLT_FUNC_NUMBER:
4539 case XSLT_FUNC_PI:
4540 case XSLT_FUNC_TEXT:
4541 case XSLT_FUNC_VALUEOF:
4542 case XSLT_FUNC_VARIABLE:
4543 /*
4544 * Parse the XSLT element.
4545 */
4546 cctxt->inode->curChildType = type;
4547 xsltParseAnyXSLTElem(cctxt, cur);
4548 break;
4549 default:
4550 xsltParseUnknownXSLTElem(cctxt, cur);
4551 cur = cur->next;
4552 continue;
4553 }
4554 } else {
4555 /*
4556 * Non-XSLT elements
4557 * -----------------
4558 */
4559 xsltCompilerNodePush(cctxt, cur);
4560 /*
4561 * Update the in-scope namespaces if needed.
4562 */
4563 if (cur->nsDef != NULL)
4564 cctxt->inode->inScopeNs =
4565 xsltCompilerBuildInScopeNsList(cctxt, cur);
4566 /*
4567 * The current element is either a literal result element
4568 * or an extension instruction.
4569 *
4570 * Process attr "xsl:extension-element-prefixes".
4571 * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4572 * processed by the implementor of the extension function;
4573 * i.e., it won't be handled by the XSLT processor.
4574 */
4575 /* SPEC 1.0:
4576 * "exclude-result-prefixes" is only allowed on literal
4577 * result elements and "xsl:exclude-result-prefixes"
4578 * on xsl:stylesheet/xsl:transform.
4579 * SPEC 2.0:
4580 * "There are a number of standard attributes
4581 * that may appear on any XSLT element: specifically
4582 * version, exclude-result-prefixes,
4583 * extension-element-prefixes, xpath-default-namespace,
4584 * default-collation, and use-when."
4585 *
4586 * SPEC 2.0:
4587 * For literal result elements:
4588 * "xsl:version, xsl:exclude-result-prefixes,
4589 * xsl:extension-element-prefixes,
4590 * xsl:xpath-default-namespace,
4591 * xsl:default-collation, or xsl:use-when."
4592 */
4593 if (cur->properties)
4594 cctxt->inode->extElemNs =
4595 xsltParseExtElemPrefixes(cctxt,
4596 cur, cctxt->inode->extElemNs,
4597 XSLT_ELEMENT_CATEGORY_LRE);
4598 /*
4599 * Eval if we have an extension instruction here.
4600 */
4601 if ((cur->ns != NULL) &&
4602 (cctxt->inode->extElemNs != NULL) &&
4603 (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
4604 {
4605 /*
4606 * Extension instructions
4607 * ----------------------------------------------------
4608 * Mark the node information.
4609 */
4610 cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
4611 cctxt->inode->extContentHandled = 0;
4612 if (cur->psvi != NULL) {
4613 cur->psvi = NULL;
4614 /*
4615 * TODO: Temporary sanity check.
4616 */
4617 xsltTransformError(NULL, cctxt->style, cur,
4618 "Internal error in xsltParseSequenceConstructor(): "
4619 "Occupied PSVI field.\n");
4620 cctxt->style->errors++;
4621 cur = cur->next;
4622 continue;
4623 }
4624 cur->psvi = (void *)
4625 xsltPreComputeExtModuleElement(cctxt->style, cur);
4626
4627 if (cur->psvi == NULL) {
4628 /*
4629 * OLD COMMENT: "Unknown element, maybe registered
4630 * at the context level. Mark it for later
4631 * recognition."
4632 * QUESTION: What does the xsltExtMarker mean?
4633 * ANSWER: It is used in
4634 * xsltApplySequenceConstructor() at
4635 * transformation-time to look out for extension
4636 * registered in the transformation context.
4637 */
4638 cur->psvi = (void *) xsltExtMarker;
4639 }
4640 /*
4641 * BIG NOTE: Now the ugly part. In previous versions
4642 * of Libxslt (until 1.1.16), all the content of an
4643 * extension instruction was processed and compiled without
4644 * the need of the extension-author to explicitely call
4645 * such a processing;.We now need to mimic this old
4646 * behaviour in order to avoid breaking old code
4647 * on the extension-author's side.
4648 * The mechanism:
4649 * 1) If the author does *not* set the
4650 * compile-time-flag @extContentHandled, then we'll
4651 * parse the content assuming that it's a "template"
4652 * (or "sequence constructor in XSLT 2.0 terms).
4653 * NOTE: If the extension is registered at
4654 * transformation-time only, then there's no way of
4655 * knowing that content shall be valid, and we'll
4656 * process the content the same way.
4657 * 2) If the author *does* set the flag, then we'll assume
4658 * that the author has handled the parsing him/herself
4659 * (e.g. called xsltParseSequenceConstructor(), etc.
4660 * explicitely in his/her code).
4661 */
4662 if ((cur->children != NULL) &&
4663 (cctxt->inode->extContentHandled == 0))
4664 {
4665 /*
4666 * Default parsing of the content using the
4667 * sequence-constructor model.
4668 */
4669 xsltParseSequenceConstructor(cctxt, cur->children);
4670 }
4671 } else {
4672 /*
4673 * Literal result element
4674 * ----------------------------------------------------
4675 * Allowed XSLT attributes:
4676 * xsl:extension-element-prefixes CDATA #IMPLIED
4677 * xsl:exclude-result-prefixes CDATA #IMPLIED
4678 * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4679 * xsl:version NMTOKEN #IMPLIED
4680 */
4681 cur->psvi = NULL;
4682 cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
4683 if (cur->properties != NULL) {
4684 xmlAttrPtr attr = cur->properties;
4685 /*
4686 * Attribute "xsl:exclude-result-prefixes".
4687 */
4688 cctxt->inode->exclResultNs =
4689 xsltParseExclResultPrefixes(cctxt, cur,
4690 cctxt->inode->exclResultNs,
4691 XSLT_ELEMENT_CATEGORY_LRE);
4692 /*
4693 * Attribute "xsl:version".
4694 */
4695 xsltParseAttrXSLTVersion(cctxt, cur,
4696 XSLT_ELEMENT_CATEGORY_LRE);
4697 /*
4698 * Report invalid XSLT attributes.
4699 * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4700 * next to xsl:version, xsl:exclude-result-prefixes and
4701 * xsl:extension-element-prefixes.
4702 *
4703 * Mark all XSLT attributes, in order to skip such
4704 * attributes when instantiating the LRE.
4705 */
4706 do {
4707 if ((attr->psvi != xsltXSLTAttrMarker) &&
4708 IS_XSLT_ATTR_FAST(attr))
4709 {
4710 if (! xmlStrEqual(attr->name,
4711 BAD_CAST "use-attribute-sets"))
4712 {
4713 xsltTransformError(NULL, cctxt->style,
4714 cur,
4715 "Unknown XSLT attribute '%s'.\n",
4716 attr->name);
4717 cctxt->style->errors++;
4718 } else {
4719 /*
4720 * XSLT attr marker.
4721 */
4722 attr->psvi = (void *) xsltXSLTAttrMarker;
4723 }
4724 }
4725 attr = attr->next;
4726 } while (attr != NULL);
4727 }
4728 /*
4729 * Create/reuse info for the literal result element.
4730 */
4731 if (cctxt->inode->nsChanged)
4732 xsltLREInfoCreate(cctxt, cur, 1);
4733 cur->psvi = cctxt->inode->litResElemInfo;
4734 /*
4735 * Apply ns-aliasing on the element and on its attributes.
4736 */
4737 if (cctxt->hasNsAliases)
4738 xsltLREBuildEffectiveNs(cctxt, cur);
4739 /*
4740 * Compile attribute value templates (AVT).
4741 */
4742 if (cur->properties) {
4743 xmlAttrPtr attr = cur->properties;
4744
4745 while (attr != NULL) {
4746 xsltCompileAttr(cctxt->style, attr);
4747 attr = attr->next;
4748 }
4749 }
4750 /*
4751 * Parse the content, which is defined to be a "template"
4752 * (or "sequence constructor" in XSLT 2.0 terms).
4753 */
4754 if (cur->children != NULL) {
4755 xsltParseSequenceConstructor(cctxt, cur->children);
4756 }
4757 }
4758 /*
4759 * Leave the non-XSLT element.
4760 */
4761 xsltCompilerNodePop(cctxt, cur);
4762 }
4763 }
4764 cur = cur->next;
4765 }
4766 if (deleteNode != NULL) {
4767 #ifdef WITH_XSLT_DEBUG_BLANKS
4768 xsltGenericDebug(xsltGenericDebugContext,
4769 "xsltParseSequenceConstructor: removing xsl:text element\n");
4770 #endif
4771 xmlUnlinkNode(deleteNode);
4772 xmlFreeNode(deleteNode);
4773 deleteNode = NULL;
4774 }
4775 }
4776
4777 /**
4778 * xsltParseTemplateContent:
4779 * @style: the XSLT stylesheet
4780 * @templ: the node containing the content to be parsed
4781 *
4782 * Parses and compiles the content-model of an xsl:template element.
4783 * Note that this is *not* the "template" content model (or "sequence
4784 * constructor" in XSLT 2.0); it it allows addional xsl:param
4785 * elements as immediate children of @templ.
4786 *
4787 * Called by:
4788 * exsltFuncFunctionComp() (EXSLT, functions.c)
4789 * So this is intended to be called from extension functions.
4790 */
4791 void
4792 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4793 if ((style == NULL) || (templ == NULL) ||
4794 (templ->type == XML_NAMESPACE_DECL))
4795 return;
4796
4797 /*
4798 * Detection of handled content of extension instructions.
4799 */
4800 if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4801 XSLT_CCTXT(style)->inode->extContentHandled = 1;
4802 }
4803
4804 if (templ->children != NULL) {
4805 xmlNodePtr child = templ->children;
4806 /*
4807 * Process xsl:param elements, which can only occur as the
4808 * immediate children of xsl:template (well, and of any
4809 * user-defined extension instruction if needed).
4810 */
4811 do {
4812 if ((child->type == XML_ELEMENT_NODE) &&
4813 IS_XSLT_ELEM_FAST(child) &&
4814 IS_XSLT_NAME(child, "param"))
4815 {
4816 XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
4817 xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
4818 } else
4819 break;
4820 child = child->next;
4821 } while (child != NULL);
4822 /*
4823 * Parse the content and register the pattern.
4824 */
4825 xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
4826 }
4827 }
4828
4829 #else /* XSLT_REFACTORED */
4830
4831 /**
4832 * xsltParseTemplateContent:
4833 * @style: the XSLT stylesheet
4834 * @templ: the container node (can be a document for literal results)
4835 *
4836 * parse a template content-model
4837 * Clean-up the template content from unwanted ignorable blank nodes
4838 * and process xslt:text
4839 */
4840 void
4841 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4842 xmlNodePtr cur, delete;
4843
4844 if ((style == NULL) || (templ == NULL) ||
4845 (templ->type == XML_NAMESPACE_DECL)) return;
4846
4847 /*
4848 * This content comes from the stylesheet
4849 * For stylesheets, the set of whitespace-preserving
4850 * element names consists of just xsl:text.
4851 */
4852 cur = templ->children;
4853 delete = NULL;
4854 while (cur != NULL) {
4855 if (delete != NULL) {
4856 #ifdef WITH_XSLT_DEBUG_BLANKS
4857 xsltGenericDebug(xsltGenericDebugContext,
4858 "xsltParseTemplateContent: removing text\n");
4859 #endif
4860 xmlUnlinkNode(delete);
4861 xmlFreeNode(delete);
4862 delete = NULL;
4863 }
4864 if (IS_XSLT_ELEM(cur)) {
4865 if (IS_XSLT_NAME(cur, "text")) {
4866 /*
4867 * TODO: Processing of xsl:text should be moved to
4868 * xsltPrecomputeStylesheet(), since otherwise this
4869 * will be performed for every multiply included
4870 * stylesheet; i.e. this here is not skipped with
4871 * the use of the style->nopreproc flag.
4872 */
4873 if (cur->children != NULL) {
4874 xmlChar *prop;
4875 xmlNodePtr text = cur->children, next;
4876 int noesc = 0;
4877
4878 prop = xmlGetNsProp(cur,
4879 (const xmlChar *)"disable-output-escaping",
4880 NULL);
4881 if (prop != NULL) {
4882 #ifdef WITH_XSLT_DEBUG_PARSING
4883 xsltGenericDebug(xsltGenericDebugContext,
4884 "Disable escaping: %s\n", text->content);
4885 #endif
4886 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4887 noesc = 1;
4888 } else if (!xmlStrEqual(prop,
4889 (const xmlChar *)"no")){
4890 xsltTransformError(NULL, style, cur,
4891 "xsl:text: disable-output-escaping allows only yes or no\n");
4892 style->warnings++;
4893
4894 }
4895 xmlFree(prop);
4896 }
4897
4898 while (text != NULL) {
4899 if (text->type == XML_COMMENT_NODE) {
4900 text = text->next;
4901 continue;
4902 }
4903 if ((text->type != XML_TEXT_NODE) &&
4904 (text->type != XML_CDATA_SECTION_NODE)) {
4905 xsltTransformError(NULL, style, cur,
4906 "xsltParseTemplateContent: xslt:text content problem\n");
4907 style->errors++;
4908 break;
4909 }
4910 if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4911 text->name = xmlStringTextNoenc;
4912 text = text->next;
4913 }
4914
4915 /*
4916 * replace xsl:text by the list of childs
4917 */
4918 if (text == NULL) {
4919 text = cur->children;
4920 while (text != NULL) {
4921 if ((style->internalized) &&
4922 (text->content != NULL) &&
4923 (!xmlDictOwns(style->dict, text->content))) {
4924
4925 /*
4926 * internalize the text string
4927 */
4928 if (text->doc->dict != NULL) {
4929 const xmlChar *tmp;
4930
4931 tmp = xmlDictLookup(text->doc->dict,
4932 text->content, -1);
4933 if (tmp != text->content) {
4934 xmlNodeSetContent(text, NULL);
4935 text->content = (xmlChar *) tmp;
4936 }
4937 }
4938 }
4939
4940 next = text->next;
4941 xmlUnlinkNode(text);
4942 xmlAddPrevSibling(cur, text);
4943 text = next;
4944 }
4945 }
4946 }
4947 delete = cur;
4948 goto skip_children;
4949 }
4950 }
4951 else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
4952 (xsltCheckExtPrefix(style, cur->ns->prefix)))
4953 {
4954 /*
4955 * okay this is an extension element compile it too
4956 */
4957 xsltStylePreCompute(style, cur);
4958 }
4959 else if (cur->type == XML_ELEMENT_NODE)
4960 {
4961 /*
4962 * This is an element which will be output as part of the
4963 * template exectution, precompile AVT if found.
4964 */
4965 if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
4966 cur->ns = xmlSearchNsByHref(cur->doc, cur,
4967 style->defaultAlias);
4968 }
4969 if (cur->properties != NULL) {
4970 xmlAttrPtr attr = cur->properties;
4971
4972 while (attr != NULL) {
4973 xsltCompileAttr(style, attr);
4974 attr = attr->next;
4975 }
4976 }
4977 }
4978 /*
4979 * Skip to next node
4980 */
4981 if (cur->children != NULL) {
4982 if (cur->children->type != XML_ENTITY_DECL) {
4983 cur = cur->children;
4984 continue;
4985 }
4986 }
4987 skip_children:
4988 if (cur->next != NULL) {
4989 cur = cur->next;
4990 continue;
4991 }
4992
4993 do {
4994 cur = cur->parent;
4995 if (cur == NULL)
4996 break;
4997 if (cur == templ) {
4998 cur = NULL;
4999 break;
5000 }
5001 if (cur->next != NULL) {
5002 cur = cur->next;
5003 break;
5004 }
5005 } while (cur != NULL);
5006 }
5007 if (delete != NULL) {
5008 #ifdef WITH_XSLT_DEBUG_PARSING
5009 xsltGenericDebug(xsltGenericDebugContext,
5010 "xsltParseTemplateContent: removing text\n");
5011 #endif
5012 xmlUnlinkNode(delete);
5013 xmlFreeNode(delete);
5014 delete = NULL;
5015 }
5016
5017 /*
5018 * Skip the first params
5019 */
5020 cur = templ->children;
5021 while (cur != NULL) {
5022 if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5023 break;
5024 cur = cur->next;
5025 }
5026
5027 /*
5028 * Browse the remainder of the template
5029 */
5030 while (cur != NULL) {
5031 if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5032 xmlNodePtr param = cur;
5033
5034 xsltTransformError(NULL, style, cur,
5035 "xsltParseTemplateContent: ignoring misplaced param element\n");
5036 if (style != NULL) style->warnings++;
5037 cur = cur->next;
5038 xmlUnlinkNode(param);
5039 xmlFreeNode(param);
5040 } else
5041 break;
5042 }
5043 }
5044
5045 #endif /* else XSLT_REFACTORED */
5046
5047 /**
5048 * xsltParseStylesheetKey:
5049 * @style: the XSLT stylesheet
5050 * @key: the "key" element
5051 *
5052 * <!-- Category: top-level-element -->
5053 * <xsl:key name = qname, match = pattern, use = expression />
5054 *
5055 * parse an XSLT stylesheet key definition and register it
5056 */
5057
5058 static void
5059 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
5060 xmlChar *prop = NULL;
5061 xmlChar *use = NULL;
5062 xmlChar *match = NULL;
5063 xmlChar *name = NULL;
5064 xmlChar *nameURI = NULL;
5065
5066 if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
5067 return;
5068
5069 /*
5070 * Get arguments
5071 */
5072 prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5073 if (prop != NULL) {
5074 const xmlChar *URI;
5075
5076 /*
5077 * TODO: Don't use xsltGetQNameURI().
5078 */
5079 URI = xsltGetQNameURI(key, &prop);
5080 if (prop == NULL) {
5081 if (style != NULL) style->errors++;
5082 goto error;
5083 } else {
5084 name = prop;
5085 if (URI != NULL)
5086 nameURI = xmlStrdup(URI);
5087 }
5088 #ifdef WITH_XSLT_DEBUG_PARSING
5089 xsltGenericDebug(xsltGenericDebugContext,
5090 "xsltParseStylesheetKey: name %s\n", name);
5091 #endif
5092 } else {
5093 xsltTransformError(NULL, style, key,
5094 "xsl:key : error missing name\n");
5095 if (style != NULL) style->errors++;
5096 goto error;
5097 }
5098
5099 match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5100 if (match == NULL) {
5101 xsltTransformError(NULL, style, key,
5102 "xsl:key : error missing match\n");
5103 if (style != NULL) style->errors++;
5104 goto error;
5105 }
5106
5107 use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5108 if (use == NULL) {
5109 xsltTransformError(NULL, style, key,
5110 "xsl:key : error missing use\n");
5111 if (style != NULL) style->errors++;
5112 goto error;
5113 }
5114
5115 /*
5116 * register the keys
5117 */
5118 xsltAddKey(style, name, nameURI, match, use, key);
5119
5120
5121 error:
5122 if (use != NULL)
5123 xmlFree(use);
5124 if (match != NULL)
5125 xmlFree(match);
5126 if (name != NULL)
5127 xmlFree(name);
5128 if (nameURI != NULL)
5129 xmlFree(nameURI);
5130
5131 if (key->children != NULL) {
5132 xsltParseContentError(style, key->children);
5133 }
5134 }
5135
5136 #ifdef XSLT_REFACTORED
5137 /**
5138 * xsltParseXSLTTemplate:
5139 * @style: the XSLT stylesheet
5140 * @template: the "template" element
5141 *
5142 * parse an XSLT stylesheet template building the associated structures
5143 * TODO: Is @style ever expected to be NULL?
5144 *
5145 * Called from:
5146 * xsltParseXSLTStylesheet()
5147 * xsltParseStylesheetTop()
5148 */
5149
5150 static void
5151 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
5152 xsltTemplatePtr templ;
5153 xmlChar *prop;
5154 double priority;
5155
5156 if ((cctxt == NULL) || (templNode == NULL) ||
5157 (templNode->type != XML_ELEMENT_NODE))
5158 return;
5159
5160 /*
5161 * Create and link the structure
5162 */
5163 templ = xsltNewTemplate();
5164 if (templ == NULL)
5165 return;
5166
5167 xsltCompilerNodePush(cctxt, templNode);
5168 if (templNode->nsDef != NULL)
5169 cctxt->inode->inScopeNs =
5170 xsltCompilerBuildInScopeNsList(cctxt, templNode);
5171
5172 templ->next = cctxt->style->templates;
5173 cctxt->style->templates = templ;
5174 templ->style = cctxt->style;
5175
5176 /*
5177 * Attribute "mode".
5178 */
5179 prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
5180 if (prop != NULL) {
5181 const xmlChar *modeURI;
5182
5183 /*
5184 * TODO: We need a standardized function for extraction
5185 * of namespace names and local names from QNames.
5186 * Don't use xsltGetQNameURI() as it cannot channe�
5187 * reports through the context.
5188 */
5189 modeURI = xsltGetQNameURI(templNode, &prop);
5190 if (prop == NULL) {
5191 cctxt->style->errors++;
5192 goto error;
5193 }
5194 templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
5195 xmlFree(prop);
5196 prop = NULL;
5197 if (xmlValidateNCName(templ->mode, 0)) {
5198 xsltTransformError(NULL, cctxt->style, templNode,
5199 "xsl:template: Attribute 'mode': The local part '%s' "
5200 "of the value is not a valid NCName.\n", templ->name);
5201 cctxt->style->errors++;
5202 goto error;
5203 }
5204 if (modeURI != NULL)
5205 templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
5206 #ifdef WITH_XSLT_DEBUG_PARSING
5207 xsltGenericDebug(xsltGenericDebugContext,
5208 "xsltParseXSLTTemplate: mode %s\n", templ->mode);
5209 #endif
5210 }
5211 /*
5212 * Attribute "match".
5213 */
5214 prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
5215 if (prop != NULL) {
5216 templ->match = prop;
5217 prop = NULL;
5218 }
5219 /*
5220 * Attribute "priority".
5221 */
5222 prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
5223 if (prop != NULL) {
5224 priority = xmlXPathStringEvalNumber(prop);
5225 templ->priority = (float) priority;
5226 xmlFree(prop);
5227 prop = NULL;
5228 }
5229 /*
5230 * Attribute "name".
5231 */
5232 prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
5233 if (prop != NULL) {
5234 const xmlChar *nameURI;
5235 xsltTemplatePtr curTempl;
5236
5237 /*
5238 * TODO: Don't use xsltGetQNameURI().
5239 */
5240 nameURI = xsltGetQNameURI(templNode, &prop);
5241 if (prop == NULL) {
5242 cctxt->style->errors++;
5243 goto error;
5244 }
5245 templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
5246 xmlFree(prop);
5247 prop = NULL;
5248 if (xmlValidateNCName(templ->name, 0)) {
5249 xsltTransformError(NULL, cctxt->style, templNode,
5250 "xsl:template: Attribute 'name': The local part '%s' of "
5251 "the value is not a valid NCName.\n", templ->name);
5252 cctxt->style->errors++;
5253 goto error;
5254 }
5255 if (nameURI != NULL)
5256 templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
5257 curTempl = templ->next;
5258 while (curTempl != NULL) {
5259 if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
5260 xmlStrEqual(curTempl->nameURI, nameURI) ) ||
5261 (nameURI == NULL && curTempl->nameURI == NULL &&
5262 xmlStrEqual(curTempl->name, templ->name)))
5263 {
5264 xsltTransformError(NULL, cctxt->style, templNode,
5265 "xsl:template: error duplicate name '%s'\n", templ->name);
5266 cctxt->style->errors++;
5267 goto error;
5268 }
5269 curTempl = curTempl->next;
5270 }
5271 }
5272 if (templNode->children != NULL) {
5273 xsltParseTemplateContent(cctxt->style, templNode);
5274 /*
5275 * MAYBE TODO: Custom behaviour: In order to stay compatible with
5276 * Xalan and MSXML(.NET), we could allow whitespace
5277 * to appear before an xml:param element; this whitespace
5278 * will additionally become part of the "template".
5279 * NOTE that this is totally deviates from the spec, but
5280 * is the de facto behaviour of Xalan and MSXML(.NET).
5281 * Personally I wouldn't allow this, since if we have:
5282 * <xsl:template ...xml:space="preserve">
5283 * <xsl:param name="foo"/>
5284 * <xsl:param name="bar"/>
5285 * <xsl:param name="zoo"/>
5286 * ... the whitespace between every xsl:param would be
5287 * added to the result tree.
5288 */
5289 }
5290
5291 templ->elem = templNode;
5292 templ->content = templNode->children;
5293 xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
5294
5295 error:
5296 xsltCompilerNodePop(cctxt, templNode);
5297 return;
5298 }
5299
5300 #else /* XSLT_REFACTORED */
5301
5302 /**
5303 * xsltParseStylesheetTemplate:
5304 * @style: the XSLT stylesheet
5305 * @template: the "template" element
5306 *
5307 * parse an XSLT stylesheet template building the associated structures
5308 */
5309
5310 static void
5311 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
5312 xsltTemplatePtr ret;
5313 xmlChar *prop;
5314 xmlChar *mode = NULL;
5315 xmlChar *modeURI = NULL;
5316 double priority;
5317
5318 if ((style == NULL) || (template == NULL) ||
5319 (template->type != XML_ELEMENT_NODE))
5320 return;
5321
5322 /*
5323 * Create and link the structure
5324 */
5325 ret = xsltNewTemplate();
5326 if (ret == NULL)
5327 return;
5328 ret->next = style->templates;
5329 style->templates = ret;
5330 ret->style = style;
5331
5332 /*
5333 * Get inherited namespaces
5334 */
5335 /*
5336 * TODO: Apply the optimized in-scope-namespace mechanism
5337 * as for the other XSLT instructions.
5338 */
5339 xsltGetInheritedNsList(style, ret, template);
5340
5341 /*
5342 * Get arguments
5343 */
5344 prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
5345 if (prop != NULL) {
5346 const xmlChar *URI;
5347
5348 /*
5349 * TODO: Don't use xsltGetQNameURI().
5350 */
5351 URI = xsltGetQNameURI(template, &prop);
5352 if (prop == NULL) {
5353 if (style != NULL) style->errors++;
5354 goto error;
5355 } else {
5356 mode = prop;
5357 if (URI != NULL)
5358 modeURI = xmlStrdup(URI);
5359 }
5360 ret->mode = xmlDictLookup(style->dict, mode, -1);
5361 ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
5362 #ifdef WITH_XSLT_DEBUG_PARSING
5363 xsltGenericDebug(xsltGenericDebugContext,
5364 "xsltParseStylesheetTemplate: mode %s\n", mode);
5365 #endif
5366 if (mode != NULL) xmlFree(mode);
5367 if (modeURI != NULL) xmlFree(modeURI);
5368 }
5369 prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
5370 if (prop != NULL) {
5371 if (ret->match != NULL) xmlFree(ret->match);
5372 ret->match = prop;
5373 }
5374
5375 prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
5376 if (prop != NULL) {
5377 priority = xmlXPathStringEvalNumber(prop);
5378 ret->priority = (float) priority;
5379 xmlFree(prop);
5380 }
5381
5382 prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
5383 if (prop != NULL) {
5384 const xmlChar *URI;
5385 xsltTemplatePtr cur;
5386
5387 /*
5388 * TODO: Don't use xsltGetQNameURI().
5389 */
5390 URI = xsltGetQNameURI(template, &prop);
5391 if (prop == NULL) {
5392 if (style != NULL) style->errors++;
5393 goto error;
5394 } else {
5395 if (xmlValidateNCName(prop,0)) {
5396 xsltTransformError(NULL, style, template,
5397 "xsl:template : error invalid name '%s'\n", prop);
5398 if (style != NULL) style->errors++;
5399 goto error;
5400 }
5401 ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
5402 xmlFree(prop);
5403 prop = NULL;
5404 if (URI != NULL)
5405 ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
5406 else
5407 ret->nameURI = NULL;
5408 cur = ret->next;
5409 while (cur != NULL) {
5410 if ((URI != NULL && xmlStrEqual(cur->name, ret->name) &&
5411 xmlStrEqual(cur->nameURI, URI) ) ||
5412 (URI == NULL && cur->nameURI == NULL &&
5413 xmlStrEqual(cur->name, ret->name))) {
5414 xsltTransformError(NULL, style, template,
5415 "xsl:template: error duplicate name '%s'\n", ret->name);
5416 style->errors++;
5417 goto error;
5418 }
5419 cur = cur->next;
5420 }
5421 }
5422 }
5423
5424 /*
5425 * parse the content and register the pattern
5426 */
5427 xsltParseTemplateContent(style, template);
5428 ret->elem = template;
5429 ret->content = template->children;
5430 xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
5431
5432 error:
5433 return;
5434 }
5435
5436 #endif /* else XSLT_REFACTORED */
5437
5438 #ifdef XSLT_REFACTORED
5439
5440 /**
5441 * xsltIncludeComp:
5442 * @cctxt: the compilation contenxt
5443 * @node: the xsl:include node
5444 *
5445 * Process the xslt include node on the source node
5446 */
5447 static xsltStyleItemIncludePtr
5448 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
5449 xsltStyleItemIncludePtr item;
5450
5451 if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
5452 return(NULL);
5453
5454 node->psvi = NULL;
5455 item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
5456 if (item == NULL) {
5457 xsltTransformError(NULL, cctxt->style, node,
5458 "xsltIncludeComp : malloc failed\n");
5459 cctxt->style->errors++;
5460 return(NULL);
5461 }
5462 memset(item, 0, sizeof(xsltStyleItemInclude));
5463
5464 node->psvi = item;
5465 item->inst = node;
5466 item->type = XSLT_FUNC_INCLUDE;
5467
5468 item->next = cctxt->style->preComps;
5469 cctxt->style->preComps = (xsltElemPreCompPtr) item;
5470
5471 return(item);
5472 }
5473
5474 /**
5475 * xsltParseFindTopLevelElem:
5476 */
5477 static int
5478 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
5479 xmlNodePtr cur,
5480 const xmlChar *name,
5481 const xmlChar *namespaceURI,
5482 int breakOnOtherElem,
5483 xmlNodePtr *resultNode)
5484 {
5485 if (name == NULL)
5486 return(-1);
5487
5488 *resultNode = NULL;
5489 while (cur != NULL) {
5490 if (cur->type == XML_ELEMENT_NODE) {
5491 if ((cur->ns != NULL) && (cur->name != NULL)) {
5492 if ((*(cur->name) == *name) &&
5493 xmlStrEqual(cur->name, name) &&
5494 xmlStrEqual(cur->ns->href, namespaceURI))
5495 {
5496 *resultNode = cur;
5497 return(1);
5498 }
5499 }
5500 if (breakOnOtherElem)
5501 break;
5502 }
5503 cur = cur->next;
5504 }
5505 *resultNode = cur;
5506 return(0);
5507 }
5508
5509 static int
5510 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
5511 xmlNodePtr node,
5512 xsltStyleType type)
5513 {
5514 int ret = 0;
5515
5516 /*
5517 * TODO: The reason why this function exists:
5518 * due to historical reasons some of the
5519 * top-level declarations are processed by functions
5520 * in other files. Since we need still to set
5521 * up the node-info and generate information like
5522 * in-scope namespaces, this is a wrapper around
5523 * those old parsing functions.
5524 */
5525 xsltCompilerNodePush(cctxt, node);
5526 if (node->nsDef != NULL)
5527 cctxt->inode->inScopeNs =
5528 xsltCompilerBuildInScopeNsList(cctxt, node);
5529 cctxt->inode->type = type;
5530
5531 switch (type) {
5532 case XSLT_FUNC_INCLUDE:
5533 {
5534 int oldIsInclude;
5535
5536 if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
5537 goto exit;
5538 /*
5539 * Mark this stylesheet tree as being currently included.
5540 */
5541 oldIsInclude = cctxt->isInclude;
5542 cctxt->isInclude = 1;
5543
5544 if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
5545 cctxt->style->errors++;
5546 }
5547 cctxt->isInclude = oldIsInclude;
5548 }
5549 break;
5550 case XSLT_FUNC_PARAM:
5551 xsltStylePreCompute(cctxt->style, node);
5552 xsltParseGlobalParam(cctxt->style, node);
5553 break;
5554 case XSLT_FUNC_VARIABLE:
5555 xsltStylePreCompute(cctxt->style, node);
5556 xsltParseGlobalVariable(cctxt->style, node);
5557 break;
5558 case XSLT_FUNC_ATTRSET:
5559 xsltParseStylesheetAttributeSet(cctxt->style, node);
5560 break;
5561 default:
5562 xsltTransformError(NULL, cctxt->style, node,
5563 "Internal error: (xsltParseTopLevelXSLTElem) "
5564 "Cannot handle this top-level declaration.\n");
5565 cctxt->style->errors++;
5566 ret = -1;
5567 }
5568
5569 exit:
5570 xsltCompilerNodePop(cctxt, node);
5571
5572 return(ret);
5573 }
5574
5575 #if 0
5576 static int
5577 xsltParseRemoveWhitespace(xmlNodePtr node)
5578 {
5579 if ((node == NULL) || (node->children == NULL))
5580 return(0);
5581 else {
5582 xmlNodePtr delNode = NULL, child = node->children;
5583
5584 do {
5585 if (delNode) {
5586 xmlUnlinkNode(delNode);
5587 xmlFreeNode(delNode);
5588 delNode = NULL;
5589 }
5590 if (((child->type == XML_TEXT_NODE) ||
5591 (child->type == XML_CDATA_SECTION_NODE)) &&
5592 (IS_BLANK_NODE(child)))
5593 delNode = child;
5594 child = child->next;
5595 } while (child != NULL);
5596 if (delNode) {
5597 xmlUnlinkNode(delNode);
5598 xmlFreeNode(delNode);
5599 delNode = NULL;
5600 }
5601 }
5602 return(0);
5603 }
5604 #endif
5605
5606 static int
5607 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5608 {
5609 #ifdef WITH_XSLT_DEBUG_PARSING
5610 int templates = 0;
5611 #endif
5612 xmlNodePtr cur, start = NULL;
5613 xsltStylesheetPtr style;
5614
5615 if ((cctxt == NULL) || (node == NULL) ||
5616 (node->type != XML_ELEMENT_NODE))
5617 return(-1);
5618
5619 style = cctxt->style;
5620 /*
5621 * At this stage all import declarations of all stylesheet modules
5622 * with the same stylesheet level have been processed.
5623 * Now we can safely parse the rest of the declarations.
5624 */
5625 if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
5626 {
5627 xsltDocumentPtr include;
5628 /*
5629 * URGENT TODO: Make this work with simplified stylesheets!
5630 * I.e., when we won't find an xsl:stylesheet element.
5631 */
5632 /*
5633 * This is as include declaration.
5634 */
5635 include = ((xsltStyleItemIncludePtr) node->psvi)->include;
5636 if (include == NULL) {
5637 /* TODO: raise error? */
5638 return(-1);
5639 }
5640 /*
5641 * TODO: Actually an xsl:include should locate an embedded
5642 * stylesheet as well; so the document-element won't always
5643 * be the element where the actual stylesheet is rooted at.
5644 * But such embedded stylesheets are not supported by Libxslt yet.
5645 */
5646 node = xmlDocGetRootElement(include->doc);
5647 if (node == NULL) {
5648 return(-1);
5649 }
5650 }
5651
5652 if (node->children == NULL)
5653 return(0);
5654 /*
5655 * Push the xsl:stylesheet/xsl:transform element.
5656 */
5657 xsltCompilerNodePush(cctxt, node);
5658 cctxt->inode->isRoot = 1;
5659 cctxt->inode->nsChanged = 0;
5660 /*
5661 * Start with the naked dummy info for literal result elements.
5662 */
5663 cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
5664
5665 /*
5666 * In every case, we need to have
5667 * the in-scope namespaces of the element, where the
5668 * stylesheet is rooted at, regardless if it's an XSLT
5669 * instruction or a literal result instruction (or if
5670 * this is an embedded stylesheet).
5671 */
5672 cctxt->inode->inScopeNs =
5673 xsltCompilerBuildInScopeNsList(cctxt, node);
5674
5675 /*
5676 * Process attributes of xsl:stylesheet/xsl:transform.
5677 * --------------------------------------------------
5678 * Allowed are:
5679 * id = id
5680 * extension-element-prefixes = tokens
5681 * exclude-result-prefixes = tokens
5682 * version = number (mandatory)
5683 */
5684 if (xsltParseAttrXSLTVersion(cctxt, node,
5685 XSLT_ELEMENT_CATEGORY_XSLT) == 0)
5686 {
5687 /*
5688 * Attribute "version".
5689 * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5690 * attribute, indicating the version of XSLT that the
5691 * stylesheet requires".
5692 * The root element of a simplified stylesheet must also have
5693 * this attribute.
5694 */
5695 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5696 if (isXsltElem)
5697 xsltTransformError(NULL, cctxt->style, node,
5698 "The attribute 'version' is missing.\n");
5699 cctxt->style->errors++;
5700 #else
5701 /* OLD behaviour. */
5702 xsltTransformError(NULL, cctxt->style, node,
5703 "xsl:version is missing: document may not be a stylesheet\n");
5704 cctxt->style->warnings++;
5705 #endif
5706 }
5707 /*
5708 * The namespaces declared by the attributes
5709 * "extension-element-prefixes" and
5710 * "exclude-result-prefixes" are local to *this*
5711 * stylesheet tree; i.e., they are *not* visible to
5712 * other stylesheet-modules, whether imported or included.
5713 *
5714 * Attribute "extension-element-prefixes".
5715 */
5716 cctxt->inode->extElemNs =
5717 xsltParseExtElemPrefixes(cctxt, node, NULL,
5718 XSLT_ELEMENT_CATEGORY_XSLT);
5719 /*
5720 * Attribute "exclude-result-prefixes".
5721 */
5722 cctxt->inode->exclResultNs =
5723 xsltParseExclResultPrefixes(cctxt, node, NULL,
5724 XSLT_ELEMENT_CATEGORY_XSLT);
5725 /*
5726 * Create/reuse info for the literal result element.
5727 */
5728 if (cctxt->inode->nsChanged)
5729 xsltLREInfoCreate(cctxt, node, 0);
5730 /*
5731 * Processed top-level elements:
5732 * ----------------------------
5733 * xsl:variable, xsl:param (QName, in-scope ns,
5734 * expression (vars allowed))
5735 * xsl:attribute-set (QName, in-scope ns)
5736 * xsl:strip-space, xsl:preserve-space (XPath NameTests,
5737 * in-scope ns)
5738 * I *think* global scope, merge with includes
5739 * xsl:output (QName, in-scope ns)
5740 * xsl:key (QName, in-scope ns, pattern,
5741 * expression (vars *not* allowed))
5742 * xsl:decimal-format (QName, needs in-scope ns)
5743 * xsl:namespace-alias (in-scope ns)
5744 * global scope, merge with includes
5745 * xsl:template (last, QName, pattern)
5746 *
5747 * (whitespace-only text-nodes have *not* been removed
5748 * yet; this will be done in xsltParseSequenceConstructor)
5749 *
5750 * Report misplaced child-nodes first.
5751 */
5752 cur = node->children;
5753 while (cur != NULL) {
5754 if (cur->type == XML_TEXT_NODE) {
5755 xsltTransformError(NULL, style, cur,
5756 "Misplaced text node (content: '%s').\n",
5757 (cur->content != NULL) ? cur->content : BAD_CAST "");
5758 style->errors++;
5759 } else if (cur->type != XML_ELEMENT_NODE) {
5760 xsltTransformError(NULL, style, cur, "Misplaced node.\n");
5761 style->errors++;
5762 }
5763 cur = cur->next;
5764 }
5765 /*
5766 * Skip xsl:import elements; they have been processed
5767 * already.
5768 */
5769 cur = node->children;
5770 while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
5771 BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
5772 cur = cur->next;
5773 if (cur == NULL)
5774 goto exit;
5775
5776 start = cur;
5777 /*
5778 * Process all top-level xsl:param elements.
5779 */
5780 while ((cur != NULL) &&
5781 xsltParseFindTopLevelElem(cctxt, cur,
5782 BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
5783 {
5784 xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
5785 cur = cur->next;
5786 }
5787 /*
5788 * Process all top-level xsl:variable elements.
5789 */
5790 cur = start;
5791 while ((cur != NULL) &&
5792 xsltParseFindTopLevelElem(cctxt, cur,
5793 BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
5794 {
5795 xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
5796 cur = cur->next;
5797 }
5798 /*
5799 * Process all the rest of top-level elements.
5800 */
5801 cur = start;
5802 while (cur != NULL) {
5803 /*
5804 * Process element nodes.
5805 */
5806 if (cur->type == XML_ELEMENT_NODE) {
5807 if (cur->ns == NULL) {
5808 xsltTransformError(NULL, style, cur,
5809 "Unexpected top-level element in no namespace.\n");
5810 style->errors++;
5811 cur = cur->next;
5812 continue;
5813 }
5814 /*
5815 * Process all XSLT elements.
5816 */
5817 if (IS_XSLT_ELEM_FAST(cur)) {
5818 /*
5819 * xsl:import is only allowed at the beginning.
5820 */
5821 if (IS_XSLT_NAME(cur, "import")) {
5822 xsltTransformError(NULL, style, cur,
5823 "Misplaced xsl:import element.\n");
5824 style->errors++;
5825 cur = cur->next;
5826 continue;
5827 }
5828 /*
5829 * TODO: Change the return type of the parsing functions
5830 * to int.
5831 */
5832 if (IS_XSLT_NAME(cur, "template")) {
5833 #ifdef WITH_XSLT_DEBUG_PARSING
5834 templates++;
5835 #endif
5836 /*
5837 * TODO: Is the position of xsl:template in the
5838 * tree significant? If not it would be easier to
5839 * parse them at a later stage.
5840 */
5841 xsltParseXSLTTemplate(cctxt, cur);
5842 } else if (IS_XSLT_NAME(cur, "variable")) {
5843 /* NOP; done already */
5844 } else if (IS_XSLT_NAME(cur, "param")) {
5845 /* NOP; done already */
5846 } else if (IS_XSLT_NAME(cur, "include")) {
5847 if (cur->psvi != NULL)
5848 xsltParseXSLTStylesheetElemCore(cctxt, cur);
5849 else {
5850 xsltTransformError(NULL, style, cur,
5851 "Internal error: "
5852 "(xsltParseXSLTStylesheetElemCore) "
5853 "The xsl:include element was not compiled.\n");
5854 style->errors++;
5855 }
5856 } else if (IS_XSLT_NAME(cur, "strip-space")) {
5857 /* No node info needed. */
5858 xsltParseStylesheetStripSpace(style, cur);
5859 } else if (IS_XSLT_NAME(cur, "preserve-space")) {
5860 /* No node info needed. */
5861 xsltParseStylesheetPreserveSpace(style, cur);
5862 } else if (IS_XSLT_NAME(cur, "output")) {
5863 /* No node-info needed. */
5864 xsltParseStylesheetOutput(style, cur);
5865 } else if (IS_XSLT_NAME(cur, "key")) {
5866 /* TODO: node-info needed for expressions ? */
5867 xsltParseStylesheetKey(style, cur);
5868 } else if (IS_XSLT_NAME(cur, "decimal-format")) {
5869 /* No node-info needed. */
5870 xsltParseStylesheetDecimalFormat(style, cur);
5871 } else if (IS_XSLT_NAME(cur, "attribute-set")) {
5872 xsltParseTopLevelXSLTElem(cctxt, cur,
5873 XSLT_FUNC_ATTRSET);
5874 } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
5875 /* NOP; done already */
5876 } else {
5877 if (cctxt->inode->forwardsCompat) {
5878 /*
5879 * Forwards-compatible mode:
5880 *
5881 * XSLT-1: "if it is a top-level element and
5882 * XSLT 1.0 does not allow such elements as top-level
5883 * elements, then the element must be ignored along
5884 * with its content;"
5885 */
5886 /*
5887 * TODO: I don't think we should generate a warning.
5888 */
5889 xsltTransformError(NULL, style, cur,
5890 "Forwards-compatible mode: Ignoring unknown XSLT "
5891 "element '%s'.\n", cur->name);
5892 style->warnings++;
5893 } else {
5894 xsltTransformError(NULL, style, cur,
5895 "Unknown XSLT element '%s'.\n", cur->name);
5896 style->errors++;
5897 }
5898 }
5899 } else {
5900 xsltTopLevelFunction function;
5901
5902 /*
5903 * Process non-XSLT elements, which are in a
5904 * non-NULL namespace.
5905 */
5906 /*
5907 * QUESTION: What does xsltExtModuleTopLevelLookup()
5908 * do exactly?
5909 */
5910 function = xsltExtModuleTopLevelLookup(cur->name,
5911 cur->ns->href);
5912 if (function != NULL)
5913 function(style, cur);
5914 #ifdef WITH_XSLT_DEBUG_PARSING
5915 xsltGenericDebug(xsltGenericDebugContext,
5916 "xsltParseXSLTStylesheetElemCore : User-defined "
5917 "data element '%s'.\n", cur->name);
5918 #endif
5919 }
5920 }
5921 cur = cur->next;
5922 }
5923
5924 exit:
5925
5926 #ifdef WITH_XSLT_DEBUG_PARSING
5927 xsltGenericDebug(xsltGenericDebugContext,
5928 "### END of parsing top-level elements of doc '%s'.\n",
5929 node->doc->URL);
5930 xsltGenericDebug(xsltGenericDebugContext,
5931 "### Templates: %d\n", templates);
5932 #ifdef XSLT_REFACTORED
5933 xsltGenericDebug(xsltGenericDebugContext,
5934 "### Max inodes: %d\n", cctxt->maxNodeInfos);
5935 xsltGenericDebug(xsltGenericDebugContext,
5936 "### Max LREs : %d\n", cctxt->maxLREs);
5937 #endif /* XSLT_REFACTORED */
5938 #endif /* WITH_XSLT_DEBUG_PARSING */
5939
5940 xsltCompilerNodePop(cctxt, node);
5941 return(0);
5942 }
5943
5944 /**
5945 * xsltParseXSLTStylesheet:
5946 * @cctxt: the compiler context
5947 * @node: the xsl:stylesheet/xsl:transform element-node
5948 *
5949 * Parses the xsl:stylesheet and xsl:transform element.
5950 *
5951 * <xsl:stylesheet
5952 * id = id
5953 * extension-element-prefixes = tokens
5954 * exclude-result-prefixes = tokens
5955 * version = number>
5956 * <!-- Content: (xsl:import*, top-level-elements) -->
5957 * </xsl:stylesheet>
5958 *
5959 * BIG TODO: The xsl:include stuff.
5960 *
5961 * Called by xsltParseStylesheetTree()
5962 *
5963 * Returns 0 on success, a positive result on errors and
5964 * -1 on API or internal errors.
5965 */
5966 static int
5967 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5968 {
5969 xmlNodePtr cur, start;
5970
5971 if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
5972 return(-1);
5973
5974 if (node->children == NULL)
5975 goto exit;
5976
5977 /*
5978 * Process top-level elements:
5979 * xsl:import (must be first)
5980 * xsl:include (this is just a pre-processing)
5981 */
5982 cur = node->children;
5983 /*
5984 * Process xsl:import elements.
5985 * XSLT 1.0: "The xsl:import element children must precede all
5986 * other element children of an xsl:stylesheet element,
5987 * including any xsl:include element children."
5988 */
5989 while ((cur != NULL) &&
5990 xsltParseFindTopLevelElem(cctxt, cur,
5991 BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
5992 {
5993 if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
5994 cctxt->style->errors++;
5995 }
5996 cur = cur->next;
5997 }
5998 if (cur == NULL)
5999 goto exit;
6000 start = cur;
6001 /*
6002 * Pre-process all xsl:include elements.
6003 */
6004 cur = start;
6005 while ((cur != NULL) &&
6006 xsltParseFindTopLevelElem(cctxt, cur,
6007 BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
6008 {
6009 xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
6010 cur = cur->next;
6011 }
6012 /*
6013 * Pre-process all xsl:namespace-alias elements.
6014 * URGENT TODO: This won't work correctly: the order of included
6015 * aliases and aliases defined here is significant.
6016 */
6017 cur = start;
6018 while ((cur != NULL) &&
6019 xsltParseFindTopLevelElem(cctxt, cur,
6020 BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
6021 {
6022 xsltNamespaceAlias(cctxt->style, cur);
6023 cur = cur->next;
6024 }
6025
6026 if (cctxt->isInclude) {
6027 /*
6028 * If this stylesheet is intended for inclusion, then
6029 * we will process only imports and includes.
6030 */
6031 goto exit;
6032 }
6033 /*
6034 * Now parse the rest of the top-level elements.
6035 */
6036 xsltParseXSLTStylesheetElemCore(cctxt, node);
6037 exit:
6038
6039 return(0);
6040 }
6041
6042 #else /* XSLT_REFACTORED */
6043
6044 /**
6045 * xsltParseStylesheetTop:
6046 * @style: the XSLT stylesheet
6047 * @top: the top level "stylesheet" or "transform" element
6048 *
6049 * scan the top level elements of an XSL stylesheet
6050 */
6051 static void
6052 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
6053 xmlNodePtr cur;
6054 xmlChar *prop;
6055 #ifdef WITH_XSLT_DEBUG_PARSING
6056 int templates = 0;
6057 #endif
6058
6059 if ((top == NULL) || (top->type != XML_ELEMENT_NODE))
6060 return;
6061
6062 prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
6063 if (prop == NULL) {
6064 xsltTransformError(NULL, style, top,
6065 "xsl:version is missing: document may not be a stylesheet\n");
6066 if (style != NULL) style->warnings++;
6067 } else {
6068 if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6069 (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6070 xsltTransformError(NULL, style, top,
6071 "xsl:version: only 1.0 features are supported\n");
6072 if (style != NULL) {
6073 style->forwards_compatible = 1;
6074 style->warnings++;
6075 }
6076 }
6077 xmlFree(prop);
6078 }
6079
6080 /*
6081 * process xsl:import elements
6082 */
6083 cur = top->children;
6084 while (cur != NULL) {
6085 if (IS_BLANK_NODE(cur)) {
6086 cur = cur->next;
6087 continue;
6088 }
6089 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
6090 if (xsltParseStylesheetImport(style, cur) != 0)
6091 if (style != NULL) style->errors++;
6092 } else
6093 break;
6094 cur = cur->next;
6095 }
6096
6097 /*
6098 * process other top-level elements
6099 */
6100 while (cur != NULL) {
6101 if (IS_BLANK_NODE(cur)) {
6102 cur = cur->next;
6103 continue;
6104 }
6105 if (cur->type == XML_TEXT_NODE) {
6106 if (cur->content != NULL) {
6107 xsltTransformError(NULL, style, cur,
6108 "misplaced text node: '%s'\n", cur->content);
6109 }
6110 if (style != NULL) style->errors++;
6111 cur = cur->next;
6112 continue;
6113 }
6114 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
6115 xsltGenericError(xsltGenericErrorContext,
6116 "Found a top-level element %s with null namespace URI\n",
6117 cur->name);
6118 if (style != NULL) style->errors++;
6119 cur = cur->next;
6120 continue;
6121 }
6122 if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
6123 xsltTopLevelFunction function;
6124
6125 function = xsltExtModuleTopLevelLookup(cur->name,
6126 cur->ns->href);
6127 if (function != NULL)
6128 function(style, cur);
6129
6130 #ifdef WITH_XSLT_DEBUG_PARSING
6131 xsltGenericDebug(xsltGenericDebugContext,
6132 "xsltParseStylesheetTop : found foreign element %s\n",
6133 cur->name);
6134 #endif
6135 cur = cur->next;
6136 continue;
6137 }
6138 if (IS_XSLT_NAME(cur, "import")) {
6139 xsltTransformError(NULL, style, cur,
6140 "xsltParseStylesheetTop: ignoring misplaced import element\n");
6141 if (style != NULL) style->errors++;
6142 } else if (IS_XSLT_NAME(cur, "include")) {
6143 if (xsltParseStylesheetInclude(style, cur) != 0)
6144 if (style != NULL) style->errors++;
6145 } else if (IS_XSLT_NAME(cur, "strip-space")) {
6146 xsltParseStylesheetStripSpace(style, cur);
6147 } else if (IS_XSLT_NAME(cur, "preserve-space")) {
6148 xsltParseStylesheetPreserveSpace(style, cur);
6149 } else if (IS_XSLT_NAME(cur, "output")) {
6150 xsltParseStylesheetOutput(style, cur);
6151 } else if (IS_XSLT_NAME(cur, "key")) {
6152 xsltParseStylesheetKey(style, cur);
6153 } else if (IS_XSLT_NAME(cur, "decimal-format")) {
6154 xsltParseStylesheetDecimalFormat(style, cur);
6155 } else if (IS_XSLT_NAME(cur, "attribute-set")) {
6156 xsltParseStylesheetAttributeSet(style, cur);
6157 } else if (IS_XSLT_NAME(cur, "variable")) {
6158 xsltParseGlobalVariable(style, cur);
6159 } else if (IS_XSLT_NAME(cur, "param")) {
6160 xsltParseGlobalParam(style, cur);
6161 } else if (IS_XSLT_NAME(cur, "template")) {
6162 #ifdef WITH_XSLT_DEBUG_PARSING
6163 templates++;
6164 #endif
6165 xsltParseStylesheetTemplate(style, cur);
6166 } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
6167 xsltNamespaceAlias(style, cur);
6168 } else {
6169 if ((style != NULL) && (style->forwards_compatible == 0)) {
6170 xsltTransformError(NULL, style, cur,
6171 "xsltParseStylesheetTop: unknown %s element\n",
6172 cur->name);
6173 if (style != NULL) style->errors++;
6174 }
6175 else {
6176 /* do Forwards-Compatible Processing */
6177 xsltTransformError(NULL, style, cur,
6178 "xsltParseStylesheetTop: ignoring unknown %s element\n",
6179 cur->name);
6180 if (style != NULL) style->warnings++;
6181 }
6182 }
6183 cur = cur->next;
6184 }
6185 #ifdef WITH_XSLT_DEBUG_PARSING
6186 xsltGenericDebug(xsltGenericDebugContext,
6187 "parsed %d templates\n", templates);
6188 #endif
6189 }
6190
6191 #endif /* else of XSLT_REFACTORED */
6192
6193 #ifdef XSLT_REFACTORED
6194 /**
6195 * xsltParseSimplifiedStylesheetTree:
6196 *
6197 * @style: the stylesheet (TODO: Change this to the compiler context)
6198 * @doc: the document containing the stylesheet.
6199 * @node: the node where the stylesheet is rooted at
6200 *
6201 * Returns 0 in case of success, a positive result if an error occurred
6202 * and -1 on API and internal errors.
6203 */
6204 static int
6205 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
6206 xmlDocPtr doc,
6207 xmlNodePtr node)
6208 {
6209 xsltTemplatePtr templ;
6210
6211 if ((cctxt == NULL) || (node == NULL))
6212 return(-1);
6213
6214 if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
6215 {
6216 /*
6217 * TODO: Adjust report, since this might be an
6218 * embedded stylesheet.
6219 */
6220 xsltTransformError(NULL, cctxt->style, node,
6221 "The attribute 'xsl:version' is missing; cannot identify "
6222 "this document as an XSLT stylesheet document.\n");
6223 cctxt->style->errors++;
6224 return(1);
6225 }
6226
6227 #ifdef WITH_XSLT_DEBUG_PARSING
6228 xsltGenericDebug(xsltGenericDebugContext,
6229 "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6230 #endif
6231
6232 /*
6233 * Create and link the template
6234 */
6235 templ = xsltNewTemplate();
6236 if (templ == NULL) {
6237 return(-1);
6238 }
6239 templ->next = cctxt->style->templates;
6240 cctxt->style->templates = templ;
6241 templ->match = xmlStrdup(BAD_CAST "/");
6242
6243 /*
6244 * Note that we push the document-node in this special case.
6245 */
6246 xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6247 /*
6248 * In every case, we need to have
6249 * the in-scope namespaces of the element, where the
6250 * stylesheet is rooted at, regardless if it's an XSLT
6251 * instruction or a literal result instruction (or if
6252 * this is an embedded stylesheet).
6253 */
6254 cctxt->inode->inScopeNs =
6255 xsltCompilerBuildInScopeNsList(cctxt, node);
6256 /*
6257 * Parse the content and register the match-pattern.
6258 */
6259 xsltParseSequenceConstructor(cctxt, node);
6260 xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6261
6262 templ->elem = (xmlNodePtr) doc;
6263 templ->content = node;
6264 xsltAddTemplate(cctxt->style, templ, NULL, NULL);
6265 cctxt->style->literal_result = 1;
6266 return(0);
6267 }
6268
6269 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6270 /**
6271 * xsltRestoreDocumentNamespaces:
6272 * @ns: map of namespaces
6273 * @doc: the document
6274 *
6275 * Restore the namespaces for the document
6276 *
6277 * Returns 0 in case of success, -1 in case of failure
6278 */
6279 int
6280 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
6281 {
6282 if (doc == NULL)
6283 return(-1);
6284 /*
6285 * Revert the changes we have applied to the namespace-URIs of
6286 * ns-decls.
6287 */
6288 while (ns != NULL) {
6289 if ((ns->doc == doc) && (ns->ns != NULL)) {
6290 ns->ns->href = ns->origNsName;
6291 ns->origNsName = NULL;
6292 ns->ns = NULL;
6293 }
6294 ns = ns->next;
6295 }
6296 return(0);
6297 }
6298 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6299
6300 /**
6301 * xsltParseStylesheetProcess:
6302 * @style: the XSLT stylesheet (the current stylesheet-level)
6303 * @doc: and xmlDoc parsed XML
6304 *
6305 * Parses an XSLT stylesheet, adding the associated structures.
6306 * Called by:
6307 * xsltParseStylesheetImportedDoc() (xslt.c)
6308 * xsltParseStylesheetInclude() (imports.c)
6309 *
6310 * Returns the value of the @style parameter if everything
6311 * went right, NULL if something went amiss.
6312 */
6313 xsltStylesheetPtr
6314 xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
6315 {
6316 xsltCompilerCtxtPtr cctxt;
6317 xmlNodePtr cur;
6318 int oldIsSimplifiedStylesheet;
6319
6320 xsltInitGlobals();
6321
6322 if ((style == NULL) || (doc == NULL))
6323 return(NULL);
6324
6325 cctxt = XSLT_CCTXT(style);
6326
6327 cur = xmlDocGetRootElement(doc);
6328 if (cur == NULL) {
6329 xsltTransformError(NULL, style, (xmlNodePtr) doc,
6330 "xsltParseStylesheetProcess : empty stylesheet\n");
6331 return(NULL);
6332 }
6333 oldIsSimplifiedStylesheet = cctxt->simplified;
6334
6335 if ((IS_XSLT_ELEM(cur)) &&
6336 ((IS_XSLT_NAME(cur, "stylesheet")) ||
6337 (IS_XSLT_NAME(cur, "transform")))) {
6338 #ifdef WITH_XSLT_DEBUG_PARSING
6339 xsltGenericDebug(xsltGenericDebugContext,
6340 "xsltParseStylesheetProcess : found stylesheet\n");
6341 #endif
6342 cctxt->simplified = 0;
6343 style->literal_result = 0;
6344 } else {
6345 cctxt->simplified = 1;
6346 style->literal_result = 1;
6347 }
6348 /*
6349 * Pre-process the stylesheet if not already done before.
6350 * This will remove PIs and comments, merge adjacent
6351 * text nodes, internalize strings, etc.
6352 */
6353 if (! style->nopreproc)
6354 xsltParsePreprocessStylesheetTree(cctxt, cur);
6355 /*
6356 * Parse and compile the stylesheet.
6357 */
6358 if (style->literal_result == 0) {
6359 if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
6360 return(NULL);
6361 } else {
6362 if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
6363 return(NULL);
6364 }
6365
6366 cctxt->simplified = oldIsSimplifiedStylesheet;
6367
6368 return(style);
6369 }
6370
6371 #else /* XSLT_REFACTORED */
6372
6373 /**
6374 * xsltParseStylesheetProcess:
6375 * @ret: the XSLT stylesheet (the current stylesheet-level)
6376 * @doc: and xmlDoc parsed XML
6377 *
6378 * Parses an XSLT stylesheet, adding the associated structures.
6379 * Called by:
6380 * xsltParseStylesheetImportedDoc() (xslt.c)
6381 * xsltParseStylesheetInclude() (imports.c)
6382 *
6383 * Returns the value of the @style parameter if everything
6384 * went right, NULL if something went amiss.
6385 */
6386 xsltStylesheetPtr
6387 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
6388 xmlNodePtr cur;
6389
6390 xsltInitGlobals();
6391
6392 if (doc == NULL)
6393 return(NULL);
6394 if (ret == NULL)
6395 return(ret);
6396
6397 /*
6398 * First steps, remove blank nodes,
6399 * locate the xsl:stylesheet element and the
6400 * namespace declaration.
6401 */
6402 cur = xmlDocGetRootElement(doc);
6403 if (cur == NULL) {
6404 xsltTransformError(NULL, ret, (xmlNodePtr) doc,
6405 "xsltParseStylesheetProcess : empty stylesheet\n");
6406 return(NULL);
6407 }
6408
6409 if ((IS_XSLT_ELEM(cur)) &&
6410 ((IS_XSLT_NAME(cur, "stylesheet")) ||
6411 (IS_XSLT_NAME(cur, "transform")))) {
6412 #ifdef WITH_XSLT_DEBUG_PARSING
6413 xsltGenericDebug(xsltGenericDebugContext,
6414 "xsltParseStylesheetProcess : found stylesheet\n");
6415 #endif
6416 ret->literal_result = 0;
6417 xsltParseStylesheetExcludePrefix(ret, cur, 1);
6418 xsltParseStylesheetExtPrefix(ret, cur, 1);
6419 } else {
6420 xsltParseStylesheetExcludePrefix(ret, cur, 0);
6421 xsltParseStylesheetExtPrefix(ret, cur, 0);
6422 ret->literal_result = 1;
6423 }
6424 if (!ret->nopreproc) {
6425 xsltPrecomputeStylesheet(ret, cur);
6426 }
6427 if (ret->literal_result == 0) {
6428 xsltParseStylesheetTop(ret, cur);
6429 } else {
6430 xmlChar *prop;
6431 xsltTemplatePtr template;
6432
6433 /*
6434 * the document itself might be the template, check xsl:version
6435 */
6436 prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
6437 if (prop == NULL) {
6438 xsltTransformError(NULL, ret, cur,
6439 "xsltParseStylesheetProcess : document is not a stylesheet\n");
6440 return(NULL);
6441 }
6442
6443 #ifdef WITH_XSLT_DEBUG_PARSING
6444 xsltGenericDebug(xsltGenericDebugContext,
6445 "xsltParseStylesheetProcess : document is stylesheet\n");
6446 #endif
6447
6448 if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
6449 xsltTransformError(NULL, ret, cur,
6450 "xsl:version: only 1.0 features are supported\n");
6451 /* TODO set up compatibility when not XSLT 1.0 */
6452 ret->warnings++;
6453 }
6454 xmlFree(prop);
6455
6456 /*
6457 * Create and link the template
6458 */
6459 template = xsltNewTemplate();
6460 if (template == NULL) {
6461 return(NULL);
6462 }
6463 template->next = ret->templates;
6464 ret->templates = template;
6465 template->match = xmlStrdup((const xmlChar *)"/");
6466
6467 /*
6468 * parse the content and register the pattern
6469 */
6470 xsltParseTemplateContent(ret, (xmlNodePtr) doc);
6471 template->elem = (xmlNodePtr) doc;
6472 template->content = doc->children;
6473 xsltAddTemplate(ret, template, NULL, NULL);
6474 ret->literal_result = 1;
6475 }
6476
6477 return(ret);
6478 }
6479
6480 #endif /* else of XSLT_REFACTORED */
6481
6482 /**
6483 * xsltParseStylesheetImportedDoc:
6484 * @doc: an xmlDoc parsed XML
6485 * @parentStyle: pointer to the parent stylesheet (if it exists)
6486 *
6487 * parse an XSLT stylesheet building the associated structures
6488 * except the processing not needed for imported documents.
6489 *
6490 * Returns a new XSLT stylesheet structure.
6491 */
6492
6493 xsltStylesheetPtr
6494 xsltParseStylesheetImportedDoc(xmlDocPtr doc,
6495 xsltStylesheetPtr parentStyle) {
6496 xsltStylesheetPtr retStyle;
6497
6498 if (doc == NULL)
6499 return(NULL);
6500
6501 retStyle = xsltNewStylesheet();
6502 if (retStyle == NULL)
6503 return(NULL);
6504 /*
6505 * Set the importing stylesheet module; also used to detect recursion.
6506 */
6507 retStyle->parent = parentStyle;
6508 /*
6509 * Adjust the string dict.
6510 */
6511 if (doc->dict != NULL) {
6512 xmlDictFree(retStyle->dict);
6513 retStyle->dict = doc->dict;
6514 #ifdef WITH_XSLT_DEBUG
6515 xsltGenericDebug(xsltGenericDebugContext,
6516 "reusing dictionary from %s for stylesheet\n",
6517 doc->URL);
6518 #endif
6519 xmlDictReference(retStyle->dict);
6520 }
6521
6522 /*
6523 * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6524 * the stylesheet to containt distinct namespace prefixes.
6525 */
6526 xsltGatherNamespaces(retStyle);
6527
6528 #ifdef XSLT_REFACTORED
6529 {
6530 xsltCompilerCtxtPtr cctxt;
6531 xsltStylesheetPtr oldCurSheet;
6532
6533 if (parentStyle == NULL) {
6534 xsltPrincipalStylesheetDataPtr principalData;
6535 /*
6536 * Principal stylesheet
6537 * --------------------
6538 */
6539 retStyle->principal = retStyle;
6540 /*
6541 * Create extra data for the principal stylesheet.
6542 */
6543 principalData = xsltNewPrincipalStylesheetData();
6544 if (principalData == NULL) {
6545 xsltFreeStylesheet(retStyle);
6546 return(NULL);
6547 }
6548 retStyle->principalData = principalData;
6549 /*
6550 * Create the compilation context
6551 * ------------------------------
6552 * (only once; for the principal stylesheet).
6553 * This is currently the only function where the
6554 * compilation context is created.
6555 */
6556 cctxt = xsltCompilationCtxtCreate(retStyle);
6557 if (cctxt == NULL) {
6558 xsltFreeStylesheet(retStyle);
6559 return(NULL);
6560 }
6561 retStyle->compCtxt = (void *) cctxt;
6562 cctxt->style = retStyle;
6563 cctxt->dict = retStyle->dict;
6564 cctxt->psData = principalData;
6565 /*
6566 * Push initial dummy node info.
6567 */
6568 cctxt->depth = -1;
6569 xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6570 } else {
6571 /*
6572 * Imported stylesheet.
6573 */
6574 retStyle->principal = parentStyle->principal;
6575 cctxt = parentStyle->compCtxt;
6576 retStyle->compCtxt = cctxt;
6577 }
6578 /*
6579 * Save the old and set the current stylesheet structure in the
6580 * compilation context.
6581 */
6582 oldCurSheet = cctxt->style;
6583 cctxt->style = retStyle;
6584
6585 retStyle->doc = doc;
6586 xsltParseStylesheetProcess(retStyle, doc);
6587
6588 cctxt->style = oldCurSheet;
6589 if (parentStyle == NULL) {
6590 /*
6591 * Pop the initial dummy node info.
6592 */
6593 xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6594 } else {
6595 /*
6596 * Clear the compilation context of imported
6597 * stylesheets.
6598 * TODO: really?
6599 */
6600 /* retStyle->compCtxt = NULL; */
6601 }
6602 /*
6603 * Free the stylesheet if there were errors.
6604 */
6605 if (retStyle != NULL) {
6606 if (retStyle->errors != 0) {
6607 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6608 /*
6609 * Restore all changes made to namespace URIs of ns-decls.
6610 */
6611 if (cctxt->psData->nsMap)
6612 xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
6613 #endif
6614 /*
6615 * Detach the doc from the stylesheet; otherwise the doc
6616 * will be freed in xsltFreeStylesheet().
6617 */
6618 retStyle->doc = NULL;
6619 /*
6620 * Cleanup the doc if its the main stylesheet.
6621 */
6622 if (parentStyle == NULL) {
6623 xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
6624 if (retStyle->compCtxt != NULL) {
6625 xsltCompilationCtxtFree(retStyle->compCtxt);
6626 retStyle->compCtxt = NULL;
6627 }
6628 }
6629
6630 xsltFreeStylesheet(retStyle);
6631 retStyle = NULL;
6632 }
6633 }
6634 }
6635
6636 #else /* XSLT_REFACTORED */
6637 /*
6638 * Old behaviour.
6639 */
6640 retStyle->doc = doc;
6641 if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
6642 retStyle->doc = NULL;
6643 xsltFreeStylesheet(retStyle);
6644 retStyle = NULL;
6645 }
6646 if (retStyle != NULL) {
6647 if (retStyle->errors != 0) {
6648 retStyle->doc = NULL;
6649 if (parentStyle == NULL)
6650 xsltCleanupStylesheetTree(doc,
6651 xmlDocGetRootElement(doc));
6652 xsltFreeStylesheet(retStyle);
6653 retStyle = NULL;
6654 }
6655 }
6656 #endif /* else of XSLT_REFACTORED */
6657
6658 return(retStyle);
6659 }
6660
6661 /**
6662 * xsltParseStylesheetDoc:
6663 * @doc: and xmlDoc parsed XML
6664 *
6665 * parse an XSLT stylesheet, building the associated structures. doc
6666 * is kept as a reference within the returned stylesheet, so changes
6667 * to doc after the parsing will be reflected when the stylesheet
6668 * is applied, and the doc is automatically freed when the
6669 * stylesheet is closed.
6670 *
6671 * Returns a new XSLT stylesheet structure.
6672 */
6673
6674 xsltStylesheetPtr
6675 xsltParseStylesheetDoc(xmlDocPtr doc) {
6676 xsltStylesheetPtr ret;
6677
6678 xsltInitGlobals();
6679
6680 ret = xsltParseStylesheetImportedDoc(doc, NULL);
6681 if (ret == NULL)
6682 return(NULL);
6683
6684 xsltResolveStylesheetAttributeSet(ret);
6685 #ifdef XSLT_REFACTORED
6686 /*
6687 * Free the compilation context.
6688 * TODO: Check if it's better to move this cleanup to
6689 * xsltParseStylesheetImportedDoc().
6690 */
6691 if (ret->compCtxt != NULL) {
6692 xsltCompilationCtxtFree(XSLT_CCTXT(ret));
6693 ret->compCtxt = NULL;
6694 }
6695 #endif
6696 return(ret);
6697 }
6698
6699 /**
6700 * xsltParseStylesheetFile:
6701 * @filename: the filename/URL to the stylesheet
6702 *
6703 * Load and parse an XSLT stylesheet
6704 *
6705 * Returns a new XSLT stylesheet structure.
6706 */
6707
6708 xsltStylesheetPtr
6709 xsltParseStylesheetFile(const xmlChar* filename) {
6710 xsltSecurityPrefsPtr sec;
6711 xsltStylesheetPtr ret;
6712 xmlDocPtr doc;
6713
6714 xsltInitGlobals();
6715
6716 if (filename == NULL)
6717 return(NULL);
6718
6719 #ifdef WITH_XSLT_DEBUG_PARSING
6720 xsltGenericDebug(xsltGenericDebugContext,
6721 "xsltParseStylesheetFile : parse %s\n", filename);
6722 #endif
6723
6724 /*
6725 * Security framework check
6726 */
6727 sec = xsltGetDefaultSecurityPrefs();
6728 if (sec != NULL) {
6729 int res;
6730
6731 res = xsltCheckRead(sec, NULL, filename);
6732 if (res == 0) {
6733 xsltTransformError(NULL, NULL, NULL,
6734 "xsltParseStylesheetFile: read rights for %s denied\n",
6735 filename);
6736 return(NULL);
6737 }
6738 }
6739
6740 doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
6741 NULL, XSLT_LOAD_START);
6742 if (doc == NULL) {
6743 xsltTransformError(NULL, NULL, NULL,
6744 "xsltParseStylesheetFile : cannot parse %s\n", filename);
6745 return(NULL);
6746 }
6747 ret = xsltParseStylesheetDoc(doc);
6748 if (ret == NULL) {
6749 xmlFreeDoc(doc);
6750 return(NULL);
6751 }
6752
6753 return(ret);
6754 }
6755
6756 /************************************************************************
6757 * *
6758 * Handling of Stylesheet PI *
6759 * *
6760 ************************************************************************/
6761
6762 #define CUR (*cur)
6763 #define SKIP(val) cur += (val)
6764 #define NXT(val) cur[(val)]
6765 #define SKIP_BLANKS \
6766 while (IS_BLANK(CUR)) NEXT
6767 #define NEXT ((*cur) ? cur++ : cur)
6768
6769 /**
6770 * xsltParseStylesheetPI:
6771 * @value: the value of the PI
6772 *
6773 * This function checks that the type is text/xml and extracts
6774 * the URI-Reference for the stylesheet
6775 *
6776 * Returns the URI-Reference for the stylesheet or NULL (it need to
6777 * be freed by the caller)
6778 */
6779 static xmlChar *
6780 xsltParseStylesheetPI(const xmlChar *value) {
6781 const xmlChar *cur;
6782 const xmlChar *start;
6783 xmlChar *val;
6784 xmlChar tmp;
6785 xmlChar *href = NULL;
6786 int isXml = 0;
6787
6788 if (value == NULL)
6789 return(NULL);
6790
6791 cur = value;
6792 while (CUR != 0) {
6793 SKIP_BLANKS;
6794 if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6795 (NXT(3) == 'e')) {
6796 SKIP(4);
6797 SKIP_BLANKS;
6798 if (CUR != '=')
6799 continue;
6800 NEXT;
6801 if ((CUR != '\'') && (CUR != '"'))
6802 continue;
6803 tmp = CUR;
6804 NEXT;
6805 start = cur;
6806 while ((CUR != 0) && (CUR != tmp))
6807 NEXT;
6808 if (CUR != tmp)
6809 continue;
6810 val = xmlStrndup(start, cur - start);
6811 NEXT;
6812 if (val == NULL)
6813 return(NULL);
6814 if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
6815 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
6816 xmlFree(val);
6817 break;
6818 }
6819 isXml = 1;
6820 xmlFree(val);
6821 } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6822 (NXT(3) == 'f')) {
6823 SKIP(4);
6824 SKIP_BLANKS;
6825 if (CUR != '=')
6826 continue;
6827 NEXT;
6828 if ((CUR != '\'') && (CUR != '"'))
6829 continue;
6830 tmp = CUR;
6831 NEXT;
6832 start = cur;
6833 while ((CUR != 0) && (CUR != tmp))
6834 NEXT;
6835 if (CUR != tmp)
6836 continue;
6837 if (href == NULL)
6838 href = xmlStrndup(start, cur - start);
6839 NEXT;
6840 } else {
6841 while ((CUR != 0) && (!IS_BLANK(CUR)))
6842 NEXT;
6843 }
6844
6845 }
6846
6847 if (!isXml) {
6848 if (href != NULL)
6849 xmlFree(href);
6850 href = NULL;
6851 }
6852 return(href);
6853 }
6854
6855 /**
6856 * xsltLoadStylesheetPI:
6857 * @doc: a document to process
6858 *
6859 * This function tries to locate the stylesheet PI in the given document
6860 * If found, and if contained within the document, it will extract
6861 * that subtree to build the stylesheet to process @doc (doc itself will
6862 * be modified). If found but referencing an external document it will
6863 * attempt to load it and generate a stylesheet from it. In both cases,
6864 * the resulting stylesheet and the document need to be freed once the
6865 * transformation is done.
6866 *
6867 * Returns a new XSLT stylesheet structure or NULL if not found.
6868 */
6869 xsltStylesheetPtr
6870 xsltLoadStylesheetPI(xmlDocPtr doc) {
6871 xmlNodePtr child;
6872 xsltStylesheetPtr ret = NULL;
6873 xmlChar *href = NULL;
6874 xmlURIPtr URI;
6875
6876 xsltInitGlobals();
6877
6878 if (doc == NULL)
6879 return(NULL);
6880
6881 /*
6882 * Find the text/xml stylesheet PI id any before the root
6883 */
6884 child = doc->children;
6885 while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
6886 if ((child->type == XML_PI_NODE) &&
6887 (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
6888 href = xsltParseStylesheetPI(child->content);
6889 if (href != NULL)
6890 break;
6891 }
6892 child = child->next;
6893 }
6894
6895 /*
6896 * If found check the href to select processing
6897 */
6898 if (href != NULL) {
6899 #ifdef WITH_XSLT_DEBUG_PARSING
6900 xsltGenericDebug(xsltGenericDebugContext,
6901 "xsltLoadStylesheetPI : found PI href=%s\n", href);
6902 #endif
6903 URI = xmlParseURI((const char *) href);
6904 if (URI == NULL) {
6905 xsltTransformError(NULL, NULL, child,
6906 "xml-stylesheet : href %s is not valid\n", href);
6907 xmlFree(href);
6908 return(NULL);
6909 }
6910 if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
6911 (URI->opaque == NULL) && (URI->authority == NULL) &&
6912 (URI->server == NULL) && (URI->user == NULL) &&
6913 (URI->path == NULL) && (URI->query == NULL)) {
6914 xmlAttrPtr ID;
6915
6916 #ifdef WITH_XSLT_DEBUG_PARSING
6917 xsltGenericDebug(xsltGenericDebugContext,
6918 "xsltLoadStylesheetPI : Reference to ID %s\n", href);
6919 #endif
6920 if (URI->fragment[0] == '#')
6921 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
6922 else
6923 ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
6924 if (ID == NULL) {
6925 xsltTransformError(NULL, NULL, child,
6926 "xml-stylesheet : no ID %s found\n", URI->fragment);
6927 } else {
6928 xmlDocPtr fake;
6929 xmlNodePtr subtree, newtree;
6930 xmlNsPtr ns;
6931
6932 #ifdef WITH_XSLT_DEBUG
6933 xsltGenericDebug(xsltGenericDebugContext,
6934 "creating new document from %s for embedded stylesheet\n",
6935 doc->URL);
6936 #endif
6937 /*
6938 * move the subtree in a new document passed to
6939 * the stylesheet analyzer
6940 */
6941 subtree = ID->parent;
6942 fake = xmlNewDoc(NULL);
6943 if (fake != NULL) {
6944 /*
6945 * Should the dictionary still be shared even though
6946 * the nodes are being copied rather than moved?
6947 */
6948 fake->dict = doc->dict;
6949 xmlDictReference(doc->dict);
6950 #ifdef WITH_XSLT_DEBUG
6951 xsltGenericDebug(xsltGenericDebugContext,
6952 "reusing dictionary from %s for embedded stylesheet\n",
6953 doc->URL);
6954 #endif
6955
6956 newtree = xmlDocCopyNode(subtree, fake, 1);
6957
6958 fake->URL = xmlNodeGetBase(doc, subtree->parent);
6959 #ifdef WITH_XSLT_DEBUG
6960 xsltGenericDebug(xsltGenericDebugContext,
6961 "set base URI for embedded stylesheet as %s\n",
6962 fake->URL);
6963 #endif
6964
6965 /*
6966 * Add all namespaces in scope of embedded stylesheet to
6967 * root element of newly created stylesheet document
6968 */
6969 while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
6970 for (ns = subtree->ns; ns; ns = ns->next) {
6971 xmlNewNs(newtree, ns->href, ns->prefix);
6972 }
6973 }
6974
6975 xmlAddChild((xmlNodePtr)fake, newtree);
6976 ret = xsltParseStylesheetDoc(fake);
6977 if (ret == NULL)
6978 xmlFreeDoc(fake);
6979 }
6980 }
6981 } else {
6982 xmlChar *URL, *base;
6983
6984 /*
6985 * Reference to an external stylesheet
6986 */
6987
6988 base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
6989 URL = xmlBuildURI(href, base);
6990 if (URL != NULL) {
6991 #ifdef WITH_XSLT_DEBUG_PARSING
6992 xsltGenericDebug(xsltGenericDebugContext,
6993 "xsltLoadStylesheetPI : fetching %s\n", URL);
6994 #endif
6995 ret = xsltParseStylesheetFile(URL);
6996 xmlFree(URL);
6997 } else {
6998 #ifdef WITH_XSLT_DEBUG_PARSING
6999 xsltGenericDebug(xsltGenericDebugContext,
7000 "xsltLoadStylesheetPI : fetching %s\n", href);
7001 #endif
7002 ret = xsltParseStylesheetFile(href);
7003 }
7004 if (base != NULL)
7005 xmlFree(base);
7006 }
7007 xmlFreeURI(URI);
7008 xmlFree(href);
7009 }
7010 return(ret);
7011 }