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