4ef3f631d98ace7eb5b3a0c864f2dbb88d9e7b4c
[reactos.git] / dll / 3rdparty / libxslt / preproc.c
1 /*
2 * preproc.c: Preprocessing of style operations
3 *
4 * References:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * Michael Kay "XSLT Programmer's Reference" pp 637-643
8 * Writing Multiple Output Files
9 *
10 * XSLT-1.1 Working Draft
11 * http://www.w3.org/TR/xslt11#multiple-output
12 *
13 * See Copyright for the status of this software.
14 *
15 * daniel@veillard.com
16 */
17
18 #define IN_LIBXSLT
19 #include "libxslt.h"
20
21 #include <string.h>
22
23 #include <libxml/xmlmemory.h>
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
26 #include <libxml/valid.h>
27 #include <libxml/hash.h>
28 #include <libxml/uri.h>
29 #include <libxml/encoding.h>
30 #include <libxml/xmlerror.h>
31 #include "xslt.h"
32 #include "xsltutils.h"
33 #include "xsltInternals.h"
34 #include "transform.h"
35 #include "templates.h"
36 #include "variables.h"
37 #include "numbersInternals.h"
38 #include "preproc.h"
39 #include "extra.h"
40 #include "imports.h"
41 #include "extensions.h"
42 #include "pattern.h"
43
44 #ifdef WITH_XSLT_DEBUG
45 #define WITH_XSLT_DEBUG_PREPROC
46 #endif
47
48 const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";
49
50 /************************************************************************
51 * *
52 * Grammar checks *
53 * *
54 ************************************************************************/
55
56 #ifdef XSLT_REFACTORED
57 /*
58 * Grammar checks are now performed in xslt.c.
59 */
60 #else
61 /**
62 * xsltCheckTopLevelElement:
63 * @style: the XSLT stylesheet
64 * @inst: the XSLT instruction
65 * @err: raise an error or not
66 *
67 * Check that the instruction is instanciated as a top level element.
68 *
69 * Returns -1 in case of error, 0 if failed and 1 in case of success
70 */
71 static int
72 xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) {
73 xmlNodePtr parent;
74 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL))
75 return(-1);
76
77 parent = inst->parent;
78 if (parent == NULL) {
79 if (err) {
80 xsltTransformError(NULL, style, inst,
81 "internal problem: element has no parent\n");
82 style->errors++;
83 }
84 return(0);
85 }
86 if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) ||
87 ((parent->ns != inst->ns) &&
88 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
89 ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) &&
90 (!xmlStrEqual(parent->name, BAD_CAST "transform")))) {
91 if (err) {
92 xsltTransformError(NULL, style, inst,
93 "element %s only allowed as child of stylesheet\n",
94 inst->name);
95 style->errors++;
96 }
97 return(0);
98 }
99 return(1);
100 }
101
102 /**
103 * xsltCheckInstructionElement:
104 * @style: the XSLT stylesheet
105 * @inst: the XSLT instruction
106 *
107 * Check that the instruction is instanciated as an instruction element.
108 */
109 static void
110 xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) {
111 xmlNodePtr parent;
112 int has_ext;
113
114 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
115 (style->literal_result))
116 return;
117
118 has_ext = (style->extInfos != NULL);
119
120 parent = inst->parent;
121 if (parent == NULL) {
122 xsltTransformError(NULL, style, inst,
123 "internal problem: element has no parent\n");
124 style->errors++;
125 return;
126 }
127 while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
128 if (((parent->ns == inst->ns) ||
129 ((parent->ns != NULL) &&
130 (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
131 ((xmlStrEqual(parent->name, BAD_CAST "template")) ||
132 (xmlStrEqual(parent->name, BAD_CAST "param")) ||
133 (xmlStrEqual(parent->name, BAD_CAST "attribute")) ||
134 (xmlStrEqual(parent->name, BAD_CAST "variable")))) {
135 return;
136 }
137
138 /*
139 * if we are within an extension element all bets are off
140 * about the semantic there e.g. xsl:param within func:function
141 */
142 if ((has_ext) && (parent->ns != NULL) &&
143 (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
144 return;
145
146 parent = parent->parent;
147 }
148 xsltTransformError(NULL, style, inst,
149 "element %s only allowed within a template, variable or param\n",
150 inst->name);
151 style->errors++;
152 }
153
154 /**
155 * xsltCheckParentElement:
156 * @style: the XSLT stylesheet
157 * @inst: the XSLT instruction
158 * @allow1: allowed parent1
159 * @allow2: allowed parent2
160 *
161 * Check that the instruction is instanciated as the childre of one of the
162 * possible parents.
163 */
164 static void
165 xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst,
166 const xmlChar *allow1, const xmlChar *allow2) {
167 xmlNodePtr parent;
168
169 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
170 (style->literal_result))
171 return;
172
173 parent = inst->parent;
174 if (parent == NULL) {
175 xsltTransformError(NULL, style, inst,
176 "internal problem: element has no parent\n");
177 style->errors++;
178 return;
179 }
180 if (((parent->ns == inst->ns) ||
181 ((parent->ns != NULL) &&
182 (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
183 ((xmlStrEqual(parent->name, allow1)) ||
184 (xmlStrEqual(parent->name, allow2)))) {
185 return;
186 }
187
188 if (style->extInfos != NULL) {
189 while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
190 /*
191 * if we are within an extension element all bets are off
192 * about the semantic there e.g. xsl:param within func:function
193 */
194 if ((parent->ns != NULL) &&
195 (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
196 return;
197
198 parent = parent->parent;
199 }
200 }
201 xsltTransformError(NULL, style, inst,
202 "element %s is not allowed within that context\n",
203 inst->name);
204 style->errors++;
205 }
206 #endif
207
208 /************************************************************************
209 * *
210 * handling of precomputed data *
211 * *
212 ************************************************************************/
213
214 /**
215 * xsltNewStylePreComp:
216 * @style: the XSLT stylesheet
217 * @type: the construct type
218 *
219 * Create a new XSLT Style precomputed block
220 *
221 * Returns the newly allocated specialized structure
222 * or NULL in case of error
223 */
224 static xsltStylePreCompPtr
225 xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
226 xsltStylePreCompPtr cur;
227 #ifdef XSLT_REFACTORED
228 size_t size;
229 #endif
230
231 if (style == NULL)
232 return(NULL);
233
234 #ifdef XSLT_REFACTORED
235 /*
236 * URGENT TODO: Use specialized factory functions in order
237 * to avoid this ugliness.
238 */
239 switch (type) {
240 case XSLT_FUNC_COPY:
241 size = sizeof(xsltStyleItemCopy); break;
242 case XSLT_FUNC_SORT:
243 size = sizeof(xsltStyleItemSort); break;
244 case XSLT_FUNC_TEXT:
245 size = sizeof(xsltStyleItemText); break;
246 case XSLT_FUNC_ELEMENT:
247 size = sizeof(xsltStyleItemElement); break;
248 case XSLT_FUNC_ATTRIBUTE:
249 size = sizeof(xsltStyleItemAttribute); break;
250 case XSLT_FUNC_COMMENT:
251 size = sizeof(xsltStyleItemComment); break;
252 case XSLT_FUNC_PI:
253 size = sizeof(xsltStyleItemPI); break;
254 case XSLT_FUNC_COPYOF:
255 size = sizeof(xsltStyleItemCopyOf); break;
256 case XSLT_FUNC_VALUEOF:
257 size = sizeof(xsltStyleItemValueOf); break;;
258 case XSLT_FUNC_NUMBER:
259 size = sizeof(xsltStyleItemNumber); break;
260 case XSLT_FUNC_APPLYIMPORTS:
261 size = sizeof(xsltStyleItemApplyImports); break;
262 case XSLT_FUNC_CALLTEMPLATE:
263 size = sizeof(xsltStyleItemCallTemplate); break;
264 case XSLT_FUNC_APPLYTEMPLATES:
265 size = sizeof(xsltStyleItemApplyTemplates); break;
266 case XSLT_FUNC_CHOOSE:
267 size = sizeof(xsltStyleItemChoose); break;
268 case XSLT_FUNC_IF:
269 size = sizeof(xsltStyleItemIf); break;
270 case XSLT_FUNC_FOREACH:
271 size = sizeof(xsltStyleItemForEach); break;
272 case XSLT_FUNC_DOCUMENT:
273 size = sizeof(xsltStyleItemDocument); break;
274 case XSLT_FUNC_WITHPARAM:
275 size = sizeof(xsltStyleItemWithParam); break;
276 case XSLT_FUNC_PARAM:
277 size = sizeof(xsltStyleItemParam); break;
278 case XSLT_FUNC_VARIABLE:
279 size = sizeof(xsltStyleItemVariable); break;
280 case XSLT_FUNC_WHEN:
281 size = sizeof(xsltStyleItemWhen); break;
282 case XSLT_FUNC_OTHERWISE:
283 size = sizeof(xsltStyleItemOtherwise); break;
284 default:
285 xsltTransformError(NULL, style, NULL,
286 "xsltNewStylePreComp : invalid type %d\n", type);
287 style->errors++;
288 return(NULL);
289 }
290 /*
291 * Create the structure.
292 */
293 cur = (xsltStylePreCompPtr) xmlMalloc(size);
294 if (cur == NULL) {
295 xsltTransformError(NULL, style, NULL,
296 "xsltNewStylePreComp : malloc failed\n");
297 style->errors++;
298 return(NULL);
299 }
300 memset(cur, 0, size);
301
302 #else /* XSLT_REFACTORED */
303 /*
304 * Old behaviour.
305 */
306 cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
307 if (cur == NULL) {
308 xsltTransformError(NULL, style, NULL,
309 "xsltNewStylePreComp : malloc failed\n");
310 style->errors++;
311 return(NULL);
312 }
313 memset(cur, 0, sizeof(xsltStylePreComp));
314 #endif /* XSLT_REFACTORED */
315
316 /*
317 * URGENT TODO: Better to move this to spezialized factory functions.
318 */
319 cur->type = type;
320 switch (cur->type) {
321 case XSLT_FUNC_COPY:
322 cur->func = (xsltTransformFunction) xsltCopy;break;
323 case XSLT_FUNC_SORT:
324 cur->func = (xsltTransformFunction) xsltSort;break;
325 case XSLT_FUNC_TEXT:
326 cur->func = (xsltTransformFunction) xsltText;break;
327 case XSLT_FUNC_ELEMENT:
328 cur->func = (xsltTransformFunction) xsltElement;break;
329 case XSLT_FUNC_ATTRIBUTE:
330 cur->func = (xsltTransformFunction) xsltAttribute;break;
331 case XSLT_FUNC_COMMENT:
332 cur->func = (xsltTransformFunction) xsltComment;break;
333 case XSLT_FUNC_PI:
334 cur->func = (xsltTransformFunction) xsltProcessingInstruction;
335 break;
336 case XSLT_FUNC_COPYOF:
337 cur->func = (xsltTransformFunction) xsltCopyOf;break;
338 case XSLT_FUNC_VALUEOF:
339 cur->func = (xsltTransformFunction) xsltValueOf;break;
340 case XSLT_FUNC_NUMBER:
341 cur->func = (xsltTransformFunction) xsltNumber;break;
342 case XSLT_FUNC_APPLYIMPORTS:
343 cur->func = (xsltTransformFunction) xsltApplyImports;break;
344 case XSLT_FUNC_CALLTEMPLATE:
345 cur->func = (xsltTransformFunction) xsltCallTemplate;break;
346 case XSLT_FUNC_APPLYTEMPLATES:
347 cur->func = (xsltTransformFunction) xsltApplyTemplates;break;
348 case XSLT_FUNC_CHOOSE:
349 cur->func = (xsltTransformFunction) xsltChoose;break;
350 case XSLT_FUNC_IF:
351 cur->func = (xsltTransformFunction) xsltIf;break;
352 case XSLT_FUNC_FOREACH:
353 cur->func = (xsltTransformFunction) xsltForEach;break;
354 case XSLT_FUNC_DOCUMENT:
355 cur->func = (xsltTransformFunction) xsltDocumentElem;break;
356 case XSLT_FUNC_WITHPARAM:
357 case XSLT_FUNC_PARAM:
358 case XSLT_FUNC_VARIABLE:
359 case XSLT_FUNC_WHEN:
360 break;
361 default:
362 if (cur->func == NULL) {
363 xsltTransformError(NULL, style, NULL,
364 "xsltNewStylePreComp : no function for type %d\n", type);
365 style->errors++;
366 }
367 }
368 cur->next = style->preComps;
369 style->preComps = (xsltElemPreCompPtr) cur;
370
371 return(cur);
372 }
373
374 /**
375 * xsltFreeStylePreComp:
376 * @comp: an XSLT Style precomputed block
377 *
378 * Free up the memory allocated by @comp
379 */
380 static void
381 xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
382 if (comp == NULL)
383 return;
384 #ifdef XSLT_REFACTORED
385 /*
386 * URGENT TODO: Implement destructors.
387 */
388 switch (comp->type) {
389 case XSLT_FUNC_LITERAL_RESULT_ELEMENT:
390 break;
391 case XSLT_FUNC_COPY:
392 break;
393 case XSLT_FUNC_SORT: {
394 xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp;
395 if (item->locale != (xsltLocale)0)
396 xsltFreeLocale(item->locale);
397 if (item->comp != NULL)
398 xmlXPathFreeCompExpr(item->comp);
399 }
400 break;
401 case XSLT_FUNC_TEXT:
402 break;
403 case XSLT_FUNC_ELEMENT:
404 break;
405 case XSLT_FUNC_ATTRIBUTE:
406 break;
407 case XSLT_FUNC_COMMENT:
408 break;
409 case XSLT_FUNC_PI:
410 break;
411 case XSLT_FUNC_COPYOF: {
412 xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp;
413 if (item->comp != NULL)
414 xmlXPathFreeCompExpr(item->comp);
415 }
416 break;
417 case XSLT_FUNC_VALUEOF: {
418 xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp;
419 if (item->comp != NULL)
420 xmlXPathFreeCompExpr(item->comp);
421 }
422 break;
423 case XSLT_FUNC_NUMBER: {
424 xsltStyleItemNumberPtr item = (xsltStyleItemNumberPtr) comp;
425 if (item->numdata.countPat != NULL)
426 xsltFreeCompMatchList(item->numdata.countPat);
427 if (item->numdata.fromPat != NULL)
428 xsltFreeCompMatchList(item->numdata.fromPat);
429 }
430 break;
431 case XSLT_FUNC_APPLYIMPORTS:
432 break;
433 case XSLT_FUNC_CALLTEMPLATE:
434 break;
435 case XSLT_FUNC_APPLYTEMPLATES: {
436 xsltStyleItemApplyTemplatesPtr item =
437 (xsltStyleItemApplyTemplatesPtr) comp;
438 if (item->comp != NULL)
439 xmlXPathFreeCompExpr(item->comp);
440 }
441 break;
442 case XSLT_FUNC_CHOOSE:
443 break;
444 case XSLT_FUNC_IF: {
445 xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp;
446 if (item->comp != NULL)
447 xmlXPathFreeCompExpr(item->comp);
448 }
449 break;
450 case XSLT_FUNC_FOREACH: {
451 xsltStyleItemForEachPtr item =
452 (xsltStyleItemForEachPtr) comp;
453 if (item->comp != NULL)
454 xmlXPathFreeCompExpr(item->comp);
455 }
456 break;
457 case XSLT_FUNC_DOCUMENT:
458 break;
459 case XSLT_FUNC_WITHPARAM: {
460 xsltStyleItemWithParamPtr item =
461 (xsltStyleItemWithParamPtr) comp;
462 if (item->comp != NULL)
463 xmlXPathFreeCompExpr(item->comp);
464 }
465 break;
466 case XSLT_FUNC_PARAM: {
467 xsltStyleItemParamPtr item =
468 (xsltStyleItemParamPtr) comp;
469 if (item->comp != NULL)
470 xmlXPathFreeCompExpr(item->comp);
471 }
472 break;
473 case XSLT_FUNC_VARIABLE: {
474 xsltStyleItemVariablePtr item =
475 (xsltStyleItemVariablePtr) comp;
476 if (item->comp != NULL)
477 xmlXPathFreeCompExpr(item->comp);
478 }
479 break;
480 case XSLT_FUNC_WHEN: {
481 xsltStyleItemWhenPtr item =
482 (xsltStyleItemWhenPtr) comp;
483 if (item->comp != NULL)
484 xmlXPathFreeCompExpr(item->comp);
485 }
486 break;
487 case XSLT_FUNC_OTHERWISE:
488 case XSLT_FUNC_FALLBACK:
489 case XSLT_FUNC_MESSAGE:
490 case XSLT_FUNC_INCLUDE:
491 case XSLT_FUNC_ATTRSET:
492
493 break;
494 default:
495 /* TODO: Raise error. */
496 break;
497 }
498 #else
499 if (comp->locale != (xsltLocale)0)
500 xsltFreeLocale(comp->locale);
501 if (comp->comp != NULL)
502 xmlXPathFreeCompExpr(comp->comp);
503 if (comp->numdata.countPat != NULL)
504 xsltFreeCompMatchList(comp->numdata.countPat);
505 if (comp->numdata.fromPat != NULL)
506 xsltFreeCompMatchList(comp->numdata.fromPat);
507 if (comp->nsList != NULL)
508 xmlFree(comp->nsList);
509 #endif
510
511 xmlFree(comp);
512 }
513
514
515 /************************************************************************
516 * *
517 * XSLT-1.1 extensions *
518 * *
519 ************************************************************************/
520
521 /**
522 * xsltDocumentComp:
523 * @style: the XSLT stylesheet
524 * @inst: the instruction in the stylesheet
525 * @function: unused
526 *
527 * Pre process an XSLT-1.1 document element
528 *
529 * Returns a precompiled data structure for the element
530 */
531 xsltElemPreCompPtr
532 xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
533 xsltTransformFunction function ATTRIBUTE_UNUSED) {
534 #ifdef XSLT_REFACTORED
535 xsltStyleItemDocumentPtr comp;
536 #else
537 xsltStylePreCompPtr comp;
538 #endif
539 const xmlChar *filename = NULL;
540
541 /*
542 * As of 2006-03-30, this function is currently defined in Libxslt
543 * to be used for:
544 * (in libxslt/extra.c)
545 * "output" in XSLT_SAXON_NAMESPACE
546 * "write" XSLT_XALAN_NAMESPACE
547 * "document" XSLT_XT_NAMESPACE
548 * "document" XSLT_NAMESPACE (from the abandoned old working
549 * draft of XSLT 1.1)
550 * (in libexslt/common.c)
551 * "document" in EXSLT_COMMON_NAMESPACE
552 */
553 #ifdef XSLT_REFACTORED
554 comp = (xsltStyleItemDocumentPtr)
555 xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
556 #else
557 comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
558 #endif
559
560 if (comp == NULL)
561 return (NULL);
562 comp->inst = inst;
563 comp->ver11 = 0;
564
565 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
566 #ifdef WITH_XSLT_DEBUG_EXTRA
567 xsltGenericDebug(xsltGenericDebugContext,
568 "Found saxon:output extension\n");
569 #endif
570 /*
571 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
572 * (http://icl.com/saxon)
573 * The @file is in no namespace; it is an AVT.
574 * (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output)
575 *
576 * TODO: Do we need not to check the namespace here?
577 */
578 filename = xsltEvalStaticAttrValueTemplate(style, inst,
579 (const xmlChar *)"file",
580 NULL, &comp->has_filename);
581 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
582 #ifdef WITH_XSLT_DEBUG_EXTRA
583 xsltGenericDebug(xsltGenericDebugContext,
584 "Found xalan:write extension\n");
585 #endif
586 /* the filename need to be interpreted */
587 /*
588 * TODO: Is "filename need to be interpreted" meant to be a todo?
589 * Where will be the filename of xalan:write be processed?
590 *
591 * TODO: Do we need not to check the namespace here?
592 * The extension ns is "http://xml.apache.org/xalan/redirect".
593 * See http://xml.apache.org/xalan-j/extensionslib.html.
594 */
595 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
596 if (inst->ns != NULL) {
597 if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) {
598 /*
599 * Mark the instruction as being of
600 * XSLT version 1.1 (abandoned).
601 */
602 comp->ver11 = 1;
603 #ifdef WITH_XSLT_DEBUG_EXTRA
604 xsltGenericDebug(xsltGenericDebugContext,
605 "Found xslt11:document construct\n");
606 #endif
607 } else {
608 if (xmlStrEqual(inst->ns->href,
609 (const xmlChar *)"http://exslt.org/common")) {
610 /* EXSLT. */
611 #ifdef WITH_XSLT_DEBUG_EXTRA
612 xsltGenericDebug(xsltGenericDebugContext,
613 "Found exslt:document extension\n");
614 #endif
615 } else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) {
616 /* James Clark's XT. */
617 #ifdef WITH_XSLT_DEBUG_EXTRA
618 xsltGenericDebug(xsltGenericDebugContext,
619 "Found xt:document extension\n");
620 #endif
621 }
622 }
623 }
624 /*
625 * The element "document" is used in conjunction with the
626 * following namespaces:
627 *
628 * 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1)
629 * <!ELEMENT xsl:document %template;>
630 * <!ATTLIST xsl:document
631 * href %avt; #REQUIRED
632 * @href is an AVT
633 * IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft,
634 * it was removed and isn't available in XSLT 1.1 anymore.
635 * In XSLT 2.0 it was renamed to xsl:result-document.
636 *
637 * All other attributes are identical to the attributes
638 * on xsl:output
639 *
640 * 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common)
641 * <exsl:document
642 * href = { uri-reference }
643 * TODO: is @href is an AVT?
644 *
645 * 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt)
646 * Example: <xt:document method="xml" href="myFile.xml">
647 * TODO: is @href is an AVT?
648 *
649 * In all cases @href is in no namespace.
650 */
651 filename = xsltEvalStaticAttrValueTemplate(style, inst,
652 (const xmlChar *)"href", NULL, &comp->has_filename);
653 }
654 if (!comp->has_filename) {
655 goto error;
656 }
657 comp->filename = filename;
658
659 error:
660 return ((xsltElemPreCompPtr) comp);
661 }
662
663 /************************************************************************
664 * *
665 * Most of the XSLT-1.0 transformations *
666 * *
667 ************************************************************************/
668
669 /**
670 * xsltSortComp:
671 * @style: the XSLT stylesheet
672 * @inst: the xslt sort node
673 *
674 * Process the xslt sort node on the source node
675 */
676 static void
677 xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
678 #ifdef XSLT_REFACTORED
679 xsltStyleItemSortPtr comp;
680 #else
681 xsltStylePreCompPtr comp;
682 #endif
683 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
684 return;
685
686 #ifdef XSLT_REFACTORED
687 comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT);
688 #else
689 comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
690 #endif
691
692 if (comp == NULL)
693 return;
694 inst->psvi = comp;
695 comp->inst = inst;
696
697 comp->stype = xsltEvalStaticAttrValueTemplate(style, inst,
698 (const xmlChar *)"data-type",
699 NULL, &comp->has_stype);
700 if (comp->stype != NULL) {
701 if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
702 comp->number = 0;
703 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
704 comp->number = 1;
705 else {
706 xsltTransformError(NULL, style, inst,
707 "xsltSortComp: no support for data-type = %s\n", comp->stype);
708 comp->number = 0; /* use default */
709 if (style != NULL) style->warnings++;
710 }
711 }
712 comp->order = xsltEvalStaticAttrValueTemplate(style, inst,
713 (const xmlChar *)"order",
714 NULL, &comp->has_order);
715 if (comp->order != NULL) {
716 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
717 comp->descending = 0;
718 else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
719 comp->descending = 1;
720 else {
721 xsltTransformError(NULL, style, inst,
722 "xsltSortComp: invalid value %s for order\n", comp->order);
723 comp->descending = 0; /* use default */
724 if (style != NULL) style->warnings++;
725 }
726 }
727 comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst,
728 (const xmlChar *)"case-order",
729 NULL, &comp->has_use);
730 if (comp->case_order != NULL) {
731 if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first"))
732 comp->lower_first = 0;
733 else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first"))
734 comp->lower_first = 1;
735 else {
736 xsltTransformError(NULL, style, inst,
737 "xsltSortComp: invalid value %s for order\n", comp->order);
738 comp->lower_first = 0; /* use default */
739 if (style != NULL) style->warnings++;
740 }
741 }
742
743 comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
744 (const xmlChar *)"lang",
745 NULL, &comp->has_lang);
746 if (comp->lang != NULL) {
747 comp->locale = xsltNewLocale(comp->lang);
748 }
749 else {
750 comp->locale = (xsltLocale)0;
751 }
752
753 comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
754 if (comp->select == NULL) {
755 /*
756 * The default value of the select attribute is ., which will
757 * cause the string-value of the current node to be used as
758 * the sort key.
759 */
760 comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);
761 }
762 comp->comp = xsltXPathCompile(style, comp->select);
763 if (comp->comp == NULL) {
764 xsltTransformError(NULL, style, inst,
765 "xsltSortComp: could not compile select expression '%s'\n",
766 comp->select);
767 if (style != NULL) style->errors++;
768 }
769 if (inst->children != NULL) {
770 xsltTransformError(NULL, style, inst,
771 "xsl:sort : is not empty\n");
772 if (style != NULL) style->errors++;
773 }
774 }
775
776 /**
777 * xsltCopyComp:
778 * @style: the XSLT stylesheet
779 * @inst: the xslt copy node
780 *
781 * Process the xslt copy node on the source node
782 */
783 static void
784 xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
785 #ifdef XSLT_REFACTORED
786 xsltStyleItemCopyPtr comp;
787 #else
788 xsltStylePreCompPtr comp;
789 #endif
790
791 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
792 return;
793 #ifdef XSLT_REFACTORED
794 comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY);
795 #else
796 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
797 #endif
798
799 if (comp == NULL)
800 return;
801 inst->psvi = comp;
802 comp->inst = inst;
803
804
805 comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",
806 XSLT_NAMESPACE);
807 if (comp->use == NULL)
808 comp->has_use = 0;
809 else
810 comp->has_use = 1;
811 }
812
813 #ifdef XSLT_REFACTORED
814 /* Enable if ever needed for xsl:text. */
815 #else
816 /**
817 * xsltTextComp:
818 * @style: an XSLT compiled stylesheet
819 * @inst: the xslt text node
820 *
821 * TODO: This function is obsolete, since xsl:text won't
822 * be compiled, but removed from the tree.
823 *
824 * Process the xslt text node on the source node
825 */
826 static void
827 xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
828 #ifdef XSLT_REFACTORED
829 xsltStyleItemTextPtr comp;
830 #else
831 xsltStylePreCompPtr comp;
832 #endif
833 const xmlChar *prop;
834
835 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
836 return;
837
838 #ifdef XSLT_REFACTORED
839 comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
840 #else
841 comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
842 #endif
843 if (comp == NULL)
844 return;
845 inst->psvi = comp;
846 comp->inst = inst;
847 comp->noescape = 0;
848
849 prop = xsltGetCNsProp(style, inst,
850 (const xmlChar *)"disable-output-escaping",
851 XSLT_NAMESPACE);
852 if (prop != NULL) {
853 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
854 comp->noescape = 1;
855 } else if (!xmlStrEqual(prop,
856 (const xmlChar *)"no")){
857 xsltTransformError(NULL, style, inst,
858 "xsl:text: disable-output-escaping allows only yes or no\n");
859 if (style != NULL) style->warnings++;
860 }
861 }
862 }
863 #endif /* else of XSLT_REFACTORED */
864
865 /**
866 * xsltElementComp:
867 * @style: an XSLT compiled stylesheet
868 * @inst: the xslt element node
869 *
870 * Process the xslt element node on the source node
871 */
872 static void
873 xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
874 #ifdef XSLT_REFACTORED
875 xsltStyleItemElementPtr comp;
876 #else
877 xsltStylePreCompPtr comp;
878 #endif
879
880 /*
881 * <xsl:element
882 * name = { qname }
883 * namespace = { uri-reference }
884 * use-attribute-sets = qnames>
885 * <!-- Content: template -->
886 * </xsl:element>
887 */
888 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
889 return;
890
891 #ifdef XSLT_REFACTORED
892 comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
893 #else
894 comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
895 #endif
896
897 if (comp == NULL)
898 return;
899 inst->psvi = comp;
900 comp->inst = inst;
901
902 /*
903 * Attribute "name".
904 */
905 /*
906 * TODO: Precompile the AVT. See bug #344894.
907 */
908 comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
909 (const xmlChar *)"name", NULL, &comp->has_name);
910 if (! comp->has_name) {
911 xsltTransformError(NULL, style, inst,
912 "xsl:element: The attribute 'name' is missing.\n");
913 style->errors++;
914 goto error;
915 }
916 /*
917 * Attribute "namespace".
918 */
919 /*
920 * TODO: Precompile the AVT. See bug #344894.
921 */
922 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
923 (const xmlChar *)"namespace", NULL, &comp->has_ns);
924
925 if (comp->name != NULL) {
926 if (xmlValidateQName(comp->name, 0)) {
927 xsltTransformError(NULL, style, inst,
928 "xsl:element: The value '%s' of the attribute 'name' is "
929 "not a valid QName.\n", comp->name);
930 style->errors++;
931 } else {
932 const xmlChar *prefix = NULL, *name;
933
934 name = xsltSplitQName(style->dict, comp->name, &prefix);
935 if (comp->has_ns == 0) {
936 xmlNsPtr ns;
937
938 /*
939 * SPEC XSLT 1.0:
940 * "If the namespace attribute is not present, then the QName is
941 * expanded into an expanded-name using the namespace declarations
942 * in effect for the xsl:element element, including any default
943 * namespace declaration.
944 */
945 ns = xmlSearchNs(inst->doc, inst, prefix);
946 if (ns != NULL) {
947 comp->ns = xmlDictLookup(style->dict, ns->href, -1);
948 comp->has_ns = 1;
949 #ifdef XSLT_REFACTORED
950 comp->nsPrefix = prefix;
951 comp->name = name;
952 #endif
953 } else if (prefix != NULL) {
954 xsltTransformError(NULL, style, inst,
955 "xsl:element: The prefixed QName '%s' "
956 "has no namespace binding in scope in the "
957 "stylesheet; this is an error, since the namespace was "
958 "not specified by the instruction itself.\n", comp->name);
959 style->errors++;
960 }
961 }
962 if ((prefix != NULL) &&
963 (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
964 {
965 /*
966 * Mark is to be skipped.
967 */
968 comp->has_name = 0;
969 }
970 }
971 }
972 /*
973 * Attribute "use-attribute-sets",
974 */
975 comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
976 (const xmlChar *)"use-attribute-sets",
977 NULL, &comp->has_use);
978
979 error:
980 return;
981 }
982
983 /**
984 * xsltAttributeComp:
985 * @style: an XSLT compiled stylesheet
986 * @inst: the xslt attribute node
987 *
988 * Process the xslt attribute node on the source node
989 */
990 static void
991 xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
992 #ifdef XSLT_REFACTORED
993 xsltStyleItemAttributePtr comp;
994 #else
995 xsltStylePreCompPtr comp;
996 #endif
997
998 /*
999 * <xsl:attribute
1000 * name = { qname }
1001 * namespace = { uri-reference }>
1002 * <!-- Content: template -->
1003 * </xsl:attribute>
1004 */
1005 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1006 return;
1007
1008 #ifdef XSLT_REFACTORED
1009 comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,
1010 XSLT_FUNC_ATTRIBUTE);
1011 #else
1012 comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
1013 #endif
1014
1015 if (comp == NULL)
1016 return;
1017 inst->psvi = comp;
1018 comp->inst = inst;
1019
1020 /*
1021 * Attribute "name".
1022 */
1023 /*
1024 * TODO: Precompile the AVT. See bug #344894.
1025 */
1026 comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
1027 (const xmlChar *)"name",
1028 NULL, &comp->has_name);
1029 if (! comp->has_name) {
1030 xsltTransformError(NULL, style, inst,
1031 "XSLT-attribute: The attribute 'name' is missing.\n");
1032 style->errors++;
1033 return;
1034 }
1035 /*
1036 * Attribute "namespace".
1037 */
1038 /*
1039 * TODO: Precompile the AVT. See bug #344894.
1040 */
1041 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
1042 (const xmlChar *)"namespace",
1043 NULL, &comp->has_ns);
1044
1045 if (comp->name != NULL) {
1046 if (xmlValidateQName(comp->name, 0)) {
1047 xsltTransformError(NULL, style, inst,
1048 "xsl:attribute: The value '%s' of the attribute 'name' is "
1049 "not a valid QName.\n", comp->name);
1050 style->errors++;
1051 } else if (xmlStrEqual(comp->name, BAD_CAST "xmlns")) {
1052 xsltTransformError(NULL, style, inst,
1053 "xsl:attribute: The attribute name 'xmlns' is not allowed.\n");
1054 style->errors++;
1055 } else {
1056 const xmlChar *prefix = NULL, *name;
1057
1058 name = xsltSplitQName(style->dict, comp->name, &prefix);
1059 if (prefix != NULL) {
1060 if (comp->has_ns == 0) {
1061 xmlNsPtr ns;
1062
1063 /*
1064 * SPEC XSLT 1.0:
1065 * "If the namespace attribute is not present, then the
1066 * QName is expanded into an expanded-name using the
1067 * namespace declarations in effect for the xsl:element
1068 * element, including any default namespace declaration.
1069 */
1070 ns = xmlSearchNs(inst->doc, inst, prefix);
1071 if (ns != NULL) {
1072 comp->ns = xmlDictLookup(style->dict, ns->href, -1);
1073 comp->has_ns = 1;
1074 #ifdef XSLT_REFACTORED
1075 comp->nsPrefix = prefix;
1076 comp->name = name;
1077 #endif
1078 } else {
1079 xsltTransformError(NULL, style, inst,
1080 "xsl:attribute: The prefixed QName '%s' "
1081 "has no namespace binding in scope in the "
1082 "stylesheet; this is an error, since the "
1083 "namespace was not specified by the instruction "
1084 "itself.\n", comp->name);
1085 style->errors++;
1086 }
1087 }
1088 }
1089 }
1090 }
1091 }
1092
1093 /**
1094 * xsltCommentComp:
1095 * @style: an XSLT compiled stylesheet
1096 * @inst: the xslt comment node
1097 *
1098 * Process the xslt comment node on the source node
1099 */
1100 static void
1101 xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1102 #ifdef XSLT_REFACTORED
1103 xsltStyleItemCommentPtr comp;
1104 #else
1105 xsltStylePreCompPtr comp;
1106 #endif
1107
1108 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1109 return;
1110
1111 #ifdef XSLT_REFACTORED
1112 comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
1113 #else
1114 comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
1115 #endif
1116
1117 if (comp == NULL)
1118 return;
1119 inst->psvi = comp;
1120 comp->inst = inst;
1121 }
1122
1123 /**
1124 * xsltProcessingInstructionComp:
1125 * @style: an XSLT compiled stylesheet
1126 * @inst: the xslt processing-instruction node
1127 *
1128 * Process the xslt processing-instruction node on the source node
1129 */
1130 static void
1131 xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1132 #ifdef XSLT_REFACTORED
1133 xsltStyleItemPIPtr comp;
1134 #else
1135 xsltStylePreCompPtr comp;
1136 #endif
1137
1138 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1139 return;
1140
1141 #ifdef XSLT_REFACTORED
1142 comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI);
1143 #else
1144 comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
1145 #endif
1146
1147 if (comp == NULL)
1148 return;
1149 inst->psvi = comp;
1150 comp->inst = inst;
1151
1152 comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
1153 (const xmlChar *)"name",
1154 XSLT_NAMESPACE, &comp->has_name);
1155 }
1156
1157 /**
1158 * xsltCopyOfComp:
1159 * @style: an XSLT compiled stylesheet
1160 * @inst: the xslt copy-of node
1161 *
1162 * Process the xslt copy-of node on the source node
1163 */
1164 static void
1165 xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1166 #ifdef XSLT_REFACTORED
1167 xsltStyleItemCopyOfPtr comp;
1168 #else
1169 xsltStylePreCompPtr comp;
1170 #endif
1171
1172 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1173 return;
1174
1175 #ifdef XSLT_REFACTORED
1176 comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
1177 #else
1178 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
1179 #endif
1180
1181 if (comp == NULL)
1182 return;
1183 inst->psvi = comp;
1184 comp->inst = inst;
1185
1186 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1187 XSLT_NAMESPACE);
1188 if (comp->select == NULL) {
1189 xsltTransformError(NULL, style, inst,
1190 "xsl:copy-of : select is missing\n");
1191 if (style != NULL) style->errors++;
1192 return;
1193 }
1194 comp->comp = xsltXPathCompile(style, comp->select);
1195 if (comp->comp == NULL) {
1196 xsltTransformError(NULL, style, inst,
1197 "xsl:copy-of : could not compile select expression '%s'\n",
1198 comp->select);
1199 if (style != NULL) style->errors++;
1200 }
1201 }
1202
1203 /**
1204 * xsltValueOfComp:
1205 * @style: an XSLT compiled stylesheet
1206 * @inst: the xslt value-of node
1207 *
1208 * Process the xslt value-of node on the source node
1209 */
1210 static void
1211 xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1212 #ifdef XSLT_REFACTORED
1213 xsltStyleItemValueOfPtr comp;
1214 #else
1215 xsltStylePreCompPtr comp;
1216 #endif
1217 const xmlChar *prop;
1218
1219 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1220 return;
1221
1222 #ifdef XSLT_REFACTORED
1223 comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
1224 #else
1225 comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
1226 #endif
1227
1228 if (comp == NULL)
1229 return;
1230 inst->psvi = comp;
1231 comp->inst = inst;
1232
1233 prop = xsltGetCNsProp(style, inst,
1234 (const xmlChar *)"disable-output-escaping",
1235 XSLT_NAMESPACE);
1236 if (prop != NULL) {
1237 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1238 comp->noescape = 1;
1239 } else if (!xmlStrEqual(prop,
1240 (const xmlChar *)"no")){
1241 xsltTransformError(NULL, style, inst,
1242 "xsl:value-of : disable-output-escaping allows only yes or no\n");
1243 if (style != NULL) style->warnings++;
1244 }
1245 }
1246 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1247 XSLT_NAMESPACE);
1248 if (comp->select == NULL) {
1249 xsltTransformError(NULL, style, inst,
1250 "xsl:value-of : select is missing\n");
1251 if (style != NULL) style->errors++;
1252 return;
1253 }
1254 comp->comp = xsltXPathCompile(style, comp->select);
1255 if (comp->comp == NULL) {
1256 xsltTransformError(NULL, style, inst,
1257 "xsl:value-of : could not compile select expression '%s'\n",
1258 comp->select);
1259 if (style != NULL) style->errors++;
1260 }
1261 }
1262
1263 static void
1264 xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst,
1265 const xmlChar *propName,
1266 int mandatory,
1267 int *hasProp, const xmlChar **nsName,
1268 const xmlChar** localName)
1269 {
1270 const xmlChar *prop;
1271
1272 if (nsName)
1273 *nsName = NULL;
1274 if (localName)
1275 *localName = NULL;
1276 if (hasProp)
1277 *hasProp = 0;
1278
1279 prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE);
1280 if (prop == NULL) {
1281 if (mandatory) {
1282 xsltTransformError(NULL, style, inst,
1283 "The attribute '%s' is missing.\n", propName);
1284 style->errors++;
1285 return;
1286 }
1287 } else {
1288 const xmlChar *URI;
1289
1290 if (xmlValidateQName(prop, 0)) {
1291 xsltTransformError(NULL, style, inst,
1292 "The value '%s' of the attribute "
1293 "'%s' is not a valid QName.\n", prop, propName);
1294 style->errors++;
1295 return;
1296 } else {
1297 /*
1298 * @prop will be in the string dict afterwards, @URI not.
1299 */
1300 URI = xsltGetQNameURI2(style, inst, &prop);
1301 if (prop == NULL) {
1302 style->errors++;
1303 } else {
1304 *localName = prop;
1305 if (hasProp)
1306 *hasProp = 1;
1307 if (URI != NULL) {
1308 /*
1309 * Fixes bug #308441: Put the ns-name in the dict
1310 * in order to pointer compare names during XPath's
1311 * variable lookup.
1312 */
1313 if (nsName)
1314 *nsName = xmlDictLookup(style->dict, URI, -1);
1315 /* comp->has_ns = 1; */
1316 }
1317 }
1318 }
1319 }
1320 return;
1321 }
1322
1323 /**
1324 * xsltWithParamComp:
1325 * @style: an XSLT compiled stylesheet
1326 * @inst: the xslt with-param node
1327 *
1328 * Process the xslt with-param node on the source node
1329 * Allowed parents: xsl:call-template, xsl:apply-templates.
1330 * <xsl:with-param
1331 * name = qname
1332 * select = expression>
1333 * <!-- Content: template -->
1334 * </xsl:with-param>
1335 */
1336 static void
1337 xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1338 #ifdef XSLT_REFACTORED
1339 xsltStyleItemWithParamPtr comp;
1340 #else
1341 xsltStylePreCompPtr comp;
1342 #endif
1343
1344 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1345 return;
1346
1347 #ifdef XSLT_REFACTORED
1348 comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
1349 #else
1350 comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
1351 #endif
1352
1353 if (comp == NULL)
1354 return;
1355 inst->psvi = comp;
1356 comp->inst = inst;
1357
1358 /*
1359 * Attribute "name".
1360 */
1361 xsltGetQNameProperty(style, inst, BAD_CAST "name",
1362 1, &(comp->has_name), &(comp->ns), &(comp->name));
1363 if (comp->ns)
1364 comp->has_ns = 1;
1365 /*
1366 * Attribute "select".
1367 */
1368 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1369 XSLT_NAMESPACE);
1370 if (comp->select != NULL) {
1371 comp->comp = xsltXPathCompile(style, comp->select);
1372 if (comp->comp == NULL) {
1373 xsltTransformError(NULL, style, inst,
1374 "XSLT-with-param: Failed to compile select "
1375 "expression '%s'\n", comp->select);
1376 style->errors++;
1377 }
1378 if (inst->children != NULL) {
1379 xsltTransformError(NULL, style, inst,
1380 "XSLT-with-param: The content should be empty since "
1381 "the attribute select is present.\n");
1382 style->warnings++;
1383 }
1384 }
1385 }
1386
1387 /**
1388 * xsltNumberComp:
1389 * @style: an XSLT compiled stylesheet
1390 * @cur: the xslt number node
1391 *
1392 * Process the xslt number node on the source node
1393 */
1394 static void
1395 xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
1396 #ifdef XSLT_REFACTORED
1397 xsltStyleItemNumberPtr comp;
1398 #else
1399 xsltStylePreCompPtr comp;
1400 #endif
1401 const xmlChar *prop;
1402
1403 if ((style == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1404 return;
1405
1406 #ifdef XSLT_REFACTORED
1407 comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
1408 #else
1409 comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
1410 #endif
1411
1412 if (comp == NULL)
1413 return;
1414 cur->psvi = comp;
1415
1416 if ((style == NULL) || (cur == NULL))
1417 return;
1418
1419 comp->numdata.doc = cur->doc;
1420 comp->numdata.node = cur;
1421 comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
1422 XSLT_NAMESPACE);
1423
1424 prop = xsltEvalStaticAttrValueTemplate(style, cur,
1425 (const xmlChar *)"format",
1426 XSLT_NAMESPACE, &comp->numdata.has_format);
1427 if (comp->numdata.has_format == 0) {
1428 comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0);
1429 } else {
1430 comp->numdata.format = prop;
1431 }
1432
1433 comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",
1434 XSLT_NAMESPACE);
1435 comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",
1436 XSLT_NAMESPACE);
1437
1438 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE);
1439 if (prop != NULL) {
1440 comp->numdata.countPat = xsltCompilePattern(prop, cur->doc, cur, style,
1441 NULL);
1442 }
1443
1444 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE);
1445 if (prop != NULL) {
1446 comp->numdata.fromPat = xsltCompilePattern(prop, cur->doc, cur, style,
1447 NULL);
1448 }
1449
1450 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);
1451 if (prop != NULL) {
1452 if (xmlStrEqual(prop, BAD_CAST("single")) ||
1453 xmlStrEqual(prop, BAD_CAST("multiple")) ||
1454 xmlStrEqual(prop, BAD_CAST("any"))) {
1455 comp->numdata.level = prop;
1456 } else {
1457 xsltTransformError(NULL, style, cur,
1458 "xsl:number : invalid value %s for level\n", prop);
1459 if (style != NULL) style->warnings++;
1460 }
1461 }
1462
1463 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
1464 if (prop != NULL) {
1465 xsltTransformError(NULL, style, cur,
1466 "xsl:number : lang attribute not implemented\n");
1467 XSLT_TODO; /* xsl:number lang attribute */
1468 }
1469
1470 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
1471 if (prop != NULL) {
1472 if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
1473 xsltTransformError(NULL, style, cur,
1474 "xsl:number : letter-value 'alphabetic' not implemented\n");
1475 if (style != NULL) style->warnings++;
1476 XSLT_TODO; /* xsl:number letter-value attribute alphabetic */
1477 } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
1478 xsltTransformError(NULL, style, cur,
1479 "xsl:number : letter-value 'traditional' not implemented\n");
1480 if (style != NULL) style->warnings++;
1481 XSLT_TODO; /* xsl:number letter-value attribute traditional */
1482 } else {
1483 xsltTransformError(NULL, style, cur,
1484 "xsl:number : invalid value %s for letter-value\n", prop);
1485 if (style != NULL) style->warnings++;
1486 }
1487 }
1488
1489 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",
1490 XSLT_NAMESPACE);
1491 if (prop != NULL) {
1492 comp->numdata.groupingCharacterLen = xmlStrlen(prop);
1493 comp->numdata.groupingCharacter =
1494 xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));
1495 }
1496
1497 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
1498 if (prop != NULL) {
1499 sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
1500 } else {
1501 comp->numdata.groupingCharacter = 0;
1502 }
1503
1504 /* Set default values */
1505 if (comp->numdata.value == NULL) {
1506 if (comp->numdata.level == NULL) {
1507 comp->numdata.level = xmlDictLookup(style->dict,
1508 BAD_CAST"single", 6);
1509 }
1510 }
1511
1512 }
1513
1514 /**
1515 * xsltApplyImportsComp:
1516 * @style: an XSLT compiled stylesheet
1517 * @inst: the xslt apply-imports node
1518 *
1519 * Process the xslt apply-imports node on the source node
1520 */
1521 static void
1522 xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1523 #ifdef XSLT_REFACTORED
1524 xsltStyleItemApplyImportsPtr comp;
1525 #else
1526 xsltStylePreCompPtr comp;
1527 #endif
1528
1529 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1530 return;
1531
1532 #ifdef XSLT_REFACTORED
1533 comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
1534 #else
1535 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
1536 #endif
1537
1538 if (comp == NULL)
1539 return;
1540 inst->psvi = comp;
1541 comp->inst = inst;
1542 }
1543
1544 /**
1545 * xsltCallTemplateComp:
1546 * @style: an XSLT compiled stylesheet
1547 * @inst: the xslt call-template node
1548 *
1549 * Process the xslt call-template node on the source node
1550 */
1551 static void
1552 xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1553 #ifdef XSLT_REFACTORED
1554 xsltStyleItemCallTemplatePtr comp;
1555 #else
1556 xsltStylePreCompPtr comp;
1557 #endif
1558
1559 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1560 return;
1561
1562 #ifdef XSLT_REFACTORED
1563 comp = (xsltStyleItemCallTemplatePtr)
1564 xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
1565 #else
1566 comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
1567 #endif
1568
1569 if (comp == NULL)
1570 return;
1571 inst->psvi = comp;
1572 comp->inst = inst;
1573
1574 /*
1575 * Attribute "name".
1576 */
1577 xsltGetQNameProperty(style, inst, BAD_CAST "name",
1578 1, &(comp->has_name), &(comp->ns), &(comp->name));
1579 if (comp->ns)
1580 comp->has_ns = 1;
1581 }
1582
1583 /**
1584 * xsltApplyTemplatesComp:
1585 * @style: an XSLT compiled stylesheet
1586 * @inst: the apply-templates node
1587 *
1588 * Process the apply-templates node on the source node
1589 */
1590 static void
1591 xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1592 #ifdef XSLT_REFACTORED
1593 xsltStyleItemApplyTemplatesPtr comp;
1594 #else
1595 xsltStylePreCompPtr comp;
1596 #endif
1597
1598 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1599 return;
1600
1601 #ifdef XSLT_REFACTORED
1602 comp = (xsltStyleItemApplyTemplatesPtr)
1603 xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
1604 #else
1605 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
1606 #endif
1607
1608 if (comp == NULL)
1609 return;
1610 inst->psvi = comp;
1611 comp->inst = inst;
1612
1613 /*
1614 * Attribute "mode".
1615 */
1616 xsltGetQNameProperty(style, inst, BAD_CAST "mode",
1617 0, NULL, &(comp->modeURI), &(comp->mode));
1618 /*
1619 * Attribute "select".
1620 */
1621 comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select",
1622 XSLT_NAMESPACE);
1623 if (comp->select != NULL) {
1624 comp->comp = xsltXPathCompile(style, comp->select);
1625 if (comp->comp == NULL) {
1626 xsltTransformError(NULL, style, inst,
1627 "XSLT-apply-templates: could not compile select "
1628 "expression '%s'\n", comp->select);
1629 style->errors++;
1630 }
1631 }
1632 /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
1633 }
1634
1635 /**
1636 * xsltChooseComp:
1637 * @style: an XSLT compiled stylesheet
1638 * @inst: the xslt choose node
1639 *
1640 * Process the xslt choose node on the source node
1641 */
1642 static void
1643 xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1644 #ifdef XSLT_REFACTORED
1645 xsltStyleItemChoosePtr comp;
1646 #else
1647 xsltStylePreCompPtr comp;
1648 #endif
1649
1650 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1651 return;
1652
1653 #ifdef XSLT_REFACTORED
1654 comp = (xsltStyleItemChoosePtr)
1655 xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
1656 #else
1657 comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
1658 #endif
1659
1660 if (comp == NULL)
1661 return;
1662 inst->psvi = comp;
1663 comp->inst = inst;
1664 }
1665
1666 /**
1667 * xsltIfComp:
1668 * @style: an XSLT compiled stylesheet
1669 * @inst: the xslt if node
1670 *
1671 * Process the xslt if node on the source node
1672 */
1673 static void
1674 xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1675 #ifdef XSLT_REFACTORED
1676 xsltStyleItemIfPtr comp;
1677 #else
1678 xsltStylePreCompPtr comp;
1679 #endif
1680
1681 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1682 return;
1683
1684 #ifdef XSLT_REFACTORED
1685 comp = (xsltStyleItemIfPtr)
1686 xsltNewStylePreComp(style, XSLT_FUNC_IF);
1687 #else
1688 comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
1689 #endif
1690
1691 if (comp == NULL)
1692 return;
1693 inst->psvi = comp;
1694 comp->inst = inst;
1695
1696 comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
1697 if (comp->test == NULL) {
1698 xsltTransformError(NULL, style, inst,
1699 "xsl:if : test is not defined\n");
1700 if (style != NULL) style->errors++;
1701 return;
1702 }
1703 comp->comp = xsltXPathCompile(style, comp->test);
1704 if (comp->comp == NULL) {
1705 xsltTransformError(NULL, style, inst,
1706 "xsl:if : could not compile test expression '%s'\n",
1707 comp->test);
1708 if (style != NULL) style->errors++;
1709 }
1710 }
1711
1712 /**
1713 * xsltWhenComp:
1714 * @style: an XSLT compiled stylesheet
1715 * @inst: the xslt if node
1716 *
1717 * Process the xslt if node on the source node
1718 */
1719 static void
1720 xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1721 #ifdef XSLT_REFACTORED
1722 xsltStyleItemWhenPtr comp;
1723 #else
1724 xsltStylePreCompPtr comp;
1725 #endif
1726
1727 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1728 return;
1729
1730 #ifdef XSLT_REFACTORED
1731 comp = (xsltStyleItemWhenPtr)
1732 xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
1733 #else
1734 comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
1735 #endif
1736
1737 if (comp == NULL)
1738 return;
1739 inst->psvi = comp;
1740 comp->inst = inst;
1741
1742 comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
1743 if (comp->test == NULL) {
1744 xsltTransformError(NULL, style, inst,
1745 "xsl:when : test is not defined\n");
1746 if (style != NULL) style->errors++;
1747 return;
1748 }
1749 comp->comp = xsltXPathCompile(style, comp->test);
1750 if (comp->comp == NULL) {
1751 xsltTransformError(NULL, style, inst,
1752 "xsl:when : could not compile test expression '%s'\n",
1753 comp->test);
1754 if (style != NULL) style->errors++;
1755 }
1756 }
1757
1758 /**
1759 * xsltForEachComp:
1760 * @style: an XSLT compiled stylesheet
1761 * @inst: the xslt for-each node
1762 *
1763 * Process the xslt for-each node on the source node
1764 */
1765 static void
1766 xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1767 #ifdef XSLT_REFACTORED
1768 xsltStyleItemForEachPtr comp;
1769 #else
1770 xsltStylePreCompPtr comp;
1771 #endif
1772
1773 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1774 return;
1775
1776 #ifdef XSLT_REFACTORED
1777 comp = (xsltStyleItemForEachPtr)
1778 xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1779 #else
1780 comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1781 #endif
1782
1783 if (comp == NULL)
1784 return;
1785 inst->psvi = comp;
1786 comp->inst = inst;
1787
1788 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1789 XSLT_NAMESPACE);
1790 if (comp->select == NULL) {
1791 xsltTransformError(NULL, style, inst,
1792 "xsl:for-each : select is missing\n");
1793 if (style != NULL) style->errors++;
1794 } else {
1795 comp->comp = xsltXPathCompile(style, comp->select);
1796 if (comp->comp == NULL) {
1797 xsltTransformError(NULL, style, inst,
1798 "xsl:for-each : could not compile select expression '%s'\n",
1799 comp->select);
1800 if (style != NULL) style->errors++;
1801 }
1802 }
1803 /* TODO: handle and skip the xsl:sort */
1804 }
1805
1806 /**
1807 * xsltVariableComp:
1808 * @style: an XSLT compiled stylesheet
1809 * @inst: the xslt variable node
1810 *
1811 * Process the xslt variable node on the source node
1812 */
1813 static void
1814 xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1815 #ifdef XSLT_REFACTORED
1816 xsltStyleItemVariablePtr comp;
1817 #else
1818 xsltStylePreCompPtr comp;
1819 #endif
1820
1821 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1822 return;
1823
1824 #ifdef XSLT_REFACTORED
1825 comp = (xsltStyleItemVariablePtr)
1826 xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1827 #else
1828 comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1829 #endif
1830
1831 if (comp == NULL)
1832 return;
1833
1834 inst->psvi = comp;
1835 comp->inst = inst;
1836 /*
1837 * The full template resolution can be done statically
1838 */
1839
1840 /*
1841 * Attribute "name".
1842 */
1843 xsltGetQNameProperty(style, inst, BAD_CAST "name",
1844 1, &(comp->has_name), &(comp->ns), &(comp->name));
1845 if (comp->ns)
1846 comp->has_ns = 1;
1847 /*
1848 * Attribute "select".
1849 */
1850 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1851 XSLT_NAMESPACE);
1852 if (comp->select != NULL) {
1853 #ifndef XSLT_REFACTORED
1854 xmlNodePtr cur;
1855 #endif
1856 comp->comp = xsltXPathCompile(style, comp->select);
1857 if (comp->comp == NULL) {
1858 xsltTransformError(NULL, style, inst,
1859 "XSLT-variable: Failed to compile the XPath expression '%s'.\n",
1860 comp->select);
1861 style->errors++;
1862 }
1863 #ifdef XSLT_REFACTORED
1864 if (inst->children != NULL) {
1865 xsltTransformError(NULL, style, inst,
1866 "XSLT-variable: There must be no child nodes, since the "
1867 "attribute 'select' was specified.\n");
1868 style->errors++;
1869 }
1870 #else
1871 for (cur = inst->children; cur != NULL; cur = cur->next) {
1872 if (cur->type != XML_COMMENT_NODE &&
1873 (cur->type != XML_TEXT_NODE || !xsltIsBlank(cur->content)))
1874 {
1875 xsltTransformError(NULL, style, inst,
1876 "XSLT-variable: There must be no child nodes, since the "
1877 "attribute 'select' was specified.\n");
1878 style->errors++;
1879 }
1880 }
1881 #endif
1882 }
1883 }
1884
1885 /**
1886 * xsltParamComp:
1887 * @style: an XSLT compiled stylesheet
1888 * @inst: the xslt param node
1889 *
1890 * Process the xslt param node on the source node
1891 */
1892 static void
1893 xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1894 #ifdef XSLT_REFACTORED
1895 xsltStyleItemParamPtr comp;
1896 #else
1897 xsltStylePreCompPtr comp;
1898 #endif
1899
1900 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1901 return;
1902
1903 #ifdef XSLT_REFACTORED
1904 comp = (xsltStyleItemParamPtr)
1905 xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1906 #else
1907 comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1908 #endif
1909
1910 if (comp == NULL)
1911 return;
1912 inst->psvi = comp;
1913 comp->inst = inst;
1914
1915 /*
1916 * Attribute "name".
1917 */
1918 xsltGetQNameProperty(style, inst, BAD_CAST "name",
1919 1, &(comp->has_name), &(comp->ns), &(comp->name));
1920 if (comp->ns)
1921 comp->has_ns = 1;
1922 /*
1923 * Attribute "select".
1924 */
1925 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1926 XSLT_NAMESPACE);
1927 if (comp->select != NULL) {
1928 comp->comp = xsltXPathCompile(style, comp->select);
1929 if (comp->comp == NULL) {
1930 xsltTransformError(NULL, style, inst,
1931 "XSLT-param: could not compile select expression '%s'.\n",
1932 comp->select);
1933 style->errors++;
1934 }
1935 if (inst->children != NULL) {
1936 xsltTransformError(NULL, style, inst,
1937 "XSLT-param: The content should be empty since the "
1938 "attribute 'select' is present.\n");
1939 style->warnings++;
1940 }
1941 }
1942 }
1943
1944 /************************************************************************
1945 * *
1946 * Generic interface *
1947 * *
1948 ************************************************************************/
1949
1950 /**
1951 * xsltFreeStylePreComps:
1952 * @style: an XSLT transformation context
1953 *
1954 * Free up the memory allocated by all precomputed blocks
1955 */
1956 void
1957 xsltFreeStylePreComps(xsltStylesheetPtr style) {
1958 xsltElemPreCompPtr cur, next;
1959
1960 if (style == NULL)
1961 return;
1962
1963 cur = style->preComps;
1964 while (cur != NULL) {
1965 next = cur->next;
1966 if (cur->type == XSLT_FUNC_EXTENSION)
1967 cur->free(cur);
1968 else
1969 xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
1970 cur = next;
1971 }
1972 }
1973
1974 #ifdef XSLT_REFACTORED
1975
1976 /**
1977 * xsltStylePreCompute:
1978 * @style: the XSLT stylesheet
1979 * @node: the element in the XSLT namespace
1980 *
1981 * Precompute an XSLT element.
1982 * This expects the type of the element to be already
1983 * set in style->compCtxt->inode->type;
1984 */
1985 void
1986 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) {
1987 /*
1988 * The xsltXSLTElemMarker marker was set beforehand by
1989 * the parsing mechanism for all elements in the XSLT namespace.
1990 */
1991 if (style == NULL) {
1992 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
1993 node->psvi = NULL;
1994 return;
1995 }
1996 if (node == NULL)
1997 return;
1998 if (! IS_XSLT_ELEM_FAST(node))
1999 return;
2000
2001 node->psvi = NULL;
2002 if (XSLT_CCTXT(style)->inode->type != 0) {
2003 switch (XSLT_CCTXT(style)->inode->type) {
2004 case XSLT_FUNC_APPLYTEMPLATES:
2005 xsltApplyTemplatesComp(style, node);
2006 break;
2007 case XSLT_FUNC_WITHPARAM:
2008 xsltWithParamComp(style, node);
2009 break;
2010 case XSLT_FUNC_VALUEOF:
2011 xsltValueOfComp(style, node);
2012 break;
2013 case XSLT_FUNC_COPY:
2014 xsltCopyComp(style, node);
2015 break;
2016 case XSLT_FUNC_COPYOF:
2017 xsltCopyOfComp(style, node);
2018 break;
2019 case XSLT_FUNC_IF:
2020 xsltIfComp(style, node);
2021 break;
2022 case XSLT_FUNC_CHOOSE:
2023 xsltChooseComp(style, node);
2024 break;
2025 case XSLT_FUNC_WHEN:
2026 xsltWhenComp(style, node);
2027 break;
2028 case XSLT_FUNC_OTHERWISE:
2029 /* NOP yet */
2030 return;
2031 case XSLT_FUNC_FOREACH:
2032 xsltForEachComp(style, node);
2033 break;
2034 case XSLT_FUNC_APPLYIMPORTS:
2035 xsltApplyImportsComp(style, node);
2036 break;
2037 case XSLT_FUNC_ATTRIBUTE:
2038 xsltAttributeComp(style, node);
2039 break;
2040 case XSLT_FUNC_ELEMENT:
2041 xsltElementComp(style, node);
2042 break;
2043 case XSLT_FUNC_SORT:
2044 xsltSortComp(style, node);
2045 break;
2046 case XSLT_FUNC_COMMENT:
2047 xsltCommentComp(style, node);
2048 break;
2049 case XSLT_FUNC_NUMBER:
2050 xsltNumberComp(style, node);
2051 break;
2052 case XSLT_FUNC_PI:
2053 xsltProcessingInstructionComp(style, node);
2054 break;
2055 case XSLT_FUNC_CALLTEMPLATE:
2056 xsltCallTemplateComp(style, node);
2057 break;
2058 case XSLT_FUNC_PARAM:
2059 xsltParamComp(style, node);
2060 break;
2061 case XSLT_FUNC_VARIABLE:
2062 xsltVariableComp(style, node);
2063 break;
2064 case XSLT_FUNC_FALLBACK:
2065 /* NOP yet */
2066 return;
2067 case XSLT_FUNC_DOCUMENT:
2068 /* The extra one */
2069 node->psvi = (void *) xsltDocumentComp(style, node,
2070 (xsltTransformFunction) xsltDocumentElem);
2071 break;
2072 case XSLT_FUNC_MESSAGE:
2073 /* NOP yet */
2074 return;
2075 default:
2076 /*
2077 * NOTE that xsl:text, xsl:template, xsl:stylesheet,
2078 * xsl:transform, xsl:import, xsl:include are not expected
2079 * to be handed over to this function.
2080 */
2081 xsltTransformError(NULL, style, node,
2082 "Internal error: (xsltStylePreCompute) cannot handle "
2083 "the XSLT element '%s'.\n", node->name);
2084 style->errors++;
2085 return;
2086 }
2087 } else {
2088 /*
2089 * Fallback to string comparison.
2090 */
2091 if (IS_XSLT_NAME(node, "apply-templates")) {
2092 xsltApplyTemplatesComp(style, node);
2093 } else if (IS_XSLT_NAME(node, "with-param")) {
2094 xsltWithParamComp(style, node);
2095 } else if (IS_XSLT_NAME(node, "value-of")) {
2096 xsltValueOfComp(style, node);
2097 } else if (IS_XSLT_NAME(node, "copy")) {
2098 xsltCopyComp(style, node);
2099 } else if (IS_XSLT_NAME(node, "copy-of")) {
2100 xsltCopyOfComp(style, node);
2101 } else if (IS_XSLT_NAME(node, "if")) {
2102 xsltIfComp(style, node);
2103 } else if (IS_XSLT_NAME(node, "choose")) {
2104 xsltChooseComp(style, node);
2105 } else if (IS_XSLT_NAME(node, "when")) {
2106 xsltWhenComp(style, node);
2107 } else if (IS_XSLT_NAME(node, "otherwise")) {
2108 /* NOP yet */
2109 return;
2110 } else if (IS_XSLT_NAME(node, "for-each")) {
2111 xsltForEachComp(style, node);
2112 } else if (IS_XSLT_NAME(node, "apply-imports")) {
2113 xsltApplyImportsComp(style, node);
2114 } else if (IS_XSLT_NAME(node, "attribute")) {
2115 xsltAttributeComp(style, node);
2116 } else if (IS_XSLT_NAME(node, "element")) {
2117 xsltElementComp(style, node);
2118 } else if (IS_XSLT_NAME(node, "sort")) {
2119 xsltSortComp(style, node);
2120 } else if (IS_XSLT_NAME(node, "comment")) {
2121 xsltCommentComp(style, node);
2122 } else if (IS_XSLT_NAME(node, "number")) {
2123 xsltNumberComp(style, node);
2124 } else if (IS_XSLT_NAME(node, "processing-instruction")) {
2125 xsltProcessingInstructionComp(style, node);
2126 } else if (IS_XSLT_NAME(node, "call-template")) {
2127 xsltCallTemplateComp(style, node);
2128 } else if (IS_XSLT_NAME(node, "param")) {
2129 xsltParamComp(style, node);
2130 } else if (IS_XSLT_NAME(node, "variable")) {
2131 xsltVariableComp(style, node);
2132 } else if (IS_XSLT_NAME(node, "fallback")) {
2133 /* NOP yet */
2134 return;
2135 } else if (IS_XSLT_NAME(node, "document")) {
2136 /* The extra one */
2137 node->psvi = (void *) xsltDocumentComp(style, node,
2138 (xsltTransformFunction) xsltDocumentElem);
2139 } else if (IS_XSLT_NAME(node, "output")) {
2140 /* Top-level */
2141 return;
2142 } else if (IS_XSLT_NAME(node, "preserve-space")) {
2143 /* Top-level */
2144 return;
2145 } else if (IS_XSLT_NAME(node, "strip-space")) {
2146 /* Top-level */
2147 return;
2148 } else if (IS_XSLT_NAME(node, "key")) {
2149 /* Top-level */
2150 return;
2151 } else if (IS_XSLT_NAME(node, "message")) {
2152 return;
2153 } else if (IS_XSLT_NAME(node, "attribute-set")) {
2154 /* Top-level */
2155 return;
2156 } else if (IS_XSLT_NAME(node, "namespace-alias")) {
2157 /* Top-level */
2158 return;
2159 } else if (IS_XSLT_NAME(node, "decimal-format")) {
2160 /* Top-level */
2161 return;
2162 } else if (IS_XSLT_NAME(node, "include")) {
2163 /* Top-level */
2164 } else {
2165 /*
2166 * NOTE that xsl:text, xsl:template, xsl:stylesheet,
2167 * xsl:transform, xsl:import, xsl:include are not expected
2168 * to be handed over to this function.
2169 */
2170 xsltTransformError(NULL, style, node,
2171 "Internal error: (xsltStylePreCompute) cannot handle "
2172 "the XSLT element '%s'.\n", node->name);
2173 style->errors++;
2174 return;
2175 }
2176 }
2177 /*
2178 * Assign the current list of in-scope namespaces to the
2179 * item. This is needed for XPath expressions.
2180 */
2181 if (node->psvi != NULL) {
2182 ((xsltStylePreCompPtr) node->psvi)->inScopeNs =
2183 XSLT_CCTXT(style)->inode->inScopeNs;
2184 }
2185 }
2186
2187 #else
2188
2189 /**
2190 * xsltStylePreCompute:
2191 * @style: the XSLT stylesheet
2192 * @inst: the instruction in the stylesheet
2193 *
2194 * Precompute an XSLT stylesheet element
2195 */
2196 void
2197 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
2198 /*
2199 * URGENT TODO: Normally inst->psvi Should never be reserved here,
2200 * BUT: since if we include the same stylesheet from
2201 * multiple imports, then the stylesheet will be parsed
2202 * again. We simply must not try to compute the stylesheet again.
2203 * TODO: Get to the point where we don't need to query the
2204 * namespace- and local-name of the node, but can evaluate this
2205 * using cctxt->style->inode->category;
2206 */
2207 if ((inst == NULL) || (inst->type != XML_ELEMENT_NODE) ||
2208 (inst->psvi != NULL))
2209 return;
2210
2211 if (IS_XSLT_ELEM(inst)) {
2212 xsltStylePreCompPtr cur;
2213
2214 if (IS_XSLT_NAME(inst, "apply-templates")) {
2215 xsltCheckInstructionElement(style, inst);
2216 xsltApplyTemplatesComp(style, inst);
2217 } else if (IS_XSLT_NAME(inst, "with-param")) {
2218 xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
2219 BAD_CAST "call-template");
2220 xsltWithParamComp(style, inst);
2221 } else if (IS_XSLT_NAME(inst, "value-of")) {
2222 xsltCheckInstructionElement(style, inst);
2223 xsltValueOfComp(style, inst);
2224 } else if (IS_XSLT_NAME(inst, "copy")) {
2225 xsltCheckInstructionElement(style, inst);
2226 xsltCopyComp(style, inst);
2227 } else if (IS_XSLT_NAME(inst, "copy-of")) {
2228 xsltCheckInstructionElement(style, inst);
2229 xsltCopyOfComp(style, inst);
2230 } else if (IS_XSLT_NAME(inst, "if")) {
2231 xsltCheckInstructionElement(style, inst);
2232 xsltIfComp(style, inst);
2233 } else if (IS_XSLT_NAME(inst, "when")) {
2234 xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
2235 xsltWhenComp(style, inst);
2236 } else if (IS_XSLT_NAME(inst, "choose")) {
2237 xsltCheckInstructionElement(style, inst);
2238 xsltChooseComp(style, inst);
2239 } else if (IS_XSLT_NAME(inst, "for-each")) {
2240 xsltCheckInstructionElement(style, inst);
2241 xsltForEachComp(style, inst);
2242 } else if (IS_XSLT_NAME(inst, "apply-imports")) {
2243 xsltCheckInstructionElement(style, inst);
2244 xsltApplyImportsComp(style, inst);
2245 } else if (IS_XSLT_NAME(inst, "attribute")) {
2246 xmlNodePtr parent = inst->parent;
2247
2248 if ((parent == NULL) || (parent->ns == NULL) ||
2249 ((parent->ns != inst->ns) &&
2250 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
2251 (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) {
2252 xsltCheckInstructionElement(style, inst);
2253 }
2254 xsltAttributeComp(style, inst);
2255 } else if (IS_XSLT_NAME(inst, "element")) {
2256 xsltCheckInstructionElement(style, inst);
2257 xsltElementComp(style, inst);
2258 } else if (IS_XSLT_NAME(inst, "text")) {
2259 xsltCheckInstructionElement(style, inst);
2260 xsltTextComp(style, inst);
2261 } else if (IS_XSLT_NAME(inst, "sort")) {
2262 xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
2263 BAD_CAST "for-each");
2264 xsltSortComp(style, inst);
2265 } else if (IS_XSLT_NAME(inst, "comment")) {
2266 xsltCheckInstructionElement(style, inst);
2267 xsltCommentComp(style, inst);
2268 } else if (IS_XSLT_NAME(inst, "number")) {
2269 xsltCheckInstructionElement(style, inst);
2270 xsltNumberComp(style, inst);
2271 } else if (IS_XSLT_NAME(inst, "processing-instruction")) {
2272 xsltCheckInstructionElement(style, inst);
2273 xsltProcessingInstructionComp(style, inst);
2274 } else if (IS_XSLT_NAME(inst, "call-template")) {
2275 xsltCheckInstructionElement(style, inst);
2276 xsltCallTemplateComp(style, inst);
2277 } else if (IS_XSLT_NAME(inst, "param")) {
2278 if (xsltCheckTopLevelElement(style, inst, 0) == 0)
2279 xsltCheckInstructionElement(style, inst);
2280 xsltParamComp(style, inst);
2281 } else if (IS_XSLT_NAME(inst, "variable")) {
2282 if (xsltCheckTopLevelElement(style, inst, 0) == 0)
2283 xsltCheckInstructionElement(style, inst);
2284 xsltVariableComp(style, inst);
2285 } else if (IS_XSLT_NAME(inst, "otherwise")) {
2286 xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
2287 xsltCheckInstructionElement(style, inst);
2288 return;
2289 } else if (IS_XSLT_NAME(inst, "template")) {
2290 xsltCheckTopLevelElement(style, inst, 1);
2291 return;
2292 } else if (IS_XSLT_NAME(inst, "output")) {
2293 xsltCheckTopLevelElement(style, inst, 1);
2294 return;
2295 } else if (IS_XSLT_NAME(inst, "preserve-space")) {
2296 xsltCheckTopLevelElement(style, inst, 1);
2297 return;
2298 } else if (IS_XSLT_NAME(inst, "strip-space")) {
2299 xsltCheckTopLevelElement(style, inst, 1);
2300 return;
2301 } else if ((IS_XSLT_NAME(inst, "stylesheet")) ||
2302 (IS_XSLT_NAME(inst, "transform"))) {
2303 xmlNodePtr parent = inst->parent;
2304
2305 if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) {
2306 xsltTransformError(NULL, style, inst,
2307 "element %s only allowed only as root element\n",
2308 inst->name);
2309 style->errors++;
2310 }
2311 return;
2312 } else if (IS_XSLT_NAME(inst, "key")) {
2313 xsltCheckTopLevelElement(style, inst, 1);
2314 return;
2315 } else if (IS_XSLT_NAME(inst, "message")) {
2316 xsltCheckInstructionElement(style, inst);
2317 return;
2318 } else if (IS_XSLT_NAME(inst, "attribute-set")) {
2319 xsltCheckTopLevelElement(style, inst, 1);
2320 return;
2321 } else if (IS_XSLT_NAME(inst, "namespace-alias")) {
2322 xsltCheckTopLevelElement(style, inst, 1);
2323 return;
2324 } else if (IS_XSLT_NAME(inst, "include")) {
2325 xsltCheckTopLevelElement(style, inst, 1);
2326 return;
2327 } else if (IS_XSLT_NAME(inst, "import")) {
2328 xsltCheckTopLevelElement(style, inst, 1);
2329 return;
2330 } else if (IS_XSLT_NAME(inst, "decimal-format")) {
2331 xsltCheckTopLevelElement(style, inst, 1);
2332 return;
2333 } else if (IS_XSLT_NAME(inst, "fallback")) {
2334 xsltCheckInstructionElement(style, inst);
2335 return;
2336 } else if (IS_XSLT_NAME(inst, "document")) {
2337 xsltCheckInstructionElement(style, inst);
2338 inst->psvi = (void *) xsltDocumentComp(style, inst,
2339 (xsltTransformFunction) xsltDocumentElem);
2340 } else {
2341 xsltTransformError(NULL, style, inst,
2342 "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
2343 if (style != NULL) style->warnings++;
2344 }
2345
2346 cur = (xsltStylePreCompPtr) inst->psvi;
2347 /*
2348 * A ns-list is build for every XSLT item in the
2349 * node-tree. This is needed for XPath expressions.
2350 */
2351 if (cur != NULL) {
2352 int i = 0;
2353
2354 cur->nsList = xmlGetNsList(inst->doc, inst);
2355 if (cur->nsList != NULL) {
2356 while (cur->nsList[i] != NULL)
2357 i++;
2358 }
2359 cur->nsNr = i;
2360 }
2361 } else {
2362 inst->psvi =
2363 (void *) xsltPreComputeExtModuleElement(style, inst);
2364
2365 /*
2366 * Unknown element, maybe registered at the context
2367 * level. Mark it for later recognition.
2368 */
2369 if (inst->psvi == NULL)
2370 inst->psvi = (void *) xsltExtMarker;
2371 }
2372 }
2373 #endif /* XSLT_REFACTORED */