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