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