d076c25614b5970ae4ff920df5706e35b06ffff1
[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(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->name = name;
260
261 /* Default values */
262 self->digit = xmlStrdup(BAD_CAST("#"));
263 self->patternSeparator = xmlStrdup(BAD_CAST(";"));
264 self->decimalPoint = xmlStrdup(BAD_CAST("."));
265 self->grouping = xmlStrdup(BAD_CAST(","));
266 self->percent = xmlStrdup(BAD_CAST("%"));
267 self->permille = xmlStrdup(BAD_CAST(permille));
268 self->zeroDigit = xmlStrdup(BAD_CAST("0"));
269 self->minusSign = xmlStrdup(BAD_CAST("-"));
270 self->infinity = xmlStrdup(BAD_CAST("Infinity"));
271 self->noNumber = xmlStrdup(BAD_CAST("NaN"));
272 }
273 return self;
274 }
275
276 static void
277 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
278 {
279 if (self != NULL) {
280 if (self->digit)
281 xmlFree(self->digit);
282 if (self->patternSeparator)
283 xmlFree(self->patternSeparator);
284 if (self->decimalPoint)
285 xmlFree(self->decimalPoint);
286 if (self->grouping)
287 xmlFree(self->grouping);
288 if (self->percent)
289 xmlFree(self->percent);
290 if (self->permille)
291 xmlFree(self->permille);
292 if (self->zeroDigit)
293 xmlFree(self->zeroDigit);
294 if (self->minusSign)
295 xmlFree(self->minusSign);
296 if (self->infinity)
297 xmlFree(self->infinity);
298 if (self->noNumber)
299 xmlFree(self->noNumber);
300 if (self->name)
301 xmlFree(self->name);
302 xmlFree(self);
303 }
304 }
305
306 static void
307 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
308 {
309 xsltDecimalFormatPtr iter;
310 xsltDecimalFormatPtr tmp;
311
312 if (self == NULL)
313 return;
314
315 iter = self->decimalFormat;
316 while (iter != NULL) {
317 tmp = iter->next;
318 xsltFreeDecimalFormat(iter);
319 iter = tmp;
320 }
321 }
322
323 /**
324 * xsltDecimalFormatGetByName:
325 * @style: the XSLT stylesheet
326 * @name: the decimal-format name to find
327 *
328 * Find decimal-format by name
329 *
330 * Returns the xsltDecimalFormatPtr
331 */
332 xsltDecimalFormatPtr
333 xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
334 {
335 xsltDecimalFormatPtr result = NULL;
336
337 if (name == NULL)
338 return style->decimalFormat;
339
340 while (style != NULL) {
341 for (result = style->decimalFormat->next;
342 result != NULL;
343 result = result->next) {
344 if (xmlStrEqual(name, result->name))
345 return result;
346 }
347 style = xsltNextImport(style);
348 }
349 return result;
350 }
351
352
353 /**
354 * xsltNewTemplate:
355 *
356 * Create a new XSLT Template
357 *
358 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
359 */
360 static xsltTemplatePtr
361 xsltNewTemplate(void) {
362 xsltTemplatePtr cur;
363
364 cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
365 if (cur == NULL) {
366 xsltTransformError(NULL, NULL, NULL,
367 "xsltNewTemplate : malloc failed\n");
368 return(NULL);
369 }
370 memset(cur, 0, sizeof(xsltTemplate));
371 cur->priority = XSLT_PAT_NO_PRIORITY;
372 return(cur);
373 }
374
375 /**
376 * xsltFreeTemplate:
377 * @template: an XSLT template
378 *
379 * Free up the memory allocated by @template
380 */
381 static void
382 xsltFreeTemplate(xsltTemplatePtr template) {
383 if (template == NULL)
384 return;
385 if (template->match) xmlFree(template->match);
386 /*
387 * NOTE: @name and @nameURI are put into the string dict now.
388 * if (template->name) xmlFree(template->name);
389 * if (template->nameURI) xmlFree(template->nameURI);
390 */
391 /*
392 if (template->mode) xmlFree(template->mode);
393 if (template->modeURI) xmlFree(template->modeURI);
394 */
395 if (template->inheritedNs) xmlFree(template->inheritedNs);
396
397 /* free profiling data */
398 if (template->templCalledTab) xmlFree(template->templCalledTab);
399 if (template->templCountTab) xmlFree(template->templCountTab);
400
401 memset(template, -1, sizeof(xsltTemplate));
402 xmlFree(template);
403 }
404
405 /**
406 * xsltFreeTemplateList:
407 * @template: an XSLT template list
408 *
409 * Free up the memory allocated by all the elements of @template
410 */
411 static void
412 xsltFreeTemplateList(xsltTemplatePtr template) {
413 xsltTemplatePtr cur;
414
415 while (template != NULL) {
416 cur = template;
417 template = template->next;
418 xsltFreeTemplate(cur);
419 }
420 }
421
422 #ifdef XSLT_REFACTORED
423
424 static void
425 xsltFreeNsAliasList(xsltNsAliasPtr item)
426 {
427 xsltNsAliasPtr tmp;
428
429 while (item) {
430 tmp = item;
431 item = item->next;
432 xmlFree(tmp);
433 }
434 return;
435 }
436
437 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
438 static void
439 xsltFreeNamespaceMap(xsltNsMapPtr item)
440 {
441 xsltNsMapPtr tmp;
442
443 while (item) {
444 tmp = item;
445 item = item->next;
446 xmlFree(tmp);
447 }
448 return;
449 }
450
451 static xsltNsMapPtr
452 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
453 xmlDocPtr doc,
454 xmlNsPtr ns,
455 xmlNodePtr elem)
456 {
457 xsltNsMapPtr ret;
458
459 if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
460 return(NULL);
461
462 ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
463 if (ret == NULL) {
464 xsltTransformError(NULL, cctxt->style, elem,
465 "Internal error: (xsltNewNamespaceMapItem) "
466 "memory allocation failed.\n");
467 return(NULL);
468 }
469 memset(ret, 0, sizeof(xsltNsMap));
470 ret->doc = doc;
471 ret->ns = ns;
472 ret->origNsName = ns->href;
473 /*
474 * Store the item at current stylesheet-level.
475 */
476 if (cctxt->psData->nsMap != NULL)
477 ret->next = cctxt->psData->nsMap;
478 cctxt->psData->nsMap = ret;
479
480 return(ret);
481 }
482 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
483
484 /**
485 * xsltCompilerVarInfoFree:
486 * @cctxt: the compilation context
487 *
488 * Frees the list of information for vars/params.
489 */
490 static void
491 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
492 {
493 xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
494
495 while (ivar) {
496 ivartmp = ivar;
497 ivar = ivar->next;
498 xmlFree(ivartmp);
499 }
500 }
501
502 /**
503 * xsltCompilerCtxtFree:
504 *
505 * Free an XSLT compiler context.
506 */
507 static void
508 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
509 {
510 if (cctxt == NULL)
511 return;
512 #ifdef WITH_XSLT_DEBUG_PARSING
513 xsltGenericDebug(xsltGenericDebugContext,
514 "Freeing compilation context\n");
515 xsltGenericDebug(xsltGenericDebugContext,
516 "### Max inodes: %d\n", cctxt->maxNodeInfos);
517 xsltGenericDebug(xsltGenericDebugContext,
518 "### Max LREs : %d\n", cctxt->maxLREs);
519 #endif
520 /*
521 * Free node-infos.
522 */
523 if (cctxt->inodeList != NULL) {
524 xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
525 while (cur != NULL) {
526 tmp = cur;
527 cur = cur->next;
528 xmlFree(tmp);
529 }
530 }
531 if (cctxt->tmpList != NULL)
532 xsltPointerListFree(cctxt->tmpList);
533 #ifdef XSLT_REFACTORED_XPATHCOMP
534 if (cctxt->xpathCtxt != NULL)
535 xmlXPathFreeContext(cctxt->xpathCtxt);
536 #endif
537 if (cctxt->nsAliases != NULL)
538 xsltFreeNsAliasList(cctxt->nsAliases);
539
540 if (cctxt->ivars)
541 xsltCompilerVarInfoFree(cctxt);
542
543 xmlFree(cctxt);
544 }
545
546 /**
547 * xsltCompilerCreate:
548 *
549 * Creates an XSLT compiler context.
550 *
551 * Returns the pointer to the created xsltCompilerCtxt or
552 * NULL in case of an internal error.
553 */
554 static xsltCompilerCtxtPtr
555 xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
556 xsltCompilerCtxtPtr ret;
557
558 ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
559 if (ret == NULL) {
560 xsltTransformError(NULL, style, NULL,
561 "xsltCompilerCreate: allocation of compiler "
562 "context failed.\n");
563 return(NULL);
564 }
565 memset(ret, 0, sizeof(xsltCompilerCtxt));
566
567 ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
568 ret->tmpList = xsltPointerListCreate(20);
569 if (ret->tmpList == NULL) {
570 goto internal_err;
571 }
572 #ifdef XSLT_REFACTORED_XPATHCOMP
573 /*
574 * Create the XPath compilation context in order
575 * to speed up precompilation of XPath expressions.
576 */
577 ret->xpathCtxt = xmlXPathNewContext(NULL);
578 if (ret->xpathCtxt == NULL)
579 goto internal_err;
580 #endif
581
582 return(ret);
583
584 internal_err:
585 xsltCompilationCtxtFree(ret);
586 return(NULL);
587 }
588
589 static void
590 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
591 {
592 xsltEffectiveNsPtr tmp;
593
594 while (first != NULL) {
595 tmp = first;
596 first = first->nextInStore;
597 xmlFree(tmp);
598 }
599 }
600
601 static void
602 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
603 {
604 if (data == NULL)
605 return;
606
607 if (data->inScopeNamespaces != NULL) {
608 int i;
609 xsltNsListContainerPtr nsi;
610 xsltPointerListPtr list =
611 (xsltPointerListPtr) data->inScopeNamespaces;
612
613 for (i = 0; i < list->number; i++) {
614 /*
615 * REVISIT TODO: Free info of in-scope namespaces.
616 */
617 nsi = (xsltNsListContainerPtr) list->items[i];
618 if (nsi->list != NULL)
619 xmlFree(nsi->list);
620 xmlFree(nsi);
621 }
622 xsltPointerListFree(list);
623 data->inScopeNamespaces = NULL;
624 }
625
626 if (data->exclResultNamespaces != NULL) {
627 int i;
628 xsltPointerListPtr list = (xsltPointerListPtr)
629 data->exclResultNamespaces;
630
631 for (i = 0; i < list->number; i++)
632 xsltPointerListFree((xsltPointerListPtr) list->items[i]);
633
634 xsltPointerListFree(list);
635 data->exclResultNamespaces = NULL;
636 }
637
638 if (data->extElemNamespaces != NULL) {
639 xsltPointerListPtr list = (xsltPointerListPtr)
640 data->extElemNamespaces;
641 int i;
642
643 for (i = 0; i < list->number; i++)
644 xsltPointerListFree((xsltPointerListPtr) list->items[i]);
645
646 xsltPointerListFree(list);
647 data->extElemNamespaces = NULL;
648 }
649 if (data->effectiveNs) {
650 xsltLREEffectiveNsNodesFree(data->effectiveNs);
651 data->effectiveNs = NULL;
652 }
653 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
654 xsltFreeNamespaceMap(data->nsMap);
655 #endif
656 xmlFree(data);
657 }
658
659 static xsltPrincipalStylesheetDataPtr
660 xsltNewPrincipalStylesheetData(void)
661 {
662 xsltPrincipalStylesheetDataPtr ret;
663
664 ret = (xsltPrincipalStylesheetDataPtr)
665 xmlMalloc(sizeof(xsltPrincipalStylesheetData));
666 if (ret == NULL) {
667 xsltTransformError(NULL, NULL, NULL,
668 "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
669 return(NULL);
670 }
671 memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
672
673 /*
674 * Global list of in-scope namespaces.
675 */
676 ret->inScopeNamespaces = xsltPointerListCreate(-1);
677 if (ret->inScopeNamespaces == NULL)
678 goto internal_err;
679 /*
680 * Global list of excluded result ns-decls.
681 */
682 ret->exclResultNamespaces = xsltPointerListCreate(-1);
683 if (ret->exclResultNamespaces == NULL)
684 goto internal_err;
685 /*
686 * Global list of extension instruction namespace names.
687 */
688 ret->extElemNamespaces = xsltPointerListCreate(-1);
689 if (ret->extElemNamespaces == NULL)
690 goto internal_err;
691
692 return(ret);
693
694 internal_err:
695
696 return(NULL);
697 }
698
699 #endif
700
701 /**
702 * xsltNewStylesheet:
703 *
704 * Create a new XSLT Stylesheet
705 *
706 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
707 */
708 xsltStylesheetPtr
709 xsltNewStylesheet(void) {
710 xsltStylesheetPtr ret = NULL;
711
712 ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
713 if (ret == NULL) {
714 xsltTransformError(NULL, NULL, NULL,
715 "xsltNewStylesheet : malloc failed\n");
716 goto internal_err;
717 }
718 memset(ret, 0, sizeof(xsltStylesheet));
719
720 ret->omitXmlDeclaration = -1;
721 ret->standalone = -1;
722 ret->decimalFormat = xsltNewDecimalFormat(NULL);
723 ret->indent = -1;
724 ret->errors = 0;
725 ret->warnings = 0;
726 ret->exclPrefixNr = 0;
727 ret->exclPrefixMax = 0;
728 ret->exclPrefixTab = NULL;
729 ret->extInfos = NULL;
730 ret->extrasNr = 0;
731 ret->internalized = 1;
732 ret->literal_result = 0;
733 ret->forwards_compatible = 0;
734 ret->dict = xmlDictCreate();
735 #ifdef WITH_XSLT_DEBUG
736 xsltGenericDebug(xsltGenericDebugContext,
737 "creating dictionary for stylesheet\n");
738 #endif
739
740 xsltInit();
741
742 return(ret);
743
744 internal_err:
745 if (ret != NULL)
746 xsltFreeStylesheet(ret);
747 return(NULL);
748 }
749
750 /**
751 * xsltAllocateExtra:
752 * @style: an XSLT stylesheet
753 *
754 * Allocate an extra runtime information slot statically while compiling
755 * the stylesheet and return its number
756 *
757 * Returns the number of the slot
758 */
759 int
760 xsltAllocateExtra(xsltStylesheetPtr style)
761 {
762 return(style->extrasNr++);
763 }
764
765 /**
766 * xsltAllocateExtraCtxt:
767 * @ctxt: an XSLT transformation context
768 *
769 * Allocate an extra runtime information slot at run-time
770 * and return its number
771 * This make sure there is a slot ready in the transformation context
772 *
773 * Returns the number of the slot
774 */
775 int
776 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
777 {
778 if (ctxt->extrasNr >= ctxt->extrasMax) {
779 int i;
780 if (ctxt->extrasNr == 0) {
781 ctxt->extrasMax = 20;
782 ctxt->extras = (xsltRuntimeExtraPtr)
783 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
784 if (ctxt->extras == NULL) {
785 xmlGenericError(xmlGenericErrorContext,
786 "xsltAllocateExtraCtxt: out of memory\n");
787 ctxt->state = XSLT_STATE_ERROR;
788 return(0);
789 }
790 for (i = 0;i < ctxt->extrasMax;i++) {
791 ctxt->extras[i].info = NULL;
792 ctxt->extras[i].deallocate = NULL;
793 ctxt->extras[i].val.ptr = NULL;
794 }
795
796 } else {
797 xsltRuntimeExtraPtr tmp;
798
799 ctxt->extrasMax += 100;
800 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
801 ctxt->extrasMax * sizeof(xsltRuntimeExtra));
802 if (tmp == NULL) {
803 xmlGenericError(xmlGenericErrorContext,
804 "xsltAllocateExtraCtxt: out of memory\n");
805 ctxt->state = XSLT_STATE_ERROR;
806 return(0);
807 }
808 ctxt->extras = tmp;
809 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
810 ctxt->extras[i].info = NULL;
811 ctxt->extras[i].deallocate = NULL;
812 ctxt->extras[i].val.ptr = NULL;
813 }
814 }
815 }
816 return(ctxt->extrasNr++);
817 }
818
819 /**
820 * xsltFreeStylesheetList:
821 * @style: an XSLT stylesheet list
822 *
823 * Free up the memory allocated by the list @style
824 */
825 static void
826 xsltFreeStylesheetList(xsltStylesheetPtr style) {
827 xsltStylesheetPtr next;
828
829 while (style != NULL) {
830 next = style->next;
831 xsltFreeStylesheet(style);
832 style = next;
833 }
834 }
835
836 /**
837 * xsltCleanupStylesheetTree:
838 *
839 * @doc: the document-node
840 * @node: the element where the stylesheet is rooted at
841 *
842 * Actually @node need not be the document-element, but
843 * currently Libxslt does not support embedded stylesheets.
844 *
845 * Returns 0 if OK, -1 on API or internal errors.
846 */
847 static int
848 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
849 xmlNodePtr rootElem ATTRIBUTE_UNUSED)
850 {
851 #if 0 /* TODO: Currently disabled, since probably not needed. */
852 xmlNodePtr cur;
853
854 if ((doc == NULL) || (rootElem == NULL) ||
855 (rootElem->type != XML_ELEMENT_NODE) ||
856 (doc != rootElem->doc))
857 return(-1);
858
859 /*
860 * Cleanup was suggested by Aleksey Sanin:
861 * Clear the PSVI field to avoid problems if the
862 * node-tree of the stylesheet is intended to be used for
863 * further processing by the user (e.g. for compiling it
864 * once again - although not recommended).
865 */
866
867 cur = rootElem;
868 while (cur != NULL) {
869 if (cur->type == XML_ELEMENT_NODE) {
870 /*
871 * Clear the PSVI field.
872 */
873 cur->psvi = NULL;
874 if (cur->children) {
875 cur = cur->children;
876 continue;
877 }
878 }
879
880 leave_node:
881 if (cur == rootElem)
882 break;
883 if (cur->next != NULL)
884 cur = cur->next;
885 else {
886 cur = cur->parent;
887 if (cur == NULL)
888 break;
889 goto leave_node;
890 }
891 }
892 #endif /* #if 0 */
893 return(0);
894 }
895
896 /**
897 * xsltFreeStylesheet:
898 * @style: an XSLT stylesheet
899 *
900 * Free up the memory allocated by @style
901 */
902 void
903 xsltFreeStylesheet(xsltStylesheetPtr style)
904 {
905 if (style == NULL)
906 return;
907
908 #ifdef XSLT_REFACTORED
909 /*
910 * Start with a cleanup of the main stylesheet's doc.
911 */
912 if ((style->principal == style) && (style->doc))
913 xsltCleanupStylesheetTree(style->doc,
914 xmlDocGetRootElement(style->doc));
915 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
916 /*
917 * Restore changed ns-decls before freeing the document.
918 */
919 if ((style->doc != NULL) &&
920 XSLT_HAS_INTERNAL_NSMAP(style))
921 {
922 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
923 style->doc);
924 }
925 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
926 #else
927 /*
928 * Start with a cleanup of the main stylesheet's doc.
929 */
930 if ((style->parent == NULL) && (style->doc))
931 xsltCleanupStylesheetTree(style->doc,
932 xmlDocGetRootElement(style->doc));
933 #endif /* XSLT_REFACTORED */
934
935 xsltFreeKeys(style);
936 xsltFreeExts(style);
937 xsltFreeTemplateHashes(style);
938 xsltFreeDecimalFormatList(style);
939 xsltFreeTemplateList(style->templates);
940 xsltFreeAttributeSetsHashes(style);
941 xsltFreeNamespaceAliasHashes(style);
942 xsltFreeStylePreComps(style);
943 /*
944 * Free documents of all included stylsheet modules of this
945 * stylesheet level.
946 */
947 xsltFreeStyleDocuments(style);
948 /*
949 * TODO: Best time to shutdown extension stuff?
950 */
951 xsltShutdownExts(style);
952
953 if (style->variables != NULL)
954 xsltFreeStackElemList(style->variables);
955 if (style->cdataSection != NULL)
956 xmlHashFree(style->cdataSection, NULL);
957 if (style->stripSpaces != NULL)
958 xmlHashFree(style->stripSpaces, NULL);
959 if (style->nsHash != NULL)
960 xmlHashFree(style->nsHash, NULL);
961 if (style->exclPrefixTab != NULL)
962 xmlFree(style->exclPrefixTab);
963 if (style->method != NULL)
964 xmlFree(style->method);
965 if (style->methodURI != NULL)
966 xmlFree(style->methodURI);
967 if (style->version != NULL)
968 xmlFree(style->version);
969 if (style->encoding != NULL)
970 xmlFree(style->encoding);
971 if (style->doctypePublic != NULL)
972 xmlFree(style->doctypePublic);
973 if (style->doctypeSystem != NULL)
974 xmlFree(style->doctypeSystem);
975 if (style->mediaType != NULL)
976 xmlFree(style->mediaType);
977 if (style->attVTs)
978 xsltFreeAVTList(style->attVTs);
979 if (style->imports != NULL)
980 xsltFreeStylesheetList(style->imports);
981
982 #ifdef XSLT_REFACTORED
983 /*
984 * If this is the principal stylesheet, then
985 * free its internal data.
986 */
987 if (style->principal == style) {
988 if (style->principalData) {
989 xsltFreePrincipalStylesheetData(style->principalData);
990 style->principalData = NULL;
991 }
992 }
993 #endif
994 /*
995 * Better to free the main document of this stylesheet level
996 * at the end - so here.
997 */
998 if (style->doc != NULL) {
999 xmlFreeDoc(style->doc);
1000 }
1001
1002 #ifdef WITH_XSLT_DEBUG
1003 xsltGenericDebug(xsltGenericDebugContext,
1004 "freeing dictionary from stylesheet\n");
1005 #endif
1006 xmlDictFree(style->dict);
1007
1008 memset(style, -1, sizeof(xsltStylesheet));
1009 xmlFree(style);
1010 }
1011
1012 /************************************************************************
1013 * *
1014 * Parsing of an XSLT Stylesheet *
1015 * *
1016 ************************************************************************/
1017
1018 #ifdef XSLT_REFACTORED
1019 /*
1020 * This is now performed in an optimized way in xsltParseXSLTTemplate.
1021 */
1022 #else
1023 /**
1024 * xsltGetInheritedNsList:
1025 * @style: the stylesheet
1026 * @template: the template
1027 * @node: the current node
1028 *
1029 * Search all the namespace applying to a given element except the ones
1030 * from excluded output prefixes currently in scope. Initialize the
1031 * template inheritedNs list with it.
1032 *
1033 * Returns the number of entries found
1034 */
1035 static int
1036 xsltGetInheritedNsList(xsltStylesheetPtr style,
1037 xsltTemplatePtr template,
1038 xmlNodePtr node)
1039 {
1040 xmlNsPtr cur;
1041 xmlNsPtr *ret = NULL;
1042 int nbns = 0;
1043 int maxns = 10;
1044 int i;
1045
1046 if ((style == NULL) || (template == NULL) || (node == NULL) ||
1047 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1048 return(0);
1049 while (node != NULL) {
1050 if (node->type == XML_ELEMENT_NODE) {
1051 cur = node->nsDef;
1052 while (cur != NULL) {
1053 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1054 goto skip_ns;
1055
1056 if ((cur->prefix != NULL) &&
1057 (xsltCheckExtPrefix(style, cur->prefix)))
1058 goto skip_ns;
1059 /*
1060 * Check if this namespace was excluded.
1061 * Note that at this point only the exclusions defined
1062 * on the topmost stylesheet element are in the exclusion-list.
1063 */
1064 for (i = 0;i < style->exclPrefixNr;i++) {
1065 if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1066 goto skip_ns;
1067 }
1068 if (ret == NULL) {
1069 ret =
1070 (xmlNsPtr *) xmlMalloc((maxns + 1) *
1071 sizeof(xmlNsPtr));
1072 if (ret == NULL) {
1073 xmlGenericError(xmlGenericErrorContext,
1074 "xsltGetInheritedNsList : out of memory!\n");
1075 return(0);
1076 }
1077 ret[nbns] = NULL;
1078 }
1079 /*
1080 * Skip shadowed namespace bindings.
1081 */
1082 for (i = 0; i < nbns; i++) {
1083 if ((cur->prefix == ret[i]->prefix) ||
1084 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
1085 break;
1086 }
1087 if (i >= nbns) {
1088 if (nbns >= maxns) {
1089 maxns *= 2;
1090 ret = (xmlNsPtr *) xmlRealloc(ret,
1091 (maxns +
1092 1) *
1093 sizeof(xmlNsPtr));
1094 if (ret == NULL) {
1095 xmlGenericError(xmlGenericErrorContext,
1096 "xsltGetInheritedNsList : realloc failed!\n");
1097 return(0);
1098 }
1099 }
1100 ret[nbns++] = cur;
1101 ret[nbns] = NULL;
1102 }
1103 skip_ns:
1104 cur = cur->next;
1105 }
1106 }
1107 node = node->parent;
1108 }
1109 if (nbns != 0) {
1110 #ifdef WITH_XSLT_DEBUG_PARSING
1111 xsltGenericDebug(xsltGenericDebugContext,
1112 "template has %d inherited namespaces\n", nbns);
1113 #endif
1114 template->inheritedNsNr = nbns;
1115 template->inheritedNs = ret;
1116 }
1117 return (nbns);
1118 }
1119 #endif /* else of XSLT_REFACTORED */
1120
1121 /**
1122 * xsltParseStylesheetOutput:
1123 * @style: the XSLT stylesheet
1124 * @cur: the "output" element
1125 *
1126 * parse an XSLT stylesheet output element and record
1127 * information related to the stylesheet output
1128 */
1129
1130 void
1131 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
1132 {
1133 xmlChar *elements,
1134 *prop;
1135 xmlChar *element,
1136 *end;
1137
1138 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1139 return;
1140
1141 prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1142 if (prop != NULL) {
1143 if (style->version != NULL)
1144 xmlFree(style->version);
1145 style->version = prop;
1146 }
1147
1148 prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1149 if (prop != NULL) {
1150 if (style->encoding != NULL)
1151 xmlFree(style->encoding);
1152 style->encoding = prop;
1153 }
1154
1155 /* relaxed to support xt:document
1156 * TODO KB: What does "relaxed to support xt:document" mean?
1157 */
1158 prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1159 if (prop != NULL) {
1160 const xmlChar *URI;
1161
1162 if (style->method != NULL)
1163 xmlFree(style->method);
1164 style->method = NULL;
1165 if (style->methodURI != NULL)
1166 xmlFree(style->methodURI);
1167 style->methodURI = NULL;
1168
1169 /*
1170 * TODO: Don't use xsltGetQNameURI().
1171 */
1172 URI = xsltGetQNameURI(cur, &prop);
1173 if (prop == NULL) {
1174 if (style != NULL) style->errors++;
1175 } else if (URI == NULL) {
1176 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1177 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1178 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1179 style->method = prop;
1180 } else {
1181 xsltTransformError(NULL, style, cur,
1182 "invalid value for method: %s\n", prop);
1183 if (style != NULL) style->warnings++;
1184 }
1185 } else {
1186 style->method = prop;
1187 style->methodURI = xmlStrdup(URI);
1188 }
1189 }
1190
1191 prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1192 if (prop != NULL) {
1193 if (style->doctypeSystem != NULL)
1194 xmlFree(style->doctypeSystem);
1195 style->doctypeSystem = prop;
1196 }
1197
1198 prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1199 if (prop != NULL) {
1200 if (style->doctypePublic != NULL)
1201 xmlFree(style->doctypePublic);
1202 style->doctypePublic = prop;
1203 }
1204
1205 prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1206 if (prop != NULL) {
1207 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1208 style->standalone = 1;
1209 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1210 style->standalone = 0;
1211 } else {
1212 xsltTransformError(NULL, style, cur,
1213 "invalid value for standalone: %s\n", prop);
1214 style->errors++;
1215 }
1216 xmlFree(prop);
1217 }
1218
1219 prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1220 if (prop != NULL) {
1221 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1222 style->indent = 1;
1223 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1224 style->indent = 0;
1225 } else {
1226 xsltTransformError(NULL, style, cur,
1227 "invalid value for indent: %s\n", prop);
1228 style->errors++;
1229 }
1230 xmlFree(prop);
1231 }
1232
1233 prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1234 if (prop != NULL) {
1235 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1236 style->omitXmlDeclaration = 1;
1237 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1238 style->omitXmlDeclaration = 0;
1239 } else {
1240 xsltTransformError(NULL, style, cur,
1241 "invalid value for omit-xml-declaration: %s\n",
1242 prop);
1243 style->errors++;
1244 }
1245 xmlFree(prop);
1246 }
1247
1248 elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1249 NULL);
1250 if (elements != NULL) {
1251 if (style->cdataSection == NULL)
1252 style->cdataSection = xmlHashCreate(10);
1253 if (style->cdataSection == NULL)
1254 return;
1255
1256 element = elements;
1257 while (*element != 0) {
1258 while (IS_BLANK(*element))
1259 element++;
1260 if (*element == 0)
1261 break;
1262 end = element;
1263 while ((*end != 0) && (!IS_BLANK(*end)))
1264 end++;
1265 element = xmlStrndup(element, end - element);
1266 if (element) {
1267 #ifdef WITH_XSLT_DEBUG_PARSING
1268 xsltGenericDebug(xsltGenericDebugContext,
1269 "add cdata section output element %s\n",
1270 element);
1271 #endif
1272 if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1273 xsltTransformError(NULL, style, cur,
1274 "Attribute 'cdata-section-elements': The value "
1275 "'%s' is not a valid QName.\n", element);
1276 xmlFree(element);
1277 style->errors++;
1278 } else {
1279 const xmlChar *URI;
1280
1281 /*
1282 * TODO: Don't use xsltGetQNameURI().
1283 */
1284 URI = xsltGetQNameURI(cur, &element);
1285 if (element == NULL) {
1286 /*
1287 * TODO: We'll report additionally an error
1288 * via the stylesheet's error handling.
1289 */
1290 xsltTransformError(NULL, style, cur,
1291 "Attribute 'cdata-section-elements': The value "
1292 "'%s' is not a valid QName.\n", element);
1293 style->errors++;
1294 } else {
1295 xmlNsPtr ns;
1296
1297 /*
1298 * XSLT-1.0 "Each QName is expanded into an
1299 * expanded-name using the namespace declarations in
1300 * effect on the xsl:output element in which the QName
1301 * occurs; if there is a default namespace, it is used
1302 * for QNames that do not have a prefix"
1303 * NOTE: Fix of bug #339570.
1304 */
1305 if (URI == NULL) {
1306 ns = xmlSearchNs(style->doc, cur, NULL);
1307 if (ns != NULL)
1308 URI = ns->href;
1309 }
1310 xmlHashAddEntry2(style->cdataSection, element, URI,
1311 (void *) "cdata");
1312 xmlFree(element);
1313 }
1314 }
1315 }
1316 element = end;
1317 }
1318 xmlFree(elements);
1319 }
1320
1321 prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1322 if (prop != NULL) {
1323 if (style->mediaType)
1324 xmlFree(style->mediaType);
1325 style->mediaType = prop;
1326 }
1327 if (cur->children != NULL) {
1328 xsltParseContentError(style, cur->children);
1329 }
1330 }
1331
1332 /**
1333 * xsltParseStylesheetDecimalFormat:
1334 * @style: the XSLT stylesheet
1335 * @cur: the "decimal-format" element
1336 *
1337 * <!-- Category: top-level-element -->
1338 * <xsl:decimal-format
1339 * name = qname, decimal-separator = char, grouping-separator = char,
1340 * infinity = string, minus-sign = char, NaN = string, percent = char
1341 * per-mille = char, zero-digit = char, digit = char,
1342 * pattern-separator = char />
1343 *
1344 * parse an XSLT stylesheet decimal-format element and
1345 * and record the formatting characteristics
1346 */
1347 static void
1348 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
1349 {
1350 xmlChar *prop;
1351 xsltDecimalFormatPtr format;
1352 xsltDecimalFormatPtr iter;
1353
1354 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1355 return;
1356
1357 format = style->decimalFormat;
1358
1359 prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1360 if (prop != NULL) {
1361 format = xsltDecimalFormatGetByName(style, prop);
1362 if (format != NULL) {
1363 xsltTransformError(NULL, style, cur,
1364 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1365 if (style != NULL) style->warnings++;
1366 return;
1367 }
1368 format = xsltNewDecimalFormat(prop);
1369 if (format == NULL) {
1370 xsltTransformError(NULL, style, cur,
1371 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1372 if (style != NULL) style->errors++;
1373 return;
1374 }
1375 /* Append new decimal-format structure */
1376 for (iter = style->decimalFormat; iter->next; iter = iter->next)
1377 ;
1378 if (iter)
1379 iter->next = format;
1380 }
1381
1382 prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1383 if (prop != NULL) {
1384 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1385 format->decimalPoint = prop;
1386 }
1387
1388 prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1389 if (prop != NULL) {
1390 if (format->grouping != NULL) xmlFree(format->grouping);
1391 format->grouping = prop;
1392 }
1393
1394 prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1395 if (prop != NULL) {
1396 if (format->infinity != NULL) xmlFree(format->infinity);
1397 format->infinity = prop;
1398 }
1399
1400 prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1401 if (prop != NULL) {
1402 if (format->minusSign != NULL) xmlFree(format->minusSign);
1403 format->minusSign = prop;
1404 }
1405
1406 prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1407 if (prop != NULL) {
1408 if (format->noNumber != NULL) xmlFree(format->noNumber);
1409 format->noNumber = prop;
1410 }
1411
1412 prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1413 if (prop != NULL) {
1414 if (format->percent != NULL) xmlFree(format->percent);
1415 format->percent = prop;
1416 }
1417
1418 prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1419 if (prop != NULL) {
1420 if (format->permille != NULL) xmlFree(format->permille);
1421 format->permille = prop;
1422 }
1423
1424 prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1425 if (prop != NULL) {
1426 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1427 format->zeroDigit = prop;
1428 }
1429
1430 prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1431 if (prop != NULL) {
1432 if (format->digit != NULL) xmlFree(format->digit);
1433 format->digit = prop;
1434 }
1435
1436 prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1437 if (prop != NULL) {
1438 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1439 format->patternSeparator = prop;
1440 }
1441 if (cur->children != NULL) {
1442 xsltParseContentError(style, cur->children);
1443 }
1444 }
1445
1446 /**
1447 * xsltParseStylesheetPreserveSpace:
1448 * @style: the XSLT stylesheet
1449 * @cur: the "preserve-space" element
1450 *
1451 * parse an XSLT stylesheet preserve-space element and record
1452 * elements needing preserving
1453 */
1454
1455 static void
1456 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1457 xmlChar *elements;
1458 xmlChar *element, *end;
1459
1460 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1461 return;
1462
1463 elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1464 if (elements == NULL) {
1465 xsltTransformError(NULL, style, cur,
1466 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1467 if (style != NULL) style->warnings++;
1468 return;
1469 }
1470
1471 if (style->stripSpaces == NULL)
1472 style->stripSpaces = xmlHashCreate(10);
1473 if (style->stripSpaces == NULL)
1474 return;
1475
1476 element = elements;
1477 while (*element != 0) {
1478 while (IS_BLANK(*element)) element++;
1479 if (*element == 0)
1480 break;
1481 end = element;
1482 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1483 element = xmlStrndup(element, end - element);
1484 if (element) {
1485 #ifdef WITH_XSLT_DEBUG_PARSING
1486 xsltGenericDebug(xsltGenericDebugContext,
1487 "add preserved space element %s\n", element);
1488 #endif
1489 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1490 style->stripAll = -1;
1491 } else {
1492 const xmlChar *URI;
1493
1494 /*
1495 * TODO: Don't use xsltGetQNameURI().
1496 */
1497 URI = xsltGetQNameURI(cur, &element);
1498
1499 xmlHashAddEntry2(style->stripSpaces, element, URI,
1500 (xmlChar *) "preserve");
1501 }
1502 xmlFree(element);
1503 }
1504 element = end;
1505 }
1506 xmlFree(elements);
1507 if (cur->children != NULL) {
1508 xsltParseContentError(style, cur->children);
1509 }
1510 }
1511
1512 #ifdef XSLT_REFACTORED
1513 #else
1514 /**
1515 * xsltParseStylesheetExtPrefix:
1516 * @style: the XSLT stylesheet
1517 * @template: the "extension-element-prefixes" prefix
1518 *
1519 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1520 * and register the namespaces of extension instruction.
1521 * SPEC "A namespace is designated as an extension namespace by using
1522 * an extension-element-prefixes attribute on:
1523 * 1) an xsl:stylesheet element
1524 * 2) an xsl:extension-element-prefixes attribute on a
1525 * literal result element
1526 * 3) an extension instruction."
1527 */
1528 static void
1529 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1530 int isXsltElem) {
1531 xmlChar *prefixes;
1532 xmlChar *prefix, *end;
1533
1534 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1535 return;
1536
1537 if (isXsltElem) {
1538 /* For xsl:stylesheet/xsl:transform. */
1539 prefixes = xmlGetNsProp(cur,
1540 (const xmlChar *)"extension-element-prefixes", NULL);
1541 } else {
1542 /* For literal result elements and extension instructions. */
1543 prefixes = xmlGetNsProp(cur,
1544 (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1545 }
1546 if (prefixes == NULL) {
1547 return;
1548 }
1549
1550 prefix = prefixes;
1551 while (*prefix != 0) {
1552 while (IS_BLANK(*prefix)) prefix++;
1553 if (*prefix == 0)
1554 break;
1555 end = prefix;
1556 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1557 prefix = xmlStrndup(prefix, end - prefix);
1558 if (prefix) {
1559 xmlNsPtr ns;
1560
1561 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1562 ns = xmlSearchNs(style->doc, cur, NULL);
1563 else
1564 ns = xmlSearchNs(style->doc, cur, prefix);
1565 if (ns == NULL) {
1566 xsltTransformError(NULL, style, cur,
1567 "xsl:extension-element-prefix : undefined namespace %s\n",
1568 prefix);
1569 if (style != NULL) style->warnings++;
1570 } else {
1571 #ifdef WITH_XSLT_DEBUG_PARSING
1572 xsltGenericDebug(xsltGenericDebugContext,
1573 "add extension prefix %s\n", prefix);
1574 #endif
1575 xsltRegisterExtPrefix(style, prefix, ns->href);
1576 }
1577 xmlFree(prefix);
1578 }
1579 prefix = end;
1580 }
1581 xmlFree(prefixes);
1582 }
1583 #endif /* else of XSLT_REFACTORED */
1584
1585 /**
1586 * xsltParseStylesheetStripSpace:
1587 * @style: the XSLT stylesheet
1588 * @cur: the "strip-space" element
1589 *
1590 * parse an XSLT stylesheet's strip-space element and record
1591 * the elements needing stripping
1592 */
1593
1594 static void
1595 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1596 xmlChar *elements;
1597 xmlChar *element, *end;
1598
1599 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1600 return;
1601
1602 elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1603 if (elements == NULL) {
1604 xsltTransformError(NULL, style, cur,
1605 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1606 if (style != NULL) style->warnings++;
1607 return;
1608 }
1609
1610 if (style->stripSpaces == NULL)
1611 style->stripSpaces = xmlHashCreate(10);
1612 if (style->stripSpaces == NULL)
1613 return;
1614
1615 element = elements;
1616 while (*element != 0) {
1617 while (IS_BLANK(*element)) element++;
1618 if (*element == 0)
1619 break;
1620 end = element;
1621 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1622 element = xmlStrndup(element, end - element);
1623 if (element) {
1624 #ifdef WITH_XSLT_DEBUG_PARSING
1625 xsltGenericDebug(xsltGenericDebugContext,
1626 "add stripped space element %s\n", element);
1627 #endif
1628 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1629 style->stripAll = 1;
1630 } else {
1631 const xmlChar *URI;
1632
1633 /*
1634 * TODO: Don't use xsltGetQNameURI().
1635 */
1636 URI = xsltGetQNameURI(cur, &element);
1637
1638 xmlHashAddEntry2(style->stripSpaces, element, URI,
1639 (xmlChar *) "strip");
1640 }
1641 xmlFree(element);
1642 }
1643 element = end;
1644 }
1645 xmlFree(elements);
1646 if (cur->children != NULL) {
1647 xsltParseContentError(style, cur->children);
1648 }
1649 }
1650
1651 #ifdef XSLT_REFACTORED
1652 #else
1653 /**
1654 * xsltParseStylesheetExcludePrefix:
1655 * @style: the XSLT stylesheet
1656 * @cur: the current point in the stylesheet
1657 *
1658 * parse an XSLT stylesheet exclude prefix and record
1659 * namespaces needing stripping
1660 *
1661 * Returns the number of Excluded prefixes added at that level
1662 */
1663
1664 static int
1665 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1666 int isXsltElem)
1667 {
1668 int nb = 0;
1669 xmlChar *prefixes;
1670 xmlChar *prefix, *end;
1671
1672 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1673 return(0);
1674
1675 if (isXsltElem)
1676 prefixes = xmlGetNsProp(cur,
1677 (const xmlChar *)"exclude-result-prefixes", NULL);
1678 else
1679 prefixes = xmlGetNsProp(cur,
1680 (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1681
1682 if (prefixes == NULL) {
1683 return(0);
1684 }
1685
1686 prefix = prefixes;
1687 while (*prefix != 0) {
1688 while (IS_BLANK(*prefix)) prefix++;
1689 if (*prefix == 0)
1690 break;
1691 end = prefix;
1692 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1693 prefix = xmlStrndup(prefix, end - prefix);
1694 if (prefix) {
1695 xmlNsPtr ns;
1696
1697 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1698 ns = xmlSearchNs(style->doc, cur, NULL);
1699 else
1700 ns = xmlSearchNs(style->doc, cur, prefix);
1701 if (ns == NULL) {
1702 xsltTransformError(NULL, style, cur,
1703 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1704 prefix);
1705 if (style != NULL) style->warnings++;
1706 } else {
1707 if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
1708 #ifdef WITH_XSLT_DEBUG_PARSING
1709 xsltGenericDebug(xsltGenericDebugContext,
1710 "exclude result prefix %s\n", prefix);
1711 #endif
1712 nb++;
1713 }
1714 }
1715 xmlFree(prefix);
1716 }
1717 prefix = end;
1718 }
1719 xmlFree(prefixes);
1720 return(nb);
1721 }
1722 #endif /* else of XSLT_REFACTORED */
1723
1724 #ifdef XSLT_REFACTORED
1725
1726 /*
1727 * xsltTreeEnsureXMLDecl:
1728 * @doc: the doc
1729 *
1730 * BIG NOTE:
1731 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1732 * Ensures that there is an XML namespace declaration on the doc.
1733 *
1734 * Returns the XML ns-struct or NULL on API and internal errors.
1735 */
1736 static xmlNsPtr
1737 xsltTreeEnsureXMLDecl(xmlDocPtr doc)
1738 {
1739 if (doc == NULL)
1740 return (NULL);
1741 if (doc->oldNs != NULL)
1742 return (doc->oldNs);
1743 {
1744 xmlNsPtr ns;
1745 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1746 if (ns == NULL) {
1747 xmlGenericError(xmlGenericErrorContext,
1748 "xsltTreeEnsureXMLDecl: Failed to allocate "
1749 "the XML namespace.\n");
1750 return (NULL);
1751 }
1752 memset(ns, 0, sizeof(xmlNs));
1753 ns->type = XML_LOCAL_NAMESPACE;
1754 /*
1755 * URGENT TODO: revisit this.
1756 */
1757 #ifdef LIBXML_NAMESPACE_DICT
1758 if (doc->dict)
1759 ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
1760 else
1761 ns->href = xmlStrdup(XML_XML_NAMESPACE);
1762 #else
1763 ns->href = xmlStrdup(XML_XML_NAMESPACE);
1764 #endif
1765 ns->prefix = xmlStrdup((const xmlChar *)"xml");
1766 doc->oldNs = ns;
1767 return (ns);
1768 }
1769 }
1770
1771 /*
1772 * xsltTreeAcquireStoredNs:
1773 * @doc: the doc
1774 * @nsName: the namespace name
1775 * @prefix: the prefix
1776 *
1777 * BIG NOTE:
1778 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1779 * Creates or reuses an xmlNs struct on doc->oldNs with
1780 * the given prefix and namespace name.
1781 *
1782 * Returns the aquired ns struct or NULL in case of an API
1783 * or internal error.
1784 */
1785 static xmlNsPtr
1786 xsltTreeAcquireStoredNs(xmlDocPtr doc,
1787 const xmlChar *nsName,
1788 const xmlChar *prefix)
1789 {
1790 xmlNsPtr ns;
1791
1792 if (doc == NULL)
1793 return (NULL);
1794 if (doc->oldNs != NULL)
1795 ns = doc->oldNs;
1796 else
1797 ns = xsltTreeEnsureXMLDecl(doc);
1798 if (ns == NULL)
1799 return (NULL);
1800 if (ns->next != NULL) {
1801 /* Reuse. */
1802 ns = ns->next;
1803 while (ns != NULL) {
1804 if ((ns->prefix == NULL) != (prefix == NULL)) {
1805 /* NOP */
1806 } else if (prefix == NULL) {
1807 if (xmlStrEqual(ns->href, nsName))
1808 return (ns);
1809 } else {
1810 if ((ns->prefix[0] == prefix[0]) &&
1811 xmlStrEqual(ns->prefix, prefix) &&
1812 xmlStrEqual(ns->href, nsName))
1813 return (ns);
1814
1815 }
1816 if (ns->next == NULL)
1817 break;
1818 ns = ns->next;
1819 }
1820 }
1821 /* Create. */
1822 ns->next = xmlNewNs(NULL, nsName, prefix);
1823 return (ns->next);
1824 }
1825
1826 /**
1827 * xsltLREBuildEffectiveNs:
1828 *
1829 * Apply ns-aliasing on the namespace of the given @elem and
1830 * its attributes.
1831 */
1832 static int
1833 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
1834 xmlNodePtr elem)
1835 {
1836 xmlNsPtr ns;
1837 xsltNsAliasPtr alias;
1838
1839 if ((cctxt == NULL) || (elem == NULL))
1840 return(-1);
1841 if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
1842 return(0);
1843
1844 alias = cctxt->nsAliases;
1845 while (alias != NULL) {
1846 if ( /* If both namespaces are NULL... */
1847 ( (elem->ns == NULL) &&
1848 ((alias->literalNs == NULL) ||
1849 (alias->literalNs->href == NULL)) ) ||
1850 /* ... or both namespace are equal */
1851 ( (elem->ns != NULL) &&
1852 (alias->literalNs != NULL) &&
1853 xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1854 {
1855 if ((alias->targetNs != NULL) &&
1856 (alias->targetNs->href != NULL))
1857 {
1858 /*
1859 * Convert namespace.
1860 */
1861 if (elem->doc == alias->docOfTargetNs) {
1862 /*
1863 * This is the nice case: same docs.
1864 * This will eventually assign a ns-decl which
1865 * is shadowed, but this has no negative effect on
1866 * the generation of the result tree.
1867 */
1868 elem->ns = alias->targetNs;
1869 } else {
1870 /*
1871 * This target xmlNs originates from a different
1872 * stylesheet tree. Try to locate it in the
1873 * in-scope namespaces.
1874 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1875 */
1876 ns = xmlSearchNs(elem->doc, elem,
1877 alias->targetNs->prefix);
1878 /*
1879 * If no matching ns-decl found, then assign a
1880 * ns-decl stored in xmlDoc.
1881 */
1882 if ((ns == NULL) ||
1883 (! xmlStrEqual(ns->href, alias->targetNs->href)))
1884 {
1885 /*
1886 * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1887 * is not very efficient, but currently I don't
1888 * see an other way of *safely* changing a node's
1889 * namespace, since the xmlNs struct in
1890 * alias->targetNs might come from an other
1891 * stylesheet tree. So we need to anchor it in the
1892 * current document, without adding it to the tree,
1893 * which would otherwise change the in-scope-ns
1894 * semantic of the tree.
1895 */
1896 ns = xsltTreeAcquireStoredNs(elem->doc,
1897 alias->targetNs->href,
1898 alias->targetNs->prefix);
1899
1900 if (ns == NULL) {
1901 xsltTransformError(NULL, cctxt->style, elem,
1902 "Internal error in "
1903 "xsltLREBuildEffectiveNs(): "
1904 "failed to acquire a stored "
1905 "ns-declaration.\n");
1906 cctxt->style->errors++;
1907 return(-1);
1908
1909 }
1910 }
1911 elem->ns = ns;
1912 }
1913 } else {
1914 /*
1915 * Move into or leave in the NULL namespace.
1916 */
1917 elem->ns = NULL;
1918 }
1919 break;
1920 }
1921 alias = alias->next;
1922 }
1923 /*
1924 * Same with attributes of literal result elements.
1925 */
1926 if (elem->properties != NULL) {
1927 xmlAttrPtr attr = elem->properties;
1928
1929 while (attr != NULL) {
1930 if (attr->ns == NULL) {
1931 attr = attr->next;
1932 continue;
1933 }
1934 alias = cctxt->nsAliases;
1935 while (alias != NULL) {
1936 if ( /* If both namespaces are NULL... */
1937 ( (elem->ns == NULL) &&
1938 ((alias->literalNs == NULL) ||
1939 (alias->literalNs->href == NULL)) ) ||
1940 /* ... or both namespace are equal */
1941 ( (elem->ns != NULL) &&
1942 (alias->literalNs != NULL) &&
1943 xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1944 {
1945 if ((alias->targetNs != NULL) &&
1946 (alias->targetNs->href != NULL))
1947 {
1948 if (elem->doc == alias->docOfTargetNs) {
1949 elem->ns = alias->targetNs;
1950 } else {
1951 ns = xmlSearchNs(elem->doc, elem,
1952 alias->targetNs->prefix);
1953 if ((ns == NULL) ||
1954 (! xmlStrEqual(ns->href, alias->targetNs->href)))
1955 {
1956 ns = xsltTreeAcquireStoredNs(elem->doc,
1957 alias->targetNs->href,
1958 alias->targetNs->prefix);
1959
1960 if (ns == NULL) {
1961 xsltTransformError(NULL, cctxt->style, elem,
1962 "Internal error in "
1963 "xsltLREBuildEffectiveNs(): "
1964 "failed to acquire a stored "
1965 "ns-declaration.\n");
1966 cctxt->style->errors++;
1967 return(-1);
1968
1969 }
1970 }
1971 elem->ns = ns;
1972 }
1973 } else {
1974 /*
1975 * Move into or leave in the NULL namespace.
1976 */
1977 elem->ns = NULL;
1978 }
1979 break;
1980 }
1981 alias = alias->next;
1982 }
1983
1984 attr = attr->next;
1985 }
1986 }
1987 return(0);
1988 }
1989
1990 /**
1991 * xsltLREBuildEffectiveNsNodes:
1992 *
1993 * Computes the effective namespaces nodes for a literal result
1994 * element.
1995 * @effectiveNs is the set of effective ns-nodes
1996 * on the literal result element, which will be added to the result
1997 * element if not already existing in the result tree.
1998 * This means that excluded namespaces (via exclude-result-prefixes,
1999 * extension-element-prefixes and the XSLT namespace) not added
2000 * to the set.
2001 * Namespace-aliasing was applied on the @effectiveNs.
2002 */
2003 static int
2004 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2005 xsltStyleItemLRElementInfoPtr item,
2006 xmlNodePtr elem,
2007 int isLRE)
2008 {
2009 xmlNsPtr ns, tmpns;
2010 xsltEffectiveNsPtr effNs, lastEffNs = NULL;
2011 int i, j, holdByElem;
2012 xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
2013 xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
2014
2015 if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
2016 (item == NULL) || (item->effectiveNs != NULL))
2017 return(-1);
2018
2019 if (item->inScopeNs == NULL)
2020 return(0);
2021
2022 extElemNs = cctxt->inode->extElemNs;
2023 exclResultNs = cctxt->inode->exclResultNs;
2024
2025 for (i = 0; i < item->inScopeNs->totalNumber; i++) {
2026 ns = item->inScopeNs->list[i];
2027 /*
2028 * Skip namespaces designated as excluded namespaces
2029 * -------------------------------------------------
2030 *
2031 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2032 * which are target namespaces of namespace-aliases
2033 * regardless if designated as excluded.
2034 *
2035 * Exclude the XSLT namespace.
2036 */
2037 if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2038 goto skip_ns;
2039
2040 /*
2041 * Apply namespace aliasing
2042 * ------------------------
2043 *
2044 * SPEC XSLT 2.0
2045 * "- A namespace node whose string value is a literal namespace
2046 * URI is not copied to the result tree.
2047 * - A namespace node whose string value is a target namespace URI
2048 * is copied to the result tree, whether or not the URI
2049 * identifies an excluded namespace."
2050 *
2051 * NOTE: The ns-aliasing machanism is non-cascading.
2052 * (checked with Saxon, Xalan and MSXML .NET).
2053 * URGENT TODO: is style->nsAliases the effective list of
2054 * ns-aliases, or do we need to lookup the whole
2055 * import-tree?
2056 * TODO: Get rid of import-tree lookup.
2057 */
2058 if (cctxt->hasNsAliases) {
2059 xsltNsAliasPtr alias;
2060 /*
2061 * First check for being a target namespace.
2062 */
2063 alias = cctxt->nsAliases;
2064 do {
2065 /*
2066 * TODO: Is xmlns="" handled already?
2067 */
2068 if ((alias->targetNs != NULL) &&
2069 (xmlStrEqual(alias->targetNs->href, ns->href)))
2070 {
2071 /*
2072 * Recognized as a target namespace; use it regardless
2073 * if excluded otherwise.
2074 */
2075 goto add_effective_ns;
2076 }
2077 alias = alias->next;
2078 } while (alias != NULL);
2079
2080 alias = cctxt->nsAliases;
2081 do {
2082 /*
2083 * TODO: Is xmlns="" handled already?
2084 */
2085 if ((alias->literalNs != NULL) &&
2086 (xmlStrEqual(alias->literalNs->href, ns->href)))
2087 {
2088 /*
2089 * Recognized as an namespace alias; do not use it.
2090 */
2091 goto skip_ns;
2092 }
2093 alias = alias->next;
2094 } while (alias != NULL);
2095 }
2096
2097 /*
2098 * Exclude excluded result namespaces.
2099 */
2100 if (exclResultNs) {
2101 for (j = 0; j < exclResultNs->number; j++)
2102 if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
2103 goto skip_ns;
2104 }
2105 /*
2106 * Exclude extension-element namespaces.
2107 */
2108 if (extElemNs) {
2109 for (j = 0; j < extElemNs->number; j++)
2110 if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
2111 goto skip_ns;
2112 }
2113
2114 add_effective_ns:
2115 /*
2116 * OPTIMIZE TODO: This information may not be needed.
2117 */
2118 if (isLRE && (elem->nsDef != NULL)) {
2119 holdByElem = 0;
2120 tmpns = elem->nsDef;
2121 do {
2122 if (tmpns == ns) {
2123 holdByElem = 1;
2124 break;
2125 }
2126 tmpns = tmpns->next;
2127 } while (tmpns != NULL);
2128 } else
2129 holdByElem = 0;
2130
2131
2132 /*
2133 * Add the effective namespace declaration.
2134 */
2135 effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
2136 if (effNs == NULL) {
2137 xsltTransformError(NULL, cctxt->style, elem,
2138 "Internal error in xsltLREBuildEffectiveNs(): "
2139 "failed to allocate memory.\n");
2140 cctxt->style->errors++;
2141 return(-1);
2142 }
2143 if (cctxt->psData->effectiveNs == NULL) {
2144 cctxt->psData->effectiveNs = effNs;
2145 effNs->nextInStore = NULL;
2146 } else {
2147 effNs->nextInStore = cctxt->psData->effectiveNs;
2148 cctxt->psData->effectiveNs = effNs;
2149 }
2150
2151 effNs->next = NULL;
2152 effNs->prefix = ns->prefix;
2153 effNs->nsName = ns->href;
2154 effNs->holdByElem = holdByElem;
2155
2156 if (lastEffNs == NULL)
2157 item->effectiveNs = effNs;
2158 else
2159 lastEffNs->next = effNs;
2160 lastEffNs = effNs;
2161
2162 skip_ns:
2163 {}
2164 }
2165 return(0);
2166 }
2167
2168
2169 /**
2170 * xsltLREInfoCreate:
2171 *
2172 * @isLRE: indicates if the given @elem is a literal result element
2173 *
2174 * Creates a new info for a literal result element.
2175 */
2176 static int
2177 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
2178 xmlNodePtr elem,
2179 int isLRE)
2180 {
2181 xsltStyleItemLRElementInfoPtr item;
2182
2183 if ((cctxt == NULL) || (cctxt->inode == NULL))
2184 return(-1);
2185
2186 item = (xsltStyleItemLRElementInfoPtr)
2187 xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
2188 if (item == NULL) {
2189 xsltTransformError(NULL, cctxt->style, NULL,
2190 "Internal error in xsltLREInfoCreate(): "
2191 "memory allocation failed.\n");
2192 cctxt->style->errors++;
2193 return(-1);
2194 }
2195 memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
2196 item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
2197 /*
2198 * Store it in the stylesheet.
2199 */
2200 item->next = cctxt->style->preComps;
2201 cctxt->style->preComps = (xsltElemPreCompPtr) item;
2202 /*
2203 * @inScopeNs are used for execution of XPath expressions
2204 * in AVTs.
2205 */
2206 item->inScopeNs = cctxt->inode->inScopeNs;
2207
2208 if (elem)
2209 xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
2210
2211 cctxt->inode->litResElemInfo = item;
2212 cctxt->inode->nsChanged = 0;
2213 cctxt->maxLREs++;
2214 return(0);
2215 }
2216
2217 /**
2218 * xsltCompilerVarInfoPush:
2219 * @cctxt: the compilation context
2220 *
2221 * Pushes a new var/param info onto the stack.
2222 *
2223 * Returns the acquired variable info.
2224 */
2225 static xsltVarInfoPtr
2226 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
2227 xmlNodePtr inst,
2228 const xmlChar *name,
2229 const xmlChar *nsName)
2230 {
2231 xsltVarInfoPtr ivar;
2232
2233 if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
2234 ivar = cctxt->ivar->next;
2235 } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
2236 ivar = cctxt->ivars;
2237 } else {
2238 ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
2239 if (ivar == NULL) {
2240 xsltTransformError(NULL, cctxt->style, inst,
2241 "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2242 cctxt->style->errors++;
2243 return(NULL);
2244 }
2245 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2246 if (cctxt->ivars == NULL) {
2247 cctxt->ivars = ivar;
2248 ivar->prev = NULL;
2249 } else {
2250 cctxt->ivar->next = ivar;
2251 ivar->prev = cctxt->ivar;
2252 }
2253 cctxt->ivar = ivar;
2254 ivar->next = NULL;
2255 }
2256 ivar->depth = cctxt->depth;
2257 ivar->name = name;
2258 ivar->nsName = nsName;
2259 return(ivar);
2260 }
2261
2262 /**
2263 * xsltCompilerVarInfoPop:
2264 * @cctxt: the compilation context
2265 *
2266 * Pops all var/param infos from the stack, which
2267 * have the current depth.
2268 */
2269 static void
2270 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
2271 {
2272
2273 while ((cctxt->ivar != NULL) &&
2274 (cctxt->ivar->depth > cctxt->depth))
2275 {
2276 cctxt->ivar = cctxt->ivar->prev;
2277 }
2278 }
2279
2280 /*
2281 * xsltCompilerNodePush:
2282 *
2283 * @cctxt: the compilation context
2284 * @node: the node to be pushed (this can also be the doc-node)
2285 *
2286 *
2287 *
2288 * Returns the current node info structure or
2289 * NULL in case of an internal error.
2290 */
2291 static xsltCompilerNodeInfoPtr
2292 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2293 {
2294 xsltCompilerNodeInfoPtr inode, iprev;
2295
2296 if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
2297 inode = cctxt->inode->next;
2298 } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
2299 inode = cctxt->inodeList;
2300 } else {
2301 /*
2302 * Create a new node-info.
2303 */
2304 inode = (xsltCompilerNodeInfoPtr)
2305 xmlMalloc(sizeof(xsltCompilerNodeInfo));
2306 if (inode == NULL) {
2307 xsltTransformError(NULL, cctxt->style, NULL,
2308 "xsltCompilerNodePush: malloc failed.\n");
2309 return(NULL);
2310 }
2311 memset(inode, 0, sizeof(xsltCompilerNodeInfo));
2312 if (cctxt->inodeList == NULL)
2313 cctxt->inodeList = inode;
2314 else {
2315 cctxt->inodeLast->next = inode;
2316 inode->prev = cctxt->inodeLast;
2317 }
2318 cctxt->inodeLast = inode;
2319 cctxt->maxNodeInfos++;
2320 if (cctxt->inode == NULL) {
2321 cctxt->inode = inode;
2322 /*
2323 * Create an initial literal result element info for
2324 * the root of the stylesheet.
2325 */
2326 xsltLREInfoCreate(cctxt, NULL, 0);
2327 }
2328 }
2329 cctxt->depth++;
2330 cctxt->inode = inode;
2331 /*
2332 * REVISIT TODO: Keep the reset always complete.
2333 * NOTE: Be carefull with the @node, since it might be
2334 * a doc-node.
2335 */
2336 inode->node = node;
2337 inode->depth = cctxt->depth;
2338 inode->templ = NULL;
2339 inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
2340 inode->type = 0;
2341 inode->item = NULL;
2342 inode->curChildType = 0;
2343 inode->extContentHandled = 0;
2344 inode->isRoot = 0;
2345
2346 if (inode->prev != NULL) {
2347 iprev = inode->prev;
2348 /*
2349 * Inherit the following information:
2350 * ---------------------------------
2351 *
2352 * In-scope namespaces
2353 */
2354 inode->inScopeNs = iprev->inScopeNs;
2355 /*
2356 * Info for literal result elements
2357 */
2358 inode->litResElemInfo = iprev->litResElemInfo;
2359 inode->nsChanged = iprev->nsChanged;
2360 /*
2361 * Excluded result namespaces
2362 */
2363 inode->exclResultNs = iprev->exclResultNs;
2364 /*
2365 * Extension instruction namespaces
2366 */
2367 inode->extElemNs = iprev->extElemNs;
2368 /*
2369 * Whitespace preservation
2370 */
2371 inode->preserveWhitespace = iprev->preserveWhitespace;
2372 /*
2373 * Forwards-compatible mode
2374 */
2375 inode->forwardsCompat = iprev->forwardsCompat;
2376 } else {
2377 inode->inScopeNs = NULL;
2378 inode->exclResultNs = NULL;
2379 inode->extElemNs = NULL;
2380 inode->preserveWhitespace = 0;
2381 inode->forwardsCompat = 0;
2382 }
2383
2384 return(inode);
2385 }
2386
2387 /*
2388 * xsltCompilerNodePop:
2389 *
2390 * @cctxt: the compilation context
2391 * @node: the node to be pushed (this can also be the doc-node)
2392 *
2393 * Pops the current node info.
2394 */
2395 static void
2396 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2397 {
2398 if (cctxt->inode == NULL) {
2399 xmlGenericError(xmlGenericErrorContext,
2400 "xsltCompilerNodePop: Top-node mismatch.\n");
2401 return;
2402 }
2403 /*
2404 * NOTE: Be carefull with the @node, since it might be
2405 * a doc-node.
2406 */
2407 if (cctxt->inode->node != node) {
2408 xmlGenericError(xmlGenericErrorContext,
2409 "xsltCompilerNodePop: Node mismatch.\n");
2410 goto mismatch;
2411 }
2412 if (cctxt->inode->depth != cctxt->depth) {
2413 xmlGenericError(xmlGenericErrorContext,
2414 "xsltCompilerNodePop: Depth mismatch.\n");
2415 goto mismatch;
2416 }
2417 cctxt->depth--;
2418 /*
2419 * Pop information of variables.
2420 */
2421 if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
2422 xsltCompilerVarInfoPop(cctxt);
2423
2424 cctxt->inode = cctxt->inode->prev;
2425 if (cctxt->inode != NULL)
2426 cctxt->inode->curChildType = 0;
2427 return;
2428
2429 mismatch:
2430 {
2431 const xmlChar *nsName = NULL, *name = NULL;
2432 const xmlChar *infnsName = NULL, *infname = NULL;
2433
2434 if (node) {
2435 if (node->type == XML_ELEMENT_NODE) {
2436 name = node->name;
2437 if (node->ns != NULL)
2438 nsName = node->ns->href;
2439 else
2440 nsName = BAD_CAST "";
2441 } else {
2442 name = BAD_CAST "#document";
2443 nsName = BAD_CAST "";
2444 }
2445 } else
2446 name = BAD_CAST "Not given";
2447
2448 if (cctxt->inode->node) {
2449 if (node->type == XML_ELEMENT_NODE) {
2450 infname = cctxt->inode->node->name;
2451 if (cctxt->inode->node->ns != NULL)
2452 infnsName = cctxt->inode->node->ns->href;
2453 else
2454 infnsName = BAD_CAST "";
2455 } else {
2456 infname = BAD_CAST "#document";
2457 infnsName = BAD_CAST "";
2458 }
2459 } else
2460 infname = BAD_CAST "Not given";
2461
2462
2463 xmlGenericError(xmlGenericErrorContext,
2464 "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2465 name, nsName);
2466 xmlGenericError(xmlGenericErrorContext,
2467 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2468 infname, infnsName);
2469 }
2470 }
2471
2472 /*
2473 * xsltCompilerBuildInScopeNsList:
2474 *
2475 * Create and store the list of in-scope namespaces for the given
2476 * node in the stylesheet. If there are no changes in the in-scope
2477 * namespaces then the last ns-info of the ancestor axis will be returned.
2478 * Compilation-time only.
2479 *
2480 * Returns the ns-info or NULL if there are no namespaces in scope.
2481 */
2482 static xsltNsListContainerPtr
2483 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2484 {
2485 xsltNsListContainerPtr nsi = NULL;
2486 xmlNsPtr *list = NULL, ns;
2487 int i, maxns = 5;
2488 /*
2489 * Create a new ns-list for this position in the node-tree.
2490 * xmlGetNsList() will return NULL, if there are no ns-decls in the
2491 * tree. Note that the ns-decl for the XML namespace is not added
2492 * to the resulting list; the XPath module handles the XML namespace
2493 * internally.
2494 */
2495 while (node != NULL) {
2496 if (node->type == XML_ELEMENT_NODE) {
2497 ns = node->nsDef;
2498 while (ns != NULL) {
2499 if (nsi == NULL) {
2500 nsi = (xsltNsListContainerPtr)
2501 xmlMalloc(sizeof(xsltNsListContainer));
2502 if (nsi == NULL) {
2503 xsltTransformError(NULL, cctxt->style, NULL,
2504 "xsltCompilerBuildInScopeNsList: "
2505 "malloc failed!\n");
2506 goto internal_err;
2507 }
2508 memset(nsi, 0, sizeof(xsltNsListContainer));
2509 nsi->list =
2510 (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
2511 if (nsi->list == NULL) {
2512 xsltTransformError(NULL, cctxt->style, NULL,
2513 "xsltCompilerBuildInScopeNsList: "
2514 "malloc failed!\n");
2515 goto internal_err;
2516 }
2517 nsi->list[0] = NULL;
2518 }
2519 /*
2520 * Skip shadowed namespace bindings.
2521 */
2522 for (i = 0; i < nsi->totalNumber; i++) {
2523 if ((ns->prefix == nsi->list[i]->prefix) ||
2524 (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
2525 break;
2526 }
2527 if (i >= nsi->totalNumber) {
2528 if (nsi->totalNumber +1 >= maxns) {
2529 maxns *= 2;
2530 nsi->list =
2531 (xmlNsPtr *) xmlRealloc(nsi->list,
2532 maxns * sizeof(xmlNsPtr));
2533 if (nsi->list == NULL) {
2534 xsltTransformError(NULL, cctxt->style, NULL,
2535 "xsltCompilerBuildInScopeNsList: "
2536 "realloc failed!\n");
2537 goto internal_err;
2538 }
2539 }
2540 nsi->list[nsi->totalNumber++] = ns;
2541 nsi->list[nsi->totalNumber] = NULL;
2542 }
2543
2544 ns = ns->next;
2545 }
2546 }
2547 node = node->parent;
2548 }
2549 if (nsi == NULL)
2550 return(NULL);
2551 /*
2552 * Move the default namespace to last position.
2553 */
2554 nsi->xpathNumber = nsi->totalNumber;
2555 for (i = 0; i < nsi->totalNumber; i++) {
2556 if (nsi->list[i]->prefix == NULL) {
2557 ns = nsi->list[i];
2558 nsi->list[i] = nsi->list[nsi->totalNumber-1];
2559 nsi->list[nsi->totalNumber-1] = ns;
2560 nsi->xpathNumber--;
2561 break;
2562 }
2563 }
2564 /*
2565 * Store the ns-list in the stylesheet.
2566 */
2567 if (xsltPointerListAddSize(
2568 (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
2569 (void *) nsi, 5) == -1)
2570 {
2571 xmlFree(nsi);
2572 nsi = NULL;
2573 xsltTransformError(NULL, cctxt->style, NULL,
2574 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2575 goto internal_err;
2576 }
2577 /*
2578 * Notify of change in status wrt namespaces.
2579 */
2580 if (cctxt->inode != NULL)
2581 cctxt->inode->nsChanged = 1;
2582
2583 return(nsi);
2584
2585 internal_err:
2586 if (list != NULL)
2587 xmlFree(list);
2588 cctxt->style->errors++;
2589 return(NULL);
2590 }
2591
2592 static int
2593 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2594 xsltPointerListPtr list,
2595 xmlNodePtr node,
2596 const xmlChar *value)
2597 {
2598 xmlChar *cur, *end;
2599 xmlNsPtr ns;
2600
2601 if ((cctxt == NULL) || (value == NULL) || (list == NULL))
2602 return(-1);
2603
2604 list->number = 0;
2605
2606 cur = (xmlChar *) value;
2607 while (*cur != 0) {
2608 while (IS_BLANK(*cur)) cur++;
2609 if (*cur == 0)
2610 break;
2611 end = cur;
2612 while ((*end != 0) && (!IS_BLANK(*end))) end++;
2613 cur = xmlStrndup(cur, end - cur);
2614 if (cur == NULL) {
2615 cur = end;
2616 continue;
2617 }
2618 /*
2619 * TODO: Export and use xmlSearchNsByPrefixStrict()
2620 * in Libxml2, tree.c, since xmlSearchNs() is in most
2621 * cases not efficient and in some cases not correct.
2622 *
2623 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2624 */
2625 if ((cur[0] == '#') &&
2626 xmlStrEqual(cur, (const xmlChar *)"#default"))
2627 ns = xmlSearchNs(cctxt->style->doc, node, NULL);
2628 else
2629 ns = xmlSearchNs(cctxt->style->doc, node, cur);
2630
2631 if (ns == NULL) {
2632 /*
2633 * TODO: Better to report the attr-node, otherwise
2634 * the user won't know which attribute was invalid.
2635 */
2636 xsltTransformError(NULL, cctxt->style, node,
2637 "No namespace binding in scope for prefix '%s'.\n", cur);
2638 /*
2639 * XSLT-1.0: "It is an error if there is no namespace
2640 * bound to the prefix on the element bearing the
2641 * exclude-result-prefixes or xsl:exclude-result-prefixes
2642 * attribute."
2643 */
2644 cctxt->style->errors++;
2645 } else {
2646 #ifdef WITH_XSLT_DEBUG_PARSING
2647 xsltGenericDebug(xsltGenericDebugContext,
2648 "resolved prefix '%s'\n", cur);
2649 #endif
2650 /*
2651 * Note that we put the namespace name into the dict.
2652 */
2653 if (xsltPointerListAddSize(list,
2654 (void *) xmlDictLookup(cctxt->style->dict,
2655 ns->href, -1), 5) == -1)
2656 {
2657 xmlFree(cur);
2658 goto internal_err;
2659 }
2660 }
2661 xmlFree(cur);
2662
2663 cur = end;
2664 }
2665 return(0);
2666
2667 internal_err:
2668 cctxt->style->errors++;
2669 return(-1);
2670 }
2671
2672 /**
2673 * xsltCompilerUtilsCreateMergedList:
2674 * @dest: the destination list (optional)
2675 * @first: the first list
2676 * @second: the second list (optional)
2677 *
2678 * Appends the content of @second to @first into @destination.
2679 * If @destination is NULL a new list will be created.
2680 *
2681 * Returns the merged list of items or NULL if there's nothing to merge.
2682 */
2683 static xsltPointerListPtr
2684 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
2685 xsltPointerListPtr second)
2686 {
2687 xsltPointerListPtr ret;
2688 size_t num;
2689
2690 if (first)
2691 num = first->number;
2692 else
2693 num = 0;
2694 if (second)
2695 num += second->number;
2696 if (num == 0)
2697 return(NULL);
2698 ret = xsltPointerListCreate(num);
2699 if (ret == NULL)
2700 return(NULL);
2701 /*
2702 * Copy contents.
2703 */
2704 if ((first != NULL) && (first->number != 0)) {
2705 memcpy(ret->items, first->items,
2706 first->number * sizeof(void *));
2707 if ((second != NULL) && (second->number != 0))
2708 memcpy(ret->items + first->number, second->items,
2709 second->number * sizeof(void *));
2710 } else if ((second != NULL) && (second->number != 0))
2711 memcpy(ret->items, (void *) second->items,
2712 second->number * sizeof(void *));
2713 ret->number = num;
2714 return(ret);
2715 }
2716
2717 /*
2718 * xsltParseExclResultPrefixes:
2719 *
2720 * Create and store the list of in-scope namespaces for the given
2721 * node in the stylesheet. If there are no changes in the in-scope
2722 * namespaces then the last ns-info of the ancestor axis will be returned.
2723 * Compilation-time only.
2724 *
2725 * Returns the ns-info or NULL if there are no namespaces in scope.
2726 */
2727 static xsltPointerListPtr
2728 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2729 xsltPointerListPtr def,
2730 int instrCategory)
2731 {
2732 xsltPointerListPtr list = NULL;
2733 xmlChar *value;
2734 xmlAttrPtr attr;
2735
2736 if ((cctxt == NULL) || (node == NULL))
2737 return(NULL);
2738
2739 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2740 attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
2741 else
2742 attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
2743 XSLT_NAMESPACE);
2744 if (attr == NULL)
2745 return(def);
2746
2747 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2748 /*
2749 * Mark the XSLT attr.
2750 */
2751 attr->psvi = (void *) xsltXSLTAttrMarker;
2752 }
2753
2754 if ((attr->children != NULL) &&
2755 (attr->children->content != NULL))
2756 value = attr->children->content;
2757 else {
2758 xsltTransformError(NULL, cctxt->style, node,
2759 "Attribute 'exclude-result-prefixes': Invalid value.\n");
2760 cctxt->style->errors++;
2761 return(def);
2762 }
2763
2764 if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2765 BAD_CAST value) != 0)
2766 goto exit;
2767 if (cctxt->tmpList->number == 0)
2768 goto exit;
2769 /*
2770 * Merge the list with the inherited list.
2771 */
2772 list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2773 if (list == NULL)
2774 goto exit;
2775 /*
2776 * Store the list in the stylesheet/compiler context.
2777 */
2778 if (xsltPointerListAddSize(
2779 cctxt->psData->exclResultNamespaces, list, 5) == -1)
2780 {
2781 xsltPointerListFree(list);
2782 list = NULL;
2783 goto exit;
2784 }
2785 /*
2786 * Notify of change in status wrt namespaces.
2787 */
2788 if (cctxt->inode != NULL)
2789 cctxt->inode->nsChanged = 1;
2790
2791 exit:
2792 if (list != NULL)
2793 return(list);
2794 else
2795 return(def);
2796 }
2797
2798 /*
2799 * xsltParseExtElemPrefixes:
2800 *
2801 * Create and store the list of in-scope namespaces for the given
2802 * node in the stylesheet. If there are no changes in the in-scope
2803 * namespaces then the last ns-info of the ancestor axis will be returned.
2804 * Compilation-time only.
2805 *
2806 * Returns the ns-info or NULL if there are no namespaces in scope.
2807 */
2808 static xsltPointerListPtr
2809 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2810 xsltPointerListPtr def,
2811 int instrCategory)
2812 {
2813 xsltPointerListPtr list = NULL;
2814 xmlAttrPtr attr;
2815 xmlChar *value;
2816 int i;
2817
2818 if ((cctxt == NULL) || (node == NULL))
2819 return(NULL);
2820
2821 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2822 attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
2823 else
2824 attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
2825 XSLT_NAMESPACE);
2826 if (attr == NULL)
2827 return(def);
2828
2829 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2830 /*
2831 * Mark the XSLT attr.
2832 */
2833 attr->psvi = (void *) xsltXSLTAttrMarker;
2834 }
2835
2836 if ((attr->children != NULL) &&
2837 (attr->children->content != NULL))
2838 value = attr->children->content;
2839 else {
2840 xsltTransformError(NULL, cctxt->style, node,
2841 "Attribute 'extension-element-prefixes': Invalid value.\n");
2842 cctxt->style->errors++;
2843 return(def);
2844 }
2845
2846
2847 if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2848 BAD_CAST value) != 0)
2849 goto exit;
2850
2851 if (cctxt->tmpList->number == 0)
2852 goto exit;
2853 /*
2854 * REVISIT: Register the extension namespaces.
2855 */
2856 for (i = 0; i < cctxt->tmpList->number; i++)
2857 xsltRegisterExtPrefix(cctxt->style, NULL,
2858 BAD_CAST cctxt->tmpList->items[i]);
2859 /*
2860 * Merge the list with the inherited list.
2861 */
2862 list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2863 if (list == NULL)
2864 goto exit;
2865 /*
2866 * Store the list in the stylesheet.
2867 */
2868 if (xsltPointerListAddSize(
2869 cctxt->psData->extElemNamespaces, list, 5) == -1)
2870 {
2871 xsltPointerListFree(list);
2872 list = NULL;
2873 goto exit;
2874 }
2875 /*
2876 * Notify of change in status wrt namespaces.
2877 */
2878 if (cctxt->inode != NULL)
2879 cctxt->inode->nsChanged = 1;
2880
2881 exit:
2882 if (list != NULL)
2883 return(list);
2884 else
2885 return(def);
2886 }
2887
2888 /*
2889 * xsltParseAttrXSLTVersion:
2890 *
2891 * @cctxt: the compilation context
2892 * @node: the element-node
2893 * @isXsltElem: whether this is an XSLT element
2894 *
2895 * Parses the attribute xsl:version.
2896 *
2897 * Returns 1 if there was such an attribute, 0 if not and
2898 * -1 if an internal or API error occured.
2899 */
2900 static int
2901 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2902 int instrCategory)
2903 {
2904 xmlChar *value;
2905 xmlAttrPtr attr;
2906
2907 if ((cctxt == NULL) || (node == NULL))
2908 return(-1);
2909
2910 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2911 attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
2912 else
2913 attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
2914
2915 if (attr == NULL)
2916 return(0);
2917
2918 attr->psvi = (void *) xsltXSLTAttrMarker;
2919
2920 if ((attr->children != NULL) &&
2921 (attr->children->content != NULL))
2922 value = attr->children->content;
2923 else {
2924 xsltTransformError(NULL, cctxt->style, node,
2925 "Attribute 'version': Invalid value.\n");
2926 cctxt->style->errors++;
2927 return(1);
2928 }
2929
2930 if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
2931 cctxt->inode->forwardsCompat = 1;
2932 /*
2933 * TODO: To what extent do we support the
2934 * forwards-compatible mode?
2935 */
2936 /*
2937 * Report this only once per compilation episode.
2938 */
2939 if (! cctxt->hasForwardsCompat) {
2940 cctxt->hasForwardsCompat = 1;
2941 cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
2942 xsltTransformError(NULL, cctxt->style, node,
2943 "Warning: the attribute xsl:version specifies a value "
2944 "different from '1.0'. Switching to forwards-compatible "
2945 "mode. Only features of XSLT 1.0 are supported by this "
2946 "processor.\n");
2947 cctxt->style->warnings++;
2948 cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
2949 }
2950 } else {
2951 cctxt->inode->forwardsCompat = 0;
2952 }
2953
2954 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2955 /*
2956 * Set a marker on XSLT attributes.
2957 */
2958 attr->psvi = (void *) xsltXSLTAttrMarker;
2959 }
2960 return(1);
2961 }
2962
2963 static int
2964 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2965 {
2966 xmlNodePtr deleteNode, cur, txt, textNode = NULL;
2967 xmlDocPtr doc;
2968 xsltStylesheetPtr style;
2969 int internalize = 0, findSpaceAttr;
2970 int xsltStylesheetElemDepth;
2971 xmlAttrPtr attr;
2972 xmlChar *value;
2973 const xmlChar *name, *nsNameXSLT = NULL;
2974 int strictWhitespace, inXSLText = 0;
2975 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
2976 xsltNsMapPtr nsMapItem;
2977 #endif
2978
2979 if ((cctxt == NULL) || (cctxt->style == NULL) ||
2980 (node == NULL) || (node->type != XML_ELEMENT_NODE))
2981 return(-1);
2982
2983 doc = node->doc;
2984 if (doc == NULL)
2985 goto internal_err;
2986
2987 style = cctxt->style;
2988 if ((style->dict != NULL) && (doc->dict == style->dict))
2989 internalize = 1;
2990 else
2991 style->internalized = 0;
2992
2993 /*
2994 * Init value of xml:space. Since this might be an embedded
2995 * stylesheet, this is needed to be performed on the element
2996 * where the stylesheet is rooted at, taking xml:space of
2997 * ancestors into account.
2998 */
2999 if (! cctxt->simplified)
3000 xsltStylesheetElemDepth = cctxt->depth +1;
3001 else
3002 xsltStylesheetElemDepth = 0;
3003
3004 if (xmlNodeGetSpacePreserve(node) != 1)
3005 cctxt->inode->preserveWhitespace = 0;
3006 else
3007 cctxt->inode->preserveWhitespace = 1;
3008
3009 /*
3010 * Eval if we should keep the old incorrect behaviour.
3011 */
3012 strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
3013
3014 nsNameXSLT = xsltConstNamespaceNameXSLT;
3015
3016 deleteNode = NULL;
3017 cur = node;
3018 while (cur != NULL) {
3019 if (deleteNode != NULL) {
3020
3021 #ifdef WITH_XSLT_DEBUG_BLANKS
3022 xsltGenericDebug(xsltGenericDebugContext,
3023 "xsltParsePreprocessStylesheetTree: removing node\n");
3024 #endif
3025 xmlUnlinkNode(deleteNode);
3026 xmlFreeNode(deleteNode);
3027 deleteNode = NULL;
3028 }
3029 if (cur->type == XML_ELEMENT_NODE) {
3030
3031 /*
3032 * Clear the PSVI field.
3033 */
3034 cur->psvi = NULL;
3035
3036 xsltCompilerNodePush(cctxt, cur);
3037
3038 inXSLText = 0;
3039 textNode = NULL;
3040 findSpaceAttr = 1;
3041 cctxt->inode->stripWhitespace = 0;
3042 /*
3043 * TODO: I'd love to use a string pointer comparison here :-/
3044 */
3045 if (IS_XSLT_ELEM(cur)) {
3046 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3047 if (cur->ns->href != nsNameXSLT) {
3048 nsMapItem = xsltNewNamespaceMapItem(cctxt,
3049 doc, cur->ns, cur);
3050 if (nsMapItem == NULL)
3051 goto internal_err;
3052 cur->ns->href = nsNameXSLT;
3053 }
3054 #endif
3055
3056 if (cur->name == NULL)
3057 goto process_attributes;
3058 /*
3059 * Mark the XSLT element for later recognition.
3060 * TODO: Using the marker is still too dangerous, since if
3061 * the parsing mechanism leaves out an XSLT element, then
3062 * this might hit the transformation-mechanism, which
3063 * will break if it doesn't expect such a marker.
3064 */
3065 /* cur->psvi = (void *) xsltXSLTElemMarker; */
3066
3067 /*
3068 * XSLT 2.0: "Any whitespace text node whose parent is
3069 * one of the following elements is removed from the "
3070 * tree, regardless of any xml:space attributes:..."
3071 * xsl:apply-imports,
3072 * xsl:apply-templates,
3073 * xsl:attribute-set,
3074 * xsl:call-template,
3075 * xsl:choose,
3076 * xsl:stylesheet, xsl:transform.
3077 * XSLT 2.0: xsl:analyze-string,
3078 * xsl:character-map,
3079 * xsl:next-match
3080 *
3081 * TODO: I'd love to use a string pointer comparison here :-/
3082 */
3083 name = cur->name;
3084 switch (*name) {
3085 case 't':
3086 if ((name[0] == 't') && (name[1] == 'e') &&
3087 (name[2] == 'x') && (name[3] == 't') &&
3088 (name[4] == 0))
3089 {
3090 /*
3091 * Process the xsl:text element.
3092 * ----------------------------
3093 * Mark it for later recognition.
3094 */
3095 cur->psvi = (void *) xsltXSLTTextMarker;
3096 /*
3097 * For stylesheets, the set of
3098 * whitespace-preserving element names
3099 * consists of just xsl:text.
3100 */
3101 findSpaceAttr = 0;
3102 cctxt->inode->preserveWhitespace = 1;
3103 inXSLText = 1;
3104 }
3105 break;
3106 case 'c':
3107 if (xmlStrEqual(name, BAD_CAST "choose") ||
3108 xmlStrEqual(name, BAD_CAST "call-template"))
3109 cctxt->inode->stripWhitespace = 1;
3110 break;
3111 case 'a':
3112 if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
3113 xmlStrEqual(name, BAD_CAST "apply-imports") ||
3114 xmlStrEqual(name, BAD_CAST "attribute-set"))
3115
3116 cctxt->inode->stripWhitespace = 1;
3117 break;
3118 default:
3119 if (xsltStylesheetElemDepth == cctxt->depth) {
3120 /*
3121 * This is a xsl:stylesheet/xsl:transform.
3122 */
3123 cctxt->inode->stripWhitespace = 1;
3124 break;
3125 }
3126
3127 if ((cur->prev != NULL) &&
3128 (cur->prev->type == XML_TEXT_NODE))
3129 {
3130 /*
3131 * XSLT 2.0 : "Any whitespace text node whose
3132 * following-sibling node is an xsl:param or
3133 * xsl:sort element is removed from the tree,
3134 * regardless of any xml:space attributes."
3135 */
3136 if (((*name == 'p') || (*name == 's')) &&
3137 (xmlStrEqual(name, BAD_CAST "param") ||
3138 xmlStrEqual(name, BAD_CAST "sort")))
3139 {
3140 do {
3141 if (IS_BLANK_NODE(cur->prev)) {
3142 txt = cur->prev;
3143 xmlUnlinkNode(txt);
3144 xmlFreeNode(txt);
3145 } else {
3146 /*
3147 * This will result in a content
3148 * error, when hitting the parsing
3149 * functions.
3150 */
3151 break;
3152 }
3153 } while (cur->prev);
3154 }
3155 }
3156 break;
3157 }
3158 }
3159
3160 process_attributes:
3161 /*
3162 * Process attributes.
3163 * ------------------
3164 */
3165 if (cur->properties != NULL) {
3166 if (cur->children == NULL)
3167 findSpaceAttr = 0;
3168 attr = cur->properties;
3169 do {
3170 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3171 if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
3172 xmlStrEqual(attr->ns->href, nsNameXSLT))
3173 {
3174 nsMapItem = xsltNewNamespaceMapItem(cctxt,
3175 doc, attr->ns, cur);
3176 if (nsMapItem == NULL)
3177 goto internal_err;
3178 attr->ns->href = nsNameXSLT;
3179 }
3180 #endif
3181 if (internalize) {
3182 /*
3183 * Internalize the attribute's value; the goal is to
3184 * speed up operations and minimize used space by
3185 * compiled stylesheets.
3186 */
3187 txt = attr->children;
3188 /*
3189 * NOTE that this assumes only one
3190 * text-node in the attribute's content.
3191 */
3192 if ((txt != NULL) && (txt->content != NULL) &&
3193 (!xmlDictOwns(style->dict, txt->content)))
3194 {
3195 value = (xmlChar *) xmlDictLookup(style->dict,
3196 txt->content, -1);
3197 xmlNodeSetContent(txt, NULL);
3198 txt->content = value;
3199 }
3200 }
3201 /*
3202 * Process xml:space attributes.
3203 * ----------------------------
3204 */
3205 if ((findSpaceAttr != 0) &&
3206 (attr->ns != NULL) &&
3207 (attr->name != NULL) &&
3208 (attr->name[0] == 's') &&
3209 (attr->ns->prefix != NULL) &&
3210 (attr->ns->prefix[0] == 'x') &&
3211 (attr->ns->prefix[1] == 'm') &&
3212 (attr->ns->prefix[2] == 'l') &&
3213 (attr->ns->prefix[3] == 0))
3214 {
3215 value = xmlGetNsProp(cur, BAD_CAST "space",
3216 XML_XML_NAMESPACE);
3217 if (value != NULL) {
3218 if (xmlStrEqual(value, BAD_CAST "preserve")) {
3219 cctxt->inode->preserveWhitespace = 1;
3220 } else if (xmlStrEqual(value, BAD_CAST "default")) {
3221 cctxt->inode->preserveWhitespace = 0;
3222 } else {
3223 /* Invalid value for xml:space. */
3224 xsltTransformError(NULL, style, cur,
3225 "Attribute xml:space: Invalid value.\n");
3226 cctxt->style->warnings++;
3227 }
3228 findSpaceAttr = 0;
3229 xmlFree(value);
3230 }
3231
3232 }
3233 attr = attr->next;
3234 } while (attr != NULL);
3235 }
3236 /*
3237 * We'll descend into the children of element nodes only.
3238 */
3239 if (cur->children != NULL) {
3240 cur = cur->children;
3241 continue;
3242 }
3243 } else if ((cur->type == XML_TEXT_NODE) ||
3244 (cur->type == XML_CDATA_SECTION_NODE))
3245 {
3246 /*
3247 * Merge adjacent text/CDATA-section-nodes
3248 * ---------------------------------------
3249 * In order to avoid breaking of existing stylesheets,
3250 * if the old behaviour is wanted (strictWhitespace == 0),
3251 * then we *won't* merge adjacent text-nodes
3252 * (except in xsl:text); this will ensure that whitespace-only
3253 * text nodes are (incorrectly) not stripped in some cases.
3254 *
3255 * Example: : <foo> <!-- bar -->zoo</foo>
3256 * Corrent (strict) result: <foo> zoo</foo>
3257 * Incorrect (old) result : <foo>zoo</foo>
3258 *
3259 * NOTE that we *will* merge adjacent text-nodes if
3260 * they are in xsl:text.
3261 * Example, the following:
3262 * <xsl:text> <!-- bar -->zoo<xsl:text>
3263 * will result in both cases in:
3264 * <xsl:text> zoo<xsl:text>
3265 */
3266 cur->type = XML_TEXT_NODE;
3267 if ((strictWhitespace != 0) || (inXSLText != 0)) {
3268 /*
3269 * New behaviour; merge nodes.
3270 */
3271 if (textNode == NULL)
3272 textNode = cur;
3273 else {
3274 if (cur->content != NULL)
3275 xmlNodeAddContent(textNode, cur->content);
3276 deleteNode = cur;
3277 }
3278 if ((cur->next == NULL) ||
3279 (cur->next->type == XML_ELEMENT_NODE))
3280 goto end_of_text;
3281 else
3282 goto next_sibling;
3283 } else {
3284 /*
3285 * Old behaviour.
3286 */
3287 if (textNode == NULL)
3288 textNode = cur;
3289 goto end_of_text;
3290 }
3291 } else if ((cur->type == XML_COMMENT_NODE) ||
3292 (cur->type == XML_PI_NODE))
3293 {
3294 /*
3295 * Remove processing instructions and comments.
3296 */
3297 deleteNode = cur;
3298 if ((cur->next == NULL) ||
3299 (cur->next->type == XML_ELEMENT_NODE))
3300 goto end_of_text;
3301 else
3302 goto next_sibling;
3303 } else {
3304 textNode = NULL;
3305 /*
3306 * Invalid node-type for this data-model.
3307 */
3308 xsltTransformError(NULL, style, cur,
3309 "Invalid type of node for the XSLT data model.\n");
3310 cctxt->style->errors++;
3311 goto next_sibling;
3312 }
3313
3314 end_of_text:
3315 if (textNode) {
3316 value = textNode->content;
3317 /*
3318 * At this point all adjacent text/CDATA-section nodes
3319 * have been merged.
3320 *
3321 * Strip whitespace-only text-nodes.
3322 * (cctxt->inode->stripWhitespace)
3323 */
3324 if ((value == NULL) || (*value == 0) ||
3325 (((cctxt->inode->stripWhitespace) ||
3326 (! cctxt->inode->preserveWhitespace)) &&
3327 IS_BLANK(*value) &&
3328 xsltIsBlank(value)))
3329 {
3330 if (textNode != cur) {
3331 xmlUnlinkNode(textNode);
3332 xmlFreeNode(textNode);
3333 } else
3334 deleteNode = textNode;
3335 textNode = NULL;
3336 goto next_sibling;
3337 }
3338 /*
3339 * Convert CDATA-section nodes to text-nodes.
3340 * TODO: Can this produce problems?
3341 */
3342 if (textNode->type != XML_TEXT_NODE) {
3343 textNode->type = XML_TEXT_NODE;
3344 textNode->name = xmlStringText;
3345 }
3346 if (internalize &&
3347 (textNode->content != NULL) &&
3348 (!xmlDictOwns(style->dict, textNode->content)))
3349 {
3350 /*
3351 * Internalize the string.
3352 */
3353 value = (xmlChar *) xmlDictLookup(style->dict,
3354 textNode->content, -1);
3355 xmlNodeSetContent(textNode, NULL);
3356 textNode->content = value;
3357 }
3358 textNode = NULL;
3359 /*
3360 * Note that "disable-output-escaping" of the xsl:text
3361 * element will be applied at a later level, when
3362 * XSLT elements are processed.
3363 */
3364 }
3365
3366 next_sibling:
3367 if (cur->type == XML_ELEMENT_NODE) {
3368 xsltCompilerNodePop(cctxt, cur);
3369 }
3370 if (cur == node)
3371 break;
3372 if (cur->next != NULL) {
3373 cur = cur->next;
3374 } else {
3375 cur = cur->parent;
3376 inXSLText = 0;
3377 goto next_sibling;
3378 };
3379 }
3380 if (deleteNode != NULL) {
3381 #ifdef WITH_XSLT_DEBUG_PARSING
3382 xsltGenericDebug(xsltGenericDebugContext,
3383 "xsltParsePreprocessStylesheetTree: removing node\n");
3384 #endif
3385 xmlUnlinkNode(deleteNode);
3386 xmlFreeNode(deleteNode);
3387 }
3388 return(0);
3389
3390 internal_err:
3391 return(-1);
3392 }
3393
3394 #endif /* XSLT_REFACTORED */
3395
3396 #ifdef XSLT_REFACTORED
3397 #else
3398 static void
3399 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
3400 {
3401 xmlNodePtr deleteNode, styleelem;
3402 int internalize = 0;
3403
3404 if ((style == NULL) || (cur == NULL))
3405 return;
3406
3407 if ((cur->doc != NULL) && (style->dict != NULL) &&
3408 (cur->doc->dict == style->dict))
3409 internalize = 1;
3410 else
3411 style->internalized = 0;
3412
3413 if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3414 (IS_XSLT_NAME(cur, "stylesheet"))) {
3415 styleelem = cur;
3416 } else {
3417 styleelem = NULL;
3418 }
3419
3420 /*
3421 * This content comes from the stylesheet
3422 * For stylesheets, the set of whitespace-preserving
3423 * element names consists of just xsl:text.
3424 */
3425 deleteNode = NULL;
3426 while (cur != NULL) {
3427 if (deleteNode != NULL) {
3428 #ifdef WITH_XSLT_DEBUG_BLANKS
3429 xsltGenericDebug(xsltGenericDebugContext,
3430 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3431 #endif
3432 xmlUnlinkNode(deleteNode);
3433 xmlFreeNode(deleteNode);
3434 deleteNode = NULL;
3435 }
3436 if (cur->type == XML_ELEMENT_NODE) {
3437 int exclPrefixes;
3438 /*
3439 * Internalize attributes values.
3440 */
3441 if ((internalize) && (cur->properties != NULL)) {
3442 xmlAttrPtr attr = cur->properties;
3443 xmlNodePtr txt;
3444
3445 while (attr != NULL) {
3446 txt = attr->children;
3447 if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3448 (txt->content != NULL) &&
3449 (!xmlDictOwns(style->dict, txt->content)))
3450 {
3451 xmlChar *tmp;
3452
3453 /*
3454 * internalize the text string, goal is to speed
3455 * up operations and minimize used space by compiled
3456 * stylesheets.
3457 */
3458 tmp = (xmlChar *) xmlDictLookup(style->dict,
3459 txt->content, -1);
3460 if (tmp != txt->content) {
3461 xmlNodeSetContent(txt, NULL);
3462 txt->content = tmp;
3463 }
3464 }
3465 attr = attr->next;
3466 }
3467 }
3468 if (IS_XSLT_ELEM(cur)) {
3469 exclPrefixes = 0;
3470 xsltStylePreCompute(style, cur);
3471 if (IS_XSLT_NAME(cur, "text")) {
3472 for (;exclPrefixes > 0;exclPrefixes--)
3473 exclPrefixPop(style);
3474 goto skip_children;
3475 }
3476 } else {
3477 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3478 }
3479
3480 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3481 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3482 xmlNodePtr root = NULL;
3483 int i, moved;
3484
3485 root = xmlDocGetRootElement(cur->doc);
3486 if ((root != NULL) && (root != cur)) {
3487 while (ns != NULL) {
3488 moved = 0;
3489 next = ns->next;
3490 for (i = 0;i < style->exclPrefixNr;i++) {
3491 if ((ns->prefix != NULL) &&
3492 (xmlStrEqual(ns->href,
3493 style->exclPrefixTab[i]))) {
3494 /*
3495 * Move the namespace definition on the root
3496 * element to avoid duplicating it without
3497 * loosing it.
3498 */
3499 if (prev == NULL) {
3500 cur->nsDef = ns->next;
3501 } else {
3502 prev->next = ns->next;
3503 }
3504 ns->next = root->nsDef;
3505 root->nsDef = ns;
3506 moved = 1;
3507 break;
3508 }
3509 }
3510 if (moved == 0)
3511 prev = ns;
3512 ns = next;
3513 }
3514 }
3515 }
3516 /*
3517 * If we have prefixes locally, recurse and pop them up when
3518 * going back
3519 */
3520 if (exclPrefixes > 0) {
3521 xsltPrecomputeStylesheet(style, cur->children);
3522 for (;exclPrefixes > 0;exclPrefixes--)
3523 exclPrefixPop(style);
3524 goto skip_children;
3525 }
3526 } else if (cur->type == XML_TEXT_NODE) {
3527 if (IS_BLANK_NODE(cur)) {
3528 if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
3529 deleteNode = cur;
3530 }
3531 } else if ((cur->content != NULL) && (internalize) &&
3532 (!xmlDictOwns(style->dict, cur->content))) {
3533 xmlChar *tmp;
3534
3535 /*
3536 * internalize the text string, goal is to speed
3537 * up operations and minimize used space by compiled
3538 * stylesheets.
3539 */
3540 tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3541 xmlNodeSetContent(cur, NULL);
3542 cur->content = tmp;
3543 }
3544 } else if ((cur->type != XML_ELEMENT_NODE) &&
3545 (cur->type != XML_CDATA_SECTION_NODE)) {
3546 deleteNode = cur;
3547 goto skip_children;
3548 }
3549
3550 /*
3551 * Skip to next node. In case of a namespaced element children of
3552 * the stylesheet and not in the XSLT namespace and not an extension
3553 * element, ignore its content.
3554 */
3555 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3556 (styleelem != NULL) && (cur->parent == styleelem) &&
3557 (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3558 (!xsltCheckExtURI(style, cur->ns->href))) {
3559 goto skip_children;
3560 } else if (cur->children != NULL) {
3561 if ((cur->children->type != XML_ENTITY_DECL) &&
3562 (cur->children->type != XML_ENTITY_REF_NODE) &&
3563 (cur->children->type != XML_ENTITY_NODE)) {
3564 cur = cur->children;
3565 continue;
3566 }
3567 }
3568
3569 skip_children:
3570 if (cur->next != NULL) {
3571 cur = cur->next;
3572 continue;
3573 }
3574 do {
3575
3576 cur = cur->parent;
3577 if (cur == NULL)
3578 break;
3579 if (cur == (xmlNodePtr) style->doc) {
3580 cur = NULL;
3581 break;
3582 }
3583 if (cur->next != NULL) {
3584 cur = cur->next;
3585 break;
3586 }
3587 } while (cur != NULL);
3588 }
3589 if (deleteNode != NULL) {
3590 #ifdef WITH_XSLT_DEBUG_PARSING
3591 xsltGenericDebug(xsltGenericDebugContext,
3592 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3593 #endif
3594 xmlUnlinkNode(deleteNode);
3595 xmlFreeNode(deleteNode);
3596 }
3597 }
3598 #endif /* end of else XSLT_REFACTORED */
3599
3600 /**
3601 * xsltGatherNamespaces:
3602 * @style: the XSLT stylesheet
3603 *
3604 * Browse the stylesheet and build the namspace hash table which
3605 * will be used for XPath interpretation. If needed do a bit of normalization
3606 */
3607
3608 static void
3609 xsltGatherNamespaces(xsltStylesheetPtr style) {
3610 xmlNodePtr cur;
3611 const xmlChar *URI;
3612
3613 if (style == NULL)
3614 return;
3615 /*
3616 * TODO: basically if the stylesheet uses the same prefix for different
3617 * patterns, well they may be in problem, hopefully they will get
3618 * a warning first.
3619 */
3620 /*
3621 * TODO: Eliminate the use of the hash for XPath expressions.
3622 * An expression should be evaluated in the context of the in-scope
3623 * namespaces; eliminate the restriction of an XML document to contain
3624 * no duplicate prefixes for different namespace names.
3625 *
3626 */
3627 cur = xmlDocGetRootElement(style->doc);
3628 while (cur != NULL) {
3629 if (cur->type == XML_ELEMENT_NODE) {
3630 xmlNsPtr ns = cur->nsDef;
3631 while (ns != NULL) {
3632 if (ns->prefix != NULL) {
3633 if (style->nsHash == NULL) {
3634 style->nsHash = xmlHashCreate(10);
3635 if (style->nsHash == NULL) {
3636 xsltTransformError(NULL, style, cur,
3637 "xsltGatherNamespaces: failed to create hash table\n");
3638 style->errors++;
3639 return;
3640 }
3641 }
3642 URI = xmlHashLookup(style->nsHash, ns->prefix);
3643 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3644 xsltTransformError(NULL, style, cur,
3645 "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3646 style->warnings++;
3647 } else if (URI == NULL) {
3648 xmlHashUpdateEntry(style->nsHash, ns->prefix,
3649 (void *) ns->href, (xmlHashDeallocator)xmlFree);
3650
3651 #ifdef WITH_XSLT_DEBUG_PARSING
3652 xsltGenericDebug(xsltGenericDebugContext,
3653 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3654 #endif
3655 }
3656 }
3657 ns = ns->next;
3658 }
3659 }
3660
3661 /*
3662 * Skip to next node
3663 */
3664 if (cur->children != NULL) {
3665 if (cur->children->type != XML_ENTITY_DECL) {
3666 cur = cur->children;
3667 continue;
3668 }
3669 }
3670 if (cur->next != NULL) {
3671 cur = cur->next;
3672 continue;
3673 }
3674
3675 do {
3676 cur = cur->parent;
3677 if (cur == NULL)
3678 break;
3679 if (cur == (xmlNodePtr) style->doc) {
3680 cur = NULL;
3681 break;
3682 }
3683 if (cur->next != NULL) {
3684 cur = cur->next;
3685 break;
3686 }
3687 } while (cur != NULL);
3688 }
3689 }
3690
3691 #ifdef XSLT_REFACTORED
3692
3693 static xsltStyleType
3694 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3695 xmlNodePtr node)
3696 {
3697 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3698 (node->name == NULL))
3699 return(0);
3700
3701 if (node->name[0] == 'a') {
3702 if (IS_XSLT_NAME(node, "apply-templates"))
3703 return(XSLT_FUNC_APPLYTEMPLATES);
3704 else if (IS_XSLT_NAME(node, "attribute"))
3705 return(XSLT_FUNC_ATTRIBUTE);
3706 else if (IS_XSLT_NAME(node, "apply-imports"))
3707 return(XSLT_FUNC_APPLYIMPORTS);
3708 else if (IS_XSLT_NAME(node, "attribute-set"))
3709 return(0);
3710
3711 } else if (node->name[0] == 'c') {
3712 if (IS_XSLT_NAME(node, "choose"))
3713 return(XSLT_FUNC_CHOOSE);
3714 else if (IS_XSLT_NAME(node, "copy"))
3715 return(XSLT_FUNC_COPY);
3716 else if (IS_XSLT_NAME(node, "copy-of"))
3717 return(XSLT_FUNC_COPYOF);
3718 else if (IS_XSLT_NAME(node, "call-template"))
3719 return(XSLT_FUNC_CALLTEMPLATE);
3720 else if (IS_XSLT_NAME(node, "comment"))
3721 return(XSLT_FUNC_COMMENT);
3722
3723 } else if (node->name[0] == 'd') {
3724 if (IS_XSLT_NAME(node, "document"))
3725 return(XSLT_FUNC_DOCUMENT);
3726 else if (IS_XSLT_NAME(node, "decimal-format"))
3727 return(0);
3728
3729 } else if (node->name[0] == 'e') {
3730 if (IS_XSLT_NAME(node, "element"))
3731 return(XSLT_FUNC_ELEMENT);
3732
3733 } else if (node->name[0] == 'f') {
3734 if (IS_XSLT_NAME(node, "for-each"))
3735 return(XSLT_FUNC_FOREACH);
3736 else if (IS_XSLT_NAME(node, "fallback"))
3737 return(XSLT_FUNC_FALLBACK);
3738
3739 } else if (*(node->name) == 'i') {
3740 if (IS_XSLT_NAME(node, "if"))
3741 return(XSLT_FUNC_IF);
3742 else if (IS_XSLT_NAME(node, "include"))
3743 return(0);
3744 else if (IS_XSLT_NAME(node, "import"))
3745 return(0);
3746
3747 } else if (*(node->name) == 'k') {
3748 if (IS_XSLT_NAME(node, "key"))
3749 return(0);
3750
3751 } else if (*(node->name) == 'm') {
3752 if (IS_XSLT_NAME(node, "message"))
3753 return(XSLT_FUNC_MESSAGE);
3754
3755 } else if (*(node->name) == 'n') {
3756 if (IS_XSLT_NAME(node, "number"))
3757 return(XSLT_FUNC_NUMBER);
3758 else if (IS_XSLT_NAME(node, "namespace-alias"))
3759 return(0);
3760
3761 } else if (*(node->name) == 'o') {
3762 if (IS_XSLT_NAME(node, "otherwise"))
3763 return(XSLT_FUNC_OTHERWISE);
3764 else if (IS_XSLT_NAME(node, "output"))
3765 return(0);
3766
3767 } else if (*(node->name) == 'p') {
3768 if (IS_XSLT_NAME(node, "param"))
3769 return(XSLT_FUNC_PARAM);
3770 else if (IS_XSLT_NAME(node, "processing-instruction"))
3771 return(XSLT_FUNC_PI);
3772 else if (IS_XSLT_NAME(node, "preserve-space"))
3773 return(0);
3774
3775 } else if (*(node->name) == 's') {
3776 if (IS_XSLT_NAME(node, "sort"))
3777 return(XSLT_FUNC_SORT);
3778 else if (IS_XSLT_NAME(node, "strip-space"))
3779 return(0);
3780 else if (IS_XSLT_NAME(node, "stylesheet"))
3781 return(0);
3782
3783 } else if (node->name[0] == 't') {
3784 if (IS_XSLT_NAME(node, "text"))
3785 return(XSLT_FUNC_TEXT);
3786 else if (IS_XSLT_NAME(node, "template"))
3787 return(0);
3788 else if (IS_XSLT_NAME(node, "transform"))
3789 return(0);
3790
3791 } else if (*(node->name) == 'v') {
3792 if (IS_XSLT_NAME(node, "value-of"))
3793 return(XSLT_FUNC_VALUEOF);
3794 else if (IS_XSLT_NAME(node, "variable"))
3795 return(XSLT_FUNC_VARIABLE);
3796
3797 } else if (*(node->name) == 'w') {
3798 if (IS_XSLT_NAME(node