[LIBXSLT] Update to version 1.1.32. CORE-14291
[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))