VirtualBox

source: vbox/trunk/src/libs/libxslt-1.1.22/libxslt/xslt.c@ 26286

Last change on this file since 26286 was 7296, checked in by vboxsync, 17 years ago

Added libxslt-1.1.22 sources.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette