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