81cc89102067dafbd7c98affbd1bc9e90a21f240
[platform/upstream/libxslt.git] / libxslt / transform.c
1 /*
2  * transform.c: Implemetation of the XSL Transformation 1.0 engine
3  *            transform part, i.e. applying a Stylesheet to a document
4  *
5  * References:
6  *   http://www.w3.org/TR/1999/REC-xslt-19991116
7  *
8  *   Michael Kay "XSLT Programmer's Reference" pp 637-643
9  *   Writing Multiple Output Files
10  *
11  *   XSLT-1.1 Working Draft
12  *   http://www.w3.org/TR/xslt11#multiple-output
13  *
14  * See Copyright for the status of this software.
15  *
16  * daniel@veillard.com
17  */
18
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/encoding.h>
29 #include <libxml/xmlerror.h>
30 #include <libxml/xpath.h>
31 #include <libxml/parserInternals.h>
32 #include <libxml/xpathInternals.h>
33 #include <libxml/HTMLtree.h>
34 #include <libxml/uri.h>
35 #include "xslt.h"
36 #include "xsltInternals.h"
37 #include "xsltutils.h"
38 #include "pattern.h"
39 #include "transform.h"
40 #include "variables.h"
41 #include "numbersInternals.h"
42 #include "namespaces.h"
43 #include "attributes.h"
44 #include "templates.h"
45 #include "imports.h"
46 #include "keys.h"
47 #include "documents.h"
48 #include "extensions.h"
49 #include "extra.h"
50 #include "preproc.h"
51
52 #ifdef WITH_XSLT_DEBUG
53 #define WITH_XSLT_DEBUG_PROCESS
54 #endif
55
56 int xsltMaxDepth = 250;
57
58 /*
59  * Useful macros
60  */
61
62 #ifndef FALSE
63 # define FALSE (0 == 1)
64 # define TRUE (!FALSE)
65 #endif
66
67 #define IS_BLANK_NODE(n)                                                \
68     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
69
70 /*
71  * Generic function for accessing stacks in the transform Context
72  */
73
74 #define PUSH_AND_POP(scope, type, name)                                 \
75 scope int name##Push(xsltTransformContextPtr ctxt, type value) {        \
76     if (ctxt->name##Nr >= ctxt->name##Max) {                            \
77         ctxt->name##Max *= 2;                                           \
78         ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,          \
79                      ctxt->name##Max * sizeof(ctxt->name##Tab[0]));     \
80         if (ctxt->name##Tab == NULL) {                                  \
81             xmlGenericError(xmlGenericErrorContext,                     \
82                     "realloc failed !\n");                              \
83             return(0);                                                  \
84         }                                                               \
85     }                                                                   \
86     ctxt->name##Tab[ctxt->name##Nr] = value;                            \
87     ctxt->name = value;                                                 \
88     return(ctxt->name##Nr++);                                           \
89 }                                                                       \
90 scope type name##Pop(xsltTransformContextPtr ctxt) {                    \
91     type ret;                                                           \
92     if (ctxt->name##Nr <= 0) return(0);                                 \
93     ctxt->name##Nr--;                                                   \
94     if (ctxt->name##Nr > 0)                                             \
95         ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];               \
96     else                                                                \
97         ctxt->name = NULL;                                              \
98     ret = ctxt->name##Tab[ctxt->name##Nr];                              \
99     ctxt->name##Tab[ctxt->name##Nr] = 0;                                \
100     return(ret);                                                        \
101 }                                                                       \
102
103 /*
104  * Those macros actually generate the functions
105  */
106 PUSH_AND_POP(static, xsltTemplatePtr, templ)
107 PUSH_AND_POP(static, xsltStackElemPtr, vars)
108
109 /************************************************************************
110  *                                                                      *
111  *                      XInclude default settings                       *
112  *                                                                      *
113  ************************************************************************/
114
115 static int xsltDoXIncludeDefault = 0;
116
117 /**
118  * xsltSetXIncludeDefault:
119  * @xinclude: whether to do XInclude processing
120  *
121  * Set whether XInclude should be processed on document being loaded by default
122  */
123 void
124 xsltSetXIncludeDefault(int xinclude) {
125     xsltDoXIncludeDefault = (xinclude != 0);
126 }
127
128 /**
129  * xsltGetXIncludeDefault:
130  *
131  * return the default state for XInclude processing
132  *
133  * Returns 0 if there is no processing 1 otherwise
134  */
135 int
136 xsltGetXIncludeDefault(void) {
137     return(xsltDoXIncludeDefault);
138 }
139
140 /************************************************************************
141  *                                                                      *
142  *                      handling of transformation contexts             *
143  *                                                                      *
144  ************************************************************************/
145
146 /**
147  * xsltNewTransformContext:
148  * @style:  a parsed XSLT stylesheet
149  * @doc:  the input document
150  *
151  * Create a new XSLT TransformContext
152  *
153  * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
154  */
155 static xsltTransformContextPtr
156 xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
157     xsltTransformContextPtr cur;
158     xsltDocumentPtr docu;
159
160     cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
161     if (cur == NULL) {
162         xsltGenericError(xsltGenericErrorContext,
163                 "xsltNewTransformContext : malloc failed\n");
164         return(NULL);
165     }
166     memset(cur, 0, sizeof(xsltTransformContext));
167
168     /*
169      * initialize the template stack
170      */
171     cur->templTab = (xsltTemplatePtr *)
172                 xmlMalloc(10 * sizeof(xsltTemplatePtr));
173     if (cur->templTab == NULL) {
174         xmlGenericError(xmlGenericErrorContext,
175                 "xsltNewTransformContext: out of memory\n");
176         xmlFree(cur);
177         return(NULL);
178     }
179     cur->templNr = 0;
180     cur->templMax = 5;
181     cur->templ = NULL;
182
183     /*
184      * initialize the variables stack
185      */
186     cur->varsTab = (xsltStackElemPtr *)
187                 xmlMalloc(10 * sizeof(xsltStackElemPtr));
188     if (cur->varsTab == NULL) {
189         xmlGenericError(xmlGenericErrorContext,
190                 "xsltNewTransformContext: out of memory\n");
191         xmlFree(cur->templTab);
192         xmlFree(cur);
193         return(NULL);
194     }
195     cur->varsNr = 0;
196     cur->varsMax = 5;
197     cur->vars = NULL;
198
199     cur->style = style;
200     xmlXPathInit();
201     cur->xpathCtxt = xmlXPathNewContext(doc);
202     if (cur->xpathCtxt == NULL) {
203         xsltGenericError(xsltGenericErrorContext,
204                 "xsltNewTransformContext : xmlXPathNewContext failed\n");
205         xmlFree(cur->templTab);
206         xmlFree(cur->varsTab);
207         xmlFree(cur);
208         return(NULL);
209     }
210     cur->xpathCtxt->proximityPosition = 0;
211     cur->xpathCtxt->contextSize = 0;
212     XSLT_REGISTER_VARIABLE_LOOKUP(cur);
213     cur->xpathCtxt->nsHash = style->nsHash;
214     docu = xsltNewDocument(cur, doc);
215     if (docu == NULL) {
216         xsltGenericError(xsltGenericErrorContext,
217                 "xsltNewTransformContext : xsltNewDocument failed\n");
218         xmlFree(cur->templTab);
219         xmlFree(cur->varsTab);
220         xmlFree(cur);
221         return(NULL);
222     }
223     docu->main = 1;
224     cur->document = docu;
225     cur->inst = NULL;
226     cur->xinclude = xsltDoXIncludeDefault;
227     cur->outputFile = NULL;
228     return(cur);
229 }
230
231 /**
232  * xsltFreeTransformContext:
233  * @ctxt:  an XSLT parser context
234  *
235  * Free up the memory allocated by @ctxt
236  */
237 static void
238 xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
239     if (ctxt == NULL)
240         return;
241     if (ctxt->xpathCtxt != NULL) {
242         ctxt->xpathCtxt->nsHash = NULL;
243         xmlXPathFreeContext(ctxt->xpathCtxt);
244     }
245     if (ctxt->templTab != NULL)
246         xmlFree(ctxt->templTab);
247     if (ctxt->varsTab != NULL)
248         xmlFree(ctxt->varsTab);
249     xsltFreeDocuments(ctxt);
250     xsltFreeCtxtExts(ctxt);
251     xsltFreeGlobalVariables(ctxt);
252     memset(ctxt, -1, sizeof(xsltTransformContext));
253     xmlFree(ctxt);
254 }
255
256 /************************************************************************
257  *                                                                      *
258  *                      Copy of Nodes in an XSLT fashion                *
259  *                                                                      *
260  ************************************************************************/
261
262 xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
263                         xmlNodePtr insert);
264
265 /**
266  * xsltCopyProp:
267  * @ctxt:  a XSLT process context
268  * @target:  the element where the attribute will be grafted
269  * @attr:  the attribute
270  *
271  * Do a copy of an attribute
272  *
273  * Returns: a new xmlAttrPtr, or NULL in case of error.
274  */
275 static xmlAttrPtr
276 xsltCopyProp(xsltTransformContextPtr ctxt, xmlNodePtr target,
277              xmlAttrPtr attr) {
278     xmlAttrPtr ret = NULL;
279     xmlNsPtr ns;
280     xmlChar *val;
281
282     if (attr == NULL)
283         return(NULL);
284
285     if (attr->ns != NULL) {
286         ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
287     } else {
288         ns = NULL;
289     }
290     val = xmlNodeListGetString(attr->doc, attr->children, 1);
291     ret = xmlSetNsProp(target, ns, attr->name, val);
292     if (val != NULL)
293         xmlFree(val);
294     return(ret);
295 }
296
297 /**
298  * xsltCopyPropList:
299  * @ctxt:  a XSLT process context
300  * @target:  the element where the attributes will be grafted
301  * @cur:  the first attribute
302  *
303  * Do a copy of an attribute list.
304  *
305  * Returns: a new xmlAttrPtr, or NULL in case of error.
306  */
307 static xmlAttrPtr
308 xsltCopyPropList(xsltTransformContextPtr ctxt, xmlNodePtr target,
309                  xmlAttrPtr cur) {
310     xmlAttrPtr ret = NULL;
311     xmlAttrPtr p = NULL,q;
312     xmlNsPtr ns;
313
314     while (cur != NULL) {
315         if (cur->ns != NULL) {
316             ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target);
317         } else {
318             ns = NULL;
319         }
320         q = xmlCopyProp(target, cur);
321         if (q != NULL) {
322             q->ns = ns;
323             if (p == NULL) {
324                 ret = p = q;
325             } else {
326                 p->next = q;
327                 q->prev = p;
328                 p = q;
329             }
330         }
331         cur = cur->next;
332     }
333     return(ret);
334 }
335
336 /**
337  * xsltCopyNode:
338  * @ctxt:  a XSLT process context
339  * @node:  the element node in the source tree.
340  * @insert:  the parent in the result tree.
341  *
342  * Make a copy of the element node @node
343  * and insert it as last child of @insert
344  *
345  * Returns a pointer to the new node, or NULL in case of error
346  */
347 static xmlNodePtr
348 xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
349              xmlNodePtr insert) {
350     xmlNodePtr copy;
351
352     copy = xmlCopyNode(node, 0);
353     if (copy != NULL) {
354         copy->doc = ctxt->output;
355         xmlAddChild(insert, copy);
356         if (node->type == XML_ELEMENT_NODE) {
357             /*
358              * Add namespaces as they are needed
359              */
360             if (node->nsDef != NULL)
361                 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
362         }
363         if (node->ns != NULL) {
364             copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
365         }
366     } else {
367         xsltGenericError(xsltGenericErrorContext,
368                 "xsltCopyNode: copy %s failed\n", node->name);
369     }
370     return(copy);
371 }
372
373 /**
374  * xsltCopyTreeList:
375  * @ctxt:  a XSLT process context
376  * @list:  the list of element node in the source tree.
377  * @insert:  the parent in the result tree.
378  *
379  * Make a copy of the full list of tree @list
380  * and insert them as last children of @insert
381  *
382  * Returns a pointer to the new list, or NULL in case of error
383  */
384 static xmlNodePtr
385 xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr list,
386              xmlNodePtr insert) {
387     xmlNodePtr copy, ret = NULL;
388
389     while (list != NULL) {
390         copy = xsltCopyTree(ctxt, list, insert);
391         if (copy != NULL) {
392             if (ret == NULL) {
393                 ret = copy;
394             }
395         }
396         list = list->next;
397     }
398     return(ret);
399 }
400
401 /**
402  * xsltCopyTree:
403  * @ctxt:  a XSLT process context
404  * @node:  the element node in the source tree.
405  * @insert:  the parent in the result tree.
406  *
407  * Make a copy of the full tree under the element node @node
408  * and insert it as last child of @insert
409  *
410  * Returns a pointer to the new tree, or NULL in case of error
411  */
412 xmlNodePtr
413 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
414              xmlNodePtr insert) {
415     xmlNodePtr copy;
416
417     if (node == NULL)
418         return(NULL);
419     switch (node->type) {
420         case XML_ELEMENT_NODE:
421         case XML_TEXT_NODE:
422         case XML_CDATA_SECTION_NODE:
423         case XML_ENTITY_REF_NODE:
424         case XML_ENTITY_NODE:
425         case XML_PI_NODE:
426         case XML_COMMENT_NODE:
427         case XML_DOCUMENT_NODE:
428         case XML_HTML_DOCUMENT_NODE:
429 #ifdef LIBXML_DOCB_ENABLED
430         case XML_DOCB_DOCUMENT_NODE:
431 #endif
432             break;
433         case XML_ATTRIBUTE_NODE:
434             return((xmlNodePtr)
435                    xsltCopyProp(ctxt, insert, (xmlAttrPtr) node));
436         case XML_NAMESPACE_DECL:
437             return((xmlNodePtr)
438                    xsltCopyNamespaceList(ctxt, insert, (xmlNsPtr) node));
439             
440         case XML_DOCUMENT_TYPE_NODE:
441         case XML_DOCUMENT_FRAG_NODE:
442         case XML_NOTATION_NODE:
443         case XML_DTD_NODE:
444         case XML_ELEMENT_DECL:
445         case XML_ATTRIBUTE_DECL:
446         case XML_ENTITY_DECL:
447         case XML_XINCLUDE_START:
448         case XML_XINCLUDE_END:
449             return(NULL);
450     }
451     copy = xmlCopyNode(node, 0);
452     copy->doc = ctxt->output;
453     if (copy != NULL) {
454         xmlAddChild(insert, copy);
455         copy->next = NULL;
456         /*
457          * Add namespaces as they are needed
458          */
459         if (node->nsDef != NULL)
460             xsltCopyNamespaceList(ctxt, copy, node->nsDef);
461         if (node->ns != NULL) {
462             copy->ns = xsltGetNamespace(ctxt, node, node->ns, insert);
463         }
464         if (node->properties != NULL)
465             copy->properties = xsltCopyPropList(ctxt, copy,
466                                                node->properties);
467         if (node->children != NULL)
468             xsltCopyTreeList(ctxt, node->children, copy);
469     } else {
470         xsltGenericError(xsltGenericErrorContext,
471                 "xsltCopyTree: copy %s failed\n", node->name);
472     }
473     return(copy);
474 }
475
476 /************************************************************************
477  *                                                                      *
478  *                      Default processing                              *
479  *                                                                      *
480  ************************************************************************/
481
482 void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node);
483 /**
484  * xsltDefaultProcessOneNode:
485  * @ctxt:  a XSLT process context
486  * @node:  the node in the source tree.
487  *
488  * Process the source node with the default built-in template rule:
489  * <xsl:template match="*|/">
490  *   <xsl:apply-templates/>
491  * </xsl:template>
492  *
493  * and
494  *
495  * <xsl:template match="text()|@*">
496  *   <xsl:value-of select="."/>
497  * </xsl:template>
498  *
499  * Note also that namespaces declarations are copied directly:
500  *
501  * the built-in template rule is the only template rule that is applied
502  * for namespace nodes.
503  */
504 static void
505 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
506     xmlNodePtr copy;
507     xmlAttrPtr attrs;
508     xmlNodePtr delete = NULL, cur;
509     int strip_spaces = -1;
510     int nbchild = 0, oldSize;
511     int childno = 0, oldPos;
512     xsltTemplatePtr template;
513
514     CHECK_STOPPED;
515     /*
516      * Handling of leaves
517      */
518     switch (node->type) {
519         case XML_DOCUMENT_NODE:
520         case XML_HTML_DOCUMENT_NODE:
521         case XML_ELEMENT_NODE:
522             break;
523         case XML_CDATA_SECTION_NODE:
524 #ifdef WITH_XSLT_DEBUG_PROCESS
525             xsltGenericDebug(xsltGenericDebugContext,
526              "xsltDefaultProcessOneNode: copy CDATA %s\n",
527                 node->content);
528 #endif
529             copy = xmlNewDocText(ctxt->output, node->content);
530             if (copy != NULL) {
531                 xmlAddChild(ctxt->insert, copy);
532             } else {
533                 xsltGenericError(xsltGenericErrorContext,
534                  "xsltDefaultProcessOneNode: cdata copy failed\n");
535             }
536             return;
537         case XML_TEXT_NODE:
538 #ifdef WITH_XSLT_DEBUG_PROCESS
539             if (node->content == NULL)
540                 xsltGenericDebug(xsltGenericDebugContext,
541                  "xsltDefaultProcessOneNode: copy empty text\n");
542             else
543                 xsltGenericDebug(xsltGenericDebugContext,
544                  "xsltDefaultProcessOneNode: copy text %s\n",
545                         node->content);
546 #endif
547             copy = xmlCopyNode(node, 0);
548             if (copy != NULL) {
549                 xmlAddChild(ctxt->insert, copy);
550             } else {
551                 xsltGenericError(xsltGenericErrorContext,
552                  "xsltDefaultProcessOneNode: text copy failed\n");
553             }
554             return;
555         case XML_ATTRIBUTE_NODE:
556             cur = node->children;
557             while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
558                 cur = cur->next;
559             if (cur == NULL) {
560                 xsltGenericError(xsltGenericErrorContext,
561                  "xsltDefaultProcessOneNode: no text for attribute\n");
562             } else {
563 #ifdef WITH_XSLT_DEBUG_PROCESS
564                 if (cur->content == NULL)
565                     xsltGenericDebug(xsltGenericDebugContext,
566                      "xsltDefaultProcessOneNode: copy empty text\n");
567                 else
568                     xsltGenericDebug(xsltGenericDebugContext,
569                      "xsltDefaultProcessOneNode: copy text %s\n",
570                         cur->content);
571 #endif
572                 copy = xmlCopyNode(cur, 0);
573                 if (copy != NULL) {
574                     xmlAddChild(ctxt->insert, copy);
575                 } else {
576                     xsltGenericError(xsltGenericErrorContext,
577                      "xsltDefaultProcessOneNode: text copy failed\n");
578                 }
579             }
580             return;
581         default:
582             return;
583     }
584     /*
585      * Handling of Elements: first pass, cleanup and counting
586      */
587     cur = node->children;
588     while (cur != NULL) {
589         switch (cur->type) {
590             case XML_TEXT_NODE:
591                 if ((IS_BLANK_NODE(cur)) &&
592                     (cur->parent != NULL) &&
593                     (ctxt->style->stripSpaces != NULL)) {
594                     if (strip_spaces == -1)
595                         strip_spaces =
596                             xsltFindElemSpaceHandling(ctxt, cur->parent);
597                     if (strip_spaces == 1) {
598                         delete = cur;
599                         break;
600                     }
601                 }
602                 /* no break on purpose */
603             case XML_CDATA_SECTION_NODE:
604             case XML_DOCUMENT_NODE:
605             case XML_HTML_DOCUMENT_NODE:
606             case XML_ELEMENT_NODE:
607             case XML_PI_NODE:
608             case XML_COMMENT_NODE:
609                 nbchild++;
610                 break;
611             default:
612 #ifdef WITH_XSLT_DEBUG_PROCESS
613                 xsltGenericDebug(xsltGenericDebugContext,
614                  "xsltDefaultProcessOneNode: skipping node type %d\n",
615                                  cur->type);
616 #endif
617                 delete = cur;
618         }
619         cur = cur->next;
620         if (delete != NULL) {
621 #ifdef WITH_XSLT_DEBUG_PROCESS
622             xsltGenericDebug(xsltGenericDebugContext,
623                  "xsltDefaultProcessOneNode: removing ignorable blank node\n");
624 #endif
625             xmlUnlinkNode(delete);
626             xmlFreeNode(delete);
627             delete = NULL;
628         }
629     }
630     /*
631      * Handling of Elements: second pass, actual processing
632      */
633     attrs = node->properties;
634     while (attrs != NULL) {
635         template = xsltGetTemplate(ctxt, (xmlNodePtr) attrs, NULL);
636         if (template) {
637             xmlNodePtr oldNode;
638
639             oldNode = ctxt->node;
640             ctxt->node = node;
641             templPush(ctxt, template);
642             xsltApplyOneTemplate(ctxt, node, template->content, 1);
643             templPop(ctxt);
644             ctxt->node = oldNode;
645         }
646         attrs = attrs->next;
647     }
648     oldSize = ctxt->xpathCtxt->contextSize;
649     oldPos = ctxt->xpathCtxt->proximityPosition;
650     cur = node->children;
651     while (cur != NULL) {
652         childno++;
653         switch (cur->type) {
654             case XML_DOCUMENT_NODE:
655             case XML_HTML_DOCUMENT_NODE:
656             case XML_ELEMENT_NODE:
657                 ctxt->xpathCtxt->contextSize = nbchild;
658                 ctxt->xpathCtxt->proximityPosition = childno;
659                 varsPush( ctxt, NULL );
660                 xsltProcessOneNode(ctxt, cur);
661                 xsltFreeStackElemList( varsPop(ctxt) );
662                 break;
663             case XML_CDATA_SECTION_NODE:
664                 template = xsltGetTemplate(ctxt, node, NULL);
665                 if (template) {
666                     xmlNodePtr oldNode;
667
668 #ifdef WITH_XSLT_DEBUG_PROCESS
669                     xsltGenericDebug(xsltGenericDebugContext,
670                  "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
671                                      node->content);
672 #endif
673                     oldNode = ctxt->node;
674                     ctxt->node = node;
675                     templPush(ctxt, template);
676                     xsltApplyOneTemplate(ctxt, node, template->content, 1);
677                     templPop(ctxt);
678                     ctxt->node = oldNode;
679                 } else /* if (ctxt->mode == NULL) */ {
680 #ifdef WITH_XSLT_DEBUG_PROCESS
681                     xsltGenericDebug(xsltGenericDebugContext,
682                      "xsltDefaultProcessOneNode: copy CDATA %s\n",
683                                      node->content);
684 #endif
685                     copy = xmlNewDocText(ctxt->output, node->content);
686                     if (copy != NULL) {
687                         xmlAddChild(ctxt->insert, copy);
688                     } else {
689                         xsltGenericError(xsltGenericErrorContext,
690                             "xsltDefaultProcessOneNode: cdata copy failed\n");
691                     }
692                 }
693                 break;
694             case XML_TEXT_NODE:
695                 template = xsltGetTemplate(ctxt, cur, NULL);
696                 if (template) {
697                     xmlNodePtr oldNode;
698
699 #ifdef WITH_XSLT_DEBUG_PROCESS
700                     xsltGenericDebug(xsltGenericDebugContext,
701              "xsltDefaultProcessOneNode: applying template for text %s\n",
702                                      node->content);
703 #endif
704                     oldNode = ctxt->node;
705                     ctxt->node = cur;
706                     ctxt->xpathCtxt->contextSize = nbchild;
707                     ctxt->xpathCtxt->proximityPosition = childno;
708                     templPush(ctxt, template);
709                     xsltApplyOneTemplate(ctxt, cur, template->content, 1);
710                     templPop(ctxt);
711                     ctxt->node = oldNode;
712                 } else /* if (ctxt->mode == NULL) */ {
713 #ifdef WITH_XSLT_DEBUG_PROCESS
714                     if (cur->content == NULL)
715                         xsltGenericDebug(xsltGenericDebugContext,
716                          "xsltDefaultProcessOneNode: copy empty text\n");
717                     else
718                         xsltGenericDebug(xsltGenericDebugContext,
719                      "xsltDefaultProcessOneNode: copy text %s\n",
720                                          cur->content);
721 #endif
722                     copy = xmlCopyNode(cur, 0);
723                     if (copy != NULL) {
724                         xmlAddChild(ctxt->insert, copy);
725                     } else {
726                         xsltGenericError(xsltGenericErrorContext,
727                             "xsltDefaultProcessOneNode: text copy failed\n");
728                     }
729                 }
730                 break;
731             case XML_PI_NODE:
732             case XML_COMMENT_NODE:
733                 template = xsltGetTemplate(ctxt, cur, NULL);
734                 if (template) {
735                     xmlNodePtr oldNode;
736
737 #ifdef WITH_XSLT_DEBUG_PROCESS
738                     if (cur->type == XML_PI_NODE)
739                         xsltGenericDebug(xsltGenericDebugContext,
740                      "xsltDefaultProcessOneNode: template found for PI %s\n",
741                                          cur->name);
742                     else if (cur->type == XML_COMMENT_NODE)
743                         xsltGenericDebug(xsltGenericDebugContext,
744                      "xsltDefaultProcessOneNode: template found for comment\n");
745 #endif
746                     oldNode = ctxt->node;
747                     ctxt->node = cur;
748                     ctxt->xpathCtxt->contextSize = nbchild;
749                     ctxt->xpathCtxt->proximityPosition = childno;
750                     templPush(ctxt, template);
751                     xsltApplyOneTemplate(ctxt, cur, template->content, 1);
752                     templPop(ctxt);
753                     ctxt->node = oldNode;
754                 }
755                 break;
756             default:
757                 break;
758         }
759         cur = cur->next;
760     }
761     ctxt->xpathCtxt->contextSize = oldSize;
762     ctxt->xpathCtxt->proximityPosition = oldPos;
763 }
764
765 /**
766  * xsltProcessOneNode:
767  * @ctxt:  a XSLT process context
768  * @node:  the node in the source tree.
769  *
770  * Process the source node.
771  */
772 void
773 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
774     xsltTemplatePtr template;
775     xmlNodePtr oldNode;
776
777     /*
778      * Cleanup children empty nodes if asked for
779      */
780     if ((node->children != NULL) &&
781         (xsltFindElemSpaceHandling(ctxt, node))) {
782         xmlNodePtr delete = NULL, cur = node->children;
783
784         while (cur != NULL) {
785             if (IS_BLANK_NODE(cur))
786                 delete = cur;
787             
788             cur = cur->next;
789             if (delete != NULL) {
790 #ifdef WITH_XSLT_DEBUG_PROCESS
791                 xsltGenericDebug(xsltGenericDebugContext,
792              "xsltProcessOneNode: removing ignorable blank node\n");
793 #endif
794                 xmlUnlinkNode(delete);
795                 xmlFreeNode(delete);
796                 delete = NULL;
797             }
798         }
799     }
800
801     template = xsltGetTemplate(ctxt, node, NULL);
802     /*
803      * If no template is found, apply the default rule.
804      */
805     if (template == NULL) {
806 #ifdef WITH_XSLT_DEBUG_PROCESS
807         if (node->type == XML_DOCUMENT_NODE)
808             xsltGenericDebug(xsltGenericDebugContext,
809              "xsltProcessOneNode: no template found for /\n");
810         else if (node->type == XML_CDATA_SECTION_NODE)
811             xsltGenericDebug(xsltGenericDebugContext,
812              "xsltProcessOneNode: no template found for CDATA\n");
813         else if (node->type == XML_ATTRIBUTE_NODE)
814             xsltGenericDebug(xsltGenericDebugContext,
815              "xsltProcessOneNode: no template found for attribute %s\n",
816                              ((xmlAttrPtr) node)->name);
817         else 
818             xsltGenericDebug(xsltGenericDebugContext,
819              "xsltProcessOneNode: no template found for %s\n", node->name);
820 #endif
821         oldNode = ctxt->node;
822         ctxt->node = node;
823         xsltDefaultProcessOneNode(ctxt, node);
824         ctxt->node = oldNode;
825         return;
826     }
827
828     if (node->type == XML_ATTRIBUTE_NODE) {
829 #ifdef WITH_XSLT_DEBUG_PROCESS
830         xsltGenericDebug(xsltGenericDebugContext,
831              "xsltProcessOneNode: applying template '%s' for attribute %s\n",
832                          template->match, node->name);
833 #endif
834         templPush(ctxt, template);
835         xsltApplyOneTemplate(ctxt, node, template->content, 1);
836         templPop(ctxt);
837     } else {
838 #ifdef WITH_XSLT_DEBUG_PROCESS
839         if (node->type == XML_DOCUMENT_NODE)
840             xsltGenericDebug(xsltGenericDebugContext,
841              "xsltProcessOneNode: applying template '%s' for /\n",
842                              template->match);
843         else 
844             xsltGenericDebug(xsltGenericDebugContext,
845              "xsltProcessOneNode: applying template '%s' for %s\n",
846                              template->match, node->name);
847 #endif
848         oldNode = ctxt->node;
849         ctxt->node = node;
850         templPush(ctxt, template);
851         xsltApplyOneTemplate(ctxt, node, template->content, 1);
852         templPop(ctxt);
853         ctxt->node = oldNode;
854     }
855 }
856
857 /**
858  * xsltApplyOneTemplate:
859  * @ctxt:  a XSLT process context
860  * @node:  the node in the source tree.
861  * @list:  the template replacement nodelist
862  * @real: is this a real template processing
863  *
864  * Process the apply-templates node on the source node
865  */
866 void
867 xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
868                      xmlNodePtr list, int real) {
869     xmlNodePtr cur = NULL, insert, copy = NULL;
870     xmlNodePtr oldInsert;
871     xmlNodePtr oldCurrent = NULL;
872     xmlNodePtr oldInst = NULL;
873     xmlAttrPtr attrs;
874
875     if (list == NULL)
876         return;
877     CHECK_STOPPED;
878
879     if (ctxt->templNr >= xsltMaxDepth) {
880         xsltGenericError(xsltGenericErrorContext,
881                 "xsltApplyOneTemplate: loop found ???\n");
882         xsltGenericError(xsltGenericErrorContext,
883                 "try increasing xsltMaxDepth (--maxdepth)\n");
884         xsltDebug(ctxt, node, list, NULL);
885         return;
886     }
887
888     /*
889      * stack and saves
890      */
891     oldInsert = insert = ctxt->insert;
892     oldInst = ctxt->inst;
893     if (real) {
894         oldCurrent = ctxt->node;
895         ctxt->node = node;
896     }
897
898     /*
899      * Insert all non-XSLT nodes found in the template
900      */
901     cur = list;
902     while (cur != NULL) {
903         ctxt->inst = cur;
904         /*
905          * test, we must have a valid insertion point
906          */
907         if (insert == NULL) {
908 #ifdef WITH_XSLT_DEBUG_PROCESS
909             xsltGenericDebug(xsltGenericDebugContext,
910                  "xsltApplyOneTemplate: insert == NULL !\n");
911 #endif
912             if (real)
913                 ctxt->node = oldCurrent;
914             ctxt->inst = oldInst;
915             return;
916         }
917
918         if (IS_XSLT_ELEM(cur)) {
919             /*
920              * This is an XSLT node
921              */
922             xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->_private;
923             if (info == NULL) {
924                 if (IS_XSLT_NAME(cur, "message")) {
925                     xsltMessage(ctxt, node, cur);
926                 } else {
927                     xsltGenericError(xsltGenericDebugContext,
928                      "xsltApplyOneTemplate: %s was not compiled\n",
929                                      cur->name);
930                 }
931                 goto skip_children;
932             }
933             
934             if (info->func != NULL) {
935                 ctxt->insert = insert;
936                 info->func(ctxt, node, cur, info);
937                 ctxt->insert = oldInsert;
938                 goto skip_children;
939             }
940
941             if (IS_XSLT_NAME(cur, "variable")) {
942                 xsltParseStylesheetVariable(ctxt, cur);
943             } else if (IS_XSLT_NAME(cur, "param")) {
944                 xsltParseStylesheetParam(ctxt, cur);
945             } else if (IS_XSLT_NAME(cur, "message")) {
946                 xsltMessage(ctxt, node, cur);
947             } else {
948                 xsltGenericError(xsltGenericDebugContext,
949                      "xsltApplyOneTemplate: problem with xsl:%s\n",
950                                  cur->name);
951             }
952             CHECK_STOPPED;
953             goto skip_children;
954         } else if ((cur->type == XML_TEXT_NODE) ||
955                    (cur->type == XML_CDATA_SECTION_NODE)) {
956             /*
957              * This text comes from the stylesheet
958              * For stylesheets, the set of whitespace-preserving
959              * element names consists of just xsl:text.
960              */
961 #ifdef WITH_XSLT_DEBUG_PROCESS
962             if (cur->type == XML_CDATA_SECTION_NODE)
963                 xsltGenericDebug(xsltGenericDebugContext,
964                      "xsltApplyOneTemplate: copy CDATA text %s\n",
965                                  cur->content);
966             else if (cur->name == xmlStringTextNoenc)
967                 xsltGenericDebug(xsltGenericDebugContext,
968                      "xsltApplyOneTemplate: copy unescaped text %s\n",
969                                  cur->content);
970             else
971                 xsltGenericDebug(xsltGenericDebugContext,
972                      "xsltApplyOneTemplate: copy text %s\n", cur->content);
973 #endif
974             copy = xmlNewText(cur->content);
975             if (copy != NULL) {
976                 if ((cur->name == xmlStringTextNoenc) ||
977                     (cur->type == XML_CDATA_SECTION_NODE))
978                     copy->name = xmlStringTextNoenc;
979                 xmlAddChild(insert, copy);
980             } else {
981                 xsltGenericError(xsltGenericErrorContext,
982                         "xsltApplyOneTemplate: text copy failed\n");
983             }
984         } else if ((cur->type == XML_ELEMENT_NODE) && 
985                    (cur->ns != NULL) && (cur->_private != NULL)) {
986             xsltTransformFunction function;
987             /*
988              * Flagged as an extension element
989              */
990             function = (xsltTransformFunction)
991                 xmlHashLookup2(ctxt->extElements, cur->name, cur->ns->href);
992             if (function == NULL) {
993                 xsltGenericError(xsltGenericErrorContext,
994                         "xsltApplyOneTemplate: failed to find extension %s\n",
995                                  cur->name);
996             } else {
997 #ifdef WITH_XSLT_DEBUG_PROCESS
998                 xsltGenericDebug(xsltGenericDebugContext,
999                  "xsltApplyOneTemplate: extension construct %s\n", cur->name);
1000 #endif
1001
1002                 ctxt->insert = insert;
1003                 function(ctxt, node, cur, cur->_private);
1004                 ctxt->insert = oldInsert;
1005             }
1006             goto skip_children;
1007         } else if (cur->type == XML_ELEMENT_NODE) {
1008 #ifdef WITH_XSLT_DEBUG_PROCESS
1009             xsltGenericDebug(xsltGenericDebugContext,
1010                  "xsltApplyOneTemplate: copy node %s\n", cur->name);
1011 #endif
1012             copy = xsltCopyNode(ctxt, cur, insert);
1013             /*
1014              * all the attributes are directly inherited
1015              */
1016             if (cur->properties != NULL) {
1017                 attrs = xsltAttrListTemplateProcess(ctxt, copy,
1018                                                     cur->properties);
1019             }
1020         }
1021
1022         /*
1023          * Skip to next node, in document order.
1024          */
1025         if (cur->children != NULL) {
1026             if (cur->children->type != XML_ENTITY_DECL) {
1027                 cur = cur->children;
1028                 if (copy != NULL)
1029                     insert = copy;
1030                 continue;
1031             }
1032         }
1033 skip_children:
1034         if (cur->next != NULL) {
1035             cur = cur->next;
1036             continue;
1037         }
1038         
1039         do {
1040             cur = cur->parent;
1041             insert = insert->parent;
1042             if (cur == NULL)
1043                 break;
1044             if (cur == list->parent) {
1045                 cur = NULL;
1046                 break;
1047             }
1048             if (cur->next != NULL) {
1049                 cur = cur->next;
1050                 break;
1051             }
1052         } while (cur != NULL);
1053     }
1054     if (real)
1055         ctxt->node = oldCurrent;
1056     ctxt->inst = oldInst;
1057 }
1058
1059
1060 /************************************************************************
1061  *                                                                      *
1062  *                  XSLT-1.1 extensions                                 *
1063  *                                                                      *
1064  ************************************************************************/
1065
1066 /**
1067  * xsltDocumentElem:
1068  * @ctxt:  an XSLT processing context
1069  * @node:  The current node
1070  * @inst:  the instruction in the stylesheet
1071  * @comp:  precomputed informations
1072  *
1073  * Process an XSLT-1.1 document element
1074  */
1075 void
1076 xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
1077                  xmlNodePtr inst, xsltStylePreCompPtr comp)
1078 {
1079     xsltStylesheetPtr style = NULL;
1080     int ret;
1081     xmlChar *filename = NULL, *prop, *elements;
1082     xmlChar *element, *end;
1083     xmlDocPtr res = NULL;
1084     xmlDocPtr oldOutput;
1085     xmlNodePtr oldInsert;
1086     const char *oldOutputFile;
1087     xsltOutputType oldType;
1088     xmlChar *URL = NULL;
1089     const xmlChar *method;
1090     const xmlChar *doctypePublic;
1091     const xmlChar *doctypeSystem;
1092     const xmlChar *version;
1093
1094     if ((ctxt == NULL) || (node == NULL) || (inst == NULL)
1095         || (comp == NULL))
1096         return;
1097
1098     if (comp->filename == NULL) {
1099
1100         if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
1101 #ifdef WITH_XSLT_DEBUG_EXTRA
1102             xsltGenericDebug(xsltGenericDebugContext,
1103                              "Found saxon:output extension\n");
1104 #endif
1105             URL = xsltEvalAttrValueTemplate(ctxt, inst,
1106                                                  (const xmlChar *) "file",
1107                                                  XSLT_SAXON_NAMESPACE);
1108         } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
1109 #ifdef WITH_XSLT_DEBUG_EXTRA
1110             xsltGenericDebug(xsltGenericDebugContext,
1111                              "Found xalan:write extension\n");
1112 #endif
1113             URL = xsltEvalAttrValueTemplate(ctxt, inst,
1114                                                  (const xmlChar *)
1115                                                  "select",
1116                                                  XSLT_XALAN_NAMESPACE);
1117         } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
1118             URL = xsltEvalAttrValueTemplate(ctxt, inst,
1119                                                  (const xmlChar *) "href",
1120                                                  XSLT_XT_NAMESPACE);
1121             if (URL == NULL) {
1122 #ifdef WITH_XSLT_DEBUG_EXTRA
1123                 xsltGenericDebug(xsltGenericDebugContext,
1124                                  "Found xslt11:document construct\n");
1125 #endif
1126                 URL = xsltEvalAttrValueTemplate(ctxt, inst,
1127                                                      (const xmlChar *)
1128                                                      "href",
1129                                                      XSLT_NAMESPACE);
1130                 comp->ver11 = 1;
1131             } else {
1132 #ifdef WITH_XSLT_DEBUG_EXTRA
1133                 xsltGenericDebug(xsltGenericDebugContext,
1134                                  "Found xt:document extension\n");
1135 #endif
1136                 comp->ver11 = 0;
1137             }
1138         }
1139
1140     } else {
1141         URL = xmlStrdup(comp->filename);
1142     }
1143
1144     if (URL == NULL) {
1145         xsltGenericError(xsltGenericErrorContext,
1146                          "xsltDocumentElem: href/URI-Reference not found\n");
1147         return;
1148     }
1149     filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
1150     if (filename == NULL) {
1151         xsltGenericError(xsltGenericErrorContext,
1152                          "xsltDocumentElem: URL computation failed for %s\n",
1153                          URL);
1154         xmlFree(URL);
1155         return;
1156     }
1157
1158     oldOutputFile = ctxt->outputFile;
1159     oldOutput = ctxt->output;
1160     oldInsert = ctxt->insert;
1161     oldType = ctxt->type;
1162     ctxt->outputFile = (const char *) filename;
1163
1164     style = xsltNewStylesheet();
1165     if (style == NULL) {
1166         xsltGenericError(xsltGenericErrorContext,
1167                          "xsltDocumentElem: out of memory\n");
1168         goto error;
1169     }
1170
1171     /*
1172      * Version described in 1.1 draft allows full parametrization
1173      * of the output.
1174      */
1175     if (comp->ver11) {
1176         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1177                                          (const xmlChar *) "version",
1178                                          XSLT_NAMESPACE);
1179         if (prop != NULL) {
1180             if (style->version != NULL)
1181                 xmlFree(style->version);
1182             style->version = prop;
1183         }
1184         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1185                                          (const xmlChar *) "encoding",
1186                                          XSLT_NAMESPACE);
1187         if (prop != NULL) {
1188             if (style->encoding != NULL)
1189                 xmlFree(style->encoding);
1190             style->encoding = prop;
1191         }
1192         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1193                                          (const xmlChar *) "method",
1194                                          XSLT_NAMESPACE);
1195         if (prop != NULL) {
1196             const xmlChar *URI;
1197
1198             if (style->method != NULL)
1199                 xmlFree(style->method);
1200             style->method = NULL;
1201             if (style->methodURI != NULL)
1202                 xmlFree(style->methodURI);
1203             style->methodURI = NULL;
1204
1205             URI = xsltGetQNameURI(inst, &prop);
1206             if (prop == NULL) {
1207                 style->errors++;
1208             } else if (URI == NULL) {
1209                 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1210                     (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1211                     (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1212                     style->method = prop;
1213                 } else {
1214                     xsltGenericError(xsltGenericErrorContext,
1215                                      "invalid value for method: %s\n", prop);
1216                     style->warnings++;
1217                 }
1218             } else {
1219                 style->method = prop;
1220                 style->methodURI = xmlStrdup(URI);
1221             }
1222         }
1223         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1224                                          (const xmlChar *)
1225                                          "doctype-system", XSLT_NAMESPACE);
1226         if (prop != NULL) {
1227             if (style->doctypeSystem != NULL)
1228                 xmlFree(style->doctypeSystem);
1229             style->doctypeSystem = prop;
1230         }
1231         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1232                                          (const xmlChar *)
1233                                          "doctype-public", XSLT_NAMESPACE);
1234         if (prop != NULL) {
1235             if (style->doctypePublic != NULL)
1236                 xmlFree(style->doctypePublic);
1237             style->doctypePublic = prop;
1238         }
1239         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1240                                          (const xmlChar *) "standalone",
1241                                          XSLT_NAMESPACE);
1242         if (prop != NULL) {
1243             if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1244                 style->standalone = 1;
1245             } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1246                 style->standalone = 0;
1247             } else {
1248                 xsltGenericError(xsltGenericErrorContext,
1249                                  "invalid value for standalone: %s\n",
1250                                  prop);
1251                 style->warnings++;
1252             }
1253             xmlFree(prop);
1254         }
1255
1256         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1257                                          (const xmlChar *) "indent",
1258                                          XSLT_NAMESPACE);
1259         if (prop != NULL) {
1260             if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1261                 style->indent = 1;
1262             } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1263                 style->indent = 0;
1264             } else {
1265                 xsltGenericError(xsltGenericErrorContext,
1266                                  "invalid value for indent: %s\n", prop);
1267                 style->warnings++;
1268             }
1269             xmlFree(prop);
1270         }
1271
1272         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1273                                          (const xmlChar *)
1274                                          "omit-xml-declaration",
1275                                          XSLT_NAMESPACE);
1276         if (prop != NULL) {
1277             if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1278                 style->omitXmlDeclaration = 1;
1279             } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1280                 style->omitXmlDeclaration = 0;
1281             } else {
1282                 xsltGenericError(xsltGenericErrorContext,
1283                                  "invalid value for omit-xml-declaration: %s\n",
1284                                  prop);
1285                 style->warnings++;
1286             }
1287             xmlFree(prop);
1288         }
1289
1290         elements = xsltEvalAttrValueTemplate(ctxt, inst,
1291                                              (const xmlChar *)
1292                                              "cdata-section-elements",
1293                                              XSLT_NAMESPACE);
1294         if (elements != NULL) {
1295             if (style->stripSpaces == NULL)
1296                 style->stripSpaces = xmlHashCreate(10);
1297             if (style->stripSpaces == NULL)
1298                 return;
1299
1300             element = elements;
1301             while (*element != 0) {
1302                 while (IS_BLANK(*element))
1303                     element++;
1304                 if (*element == 0)
1305                     break;
1306                 end = element;
1307                 while ((*end != 0) && (!IS_BLANK(*end)))
1308                     end++;
1309                 element = xmlStrndup(element, end - element);
1310                 if (element) {
1311 #ifdef WITH_XSLT_DEBUG_PARSING
1312                     xsltGenericDebug(xsltGenericDebugContext,
1313                                      "add cdata section output element %s\n",
1314                                      element);
1315 #endif
1316                     xmlHashAddEntry(style->stripSpaces, element,
1317                                     (xmlChar *) "cdata");
1318                     xmlFree(element);
1319                 }
1320                 element = end;
1321             }
1322             xmlFree(elements);
1323         }
1324     } else {
1325         xsltParseStylesheetOutput(style, inst);
1326     }
1327
1328     /*
1329      * Create a new document tree and process the element template
1330      */
1331     XSLT_GET_IMPORT_PTR(method, style, method)
1332     XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
1333     XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
1334     XSLT_GET_IMPORT_PTR(version, style, version)
1335
1336     if ((method != NULL) &&
1337         (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
1338         if (xmlStrEqual(method, (const xmlChar *) "html")) {
1339             ctxt->type = XSLT_OUTPUT_HTML;
1340             if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
1341                 res = htmlNewDoc(doctypeSystem, doctypePublic);
1342             else {
1343                 if (version == NULL)
1344                     version = (const xmlChar *) "4.0";
1345 #ifdef XSLT_GENERATE_HTML_DOCTYPE
1346                 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
1347 #endif
1348                 res = htmlNewDoc(doctypeSystem, doctypePublic);
1349             }
1350             if (res == NULL)
1351                 goto error;
1352         } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
1353             xsltGenericError(xsltGenericErrorContext,
1354              "xsltApplyStylesheet: unsupported method xhtml, using html\n",
1355                              style->method);
1356             ctxt->type = XSLT_OUTPUT_HTML;
1357             res = htmlNewDoc(doctypeSystem, doctypePublic);
1358             if (res == NULL)
1359                 goto error;
1360         } else if (xmlStrEqual(style->method, (const xmlChar *) "text")) {
1361             ctxt->type = XSLT_OUTPUT_TEXT;
1362             res = xmlNewDoc(style->version);
1363             if (res == NULL)
1364                 goto error;
1365         } else {
1366             xsltGenericError(xsltGenericErrorContext,
1367                              "xsltApplyStylesheet: unsupported method %s\n",
1368                              style->method);
1369             goto error;
1370         }
1371     } else {
1372         ctxt->type = XSLT_OUTPUT_XML;
1373         res = xmlNewDoc(style->version);
1374         if (res == NULL)
1375             goto error;
1376     }
1377     res->charset = XML_CHAR_ENCODING_UTF8;
1378     if (style->encoding != NULL)
1379         res->encoding = xmlStrdup(style->encoding);
1380     ctxt->output = res;
1381     ctxt->insert = (xmlNodePtr) res;
1382     varsPush(ctxt, NULL);
1383     xsltApplyOneTemplate(ctxt, node, inst->children, 0);
1384     xsltFreeStackElemList(varsPop(ctxt));
1385
1386     /*
1387      * Save the res
1388      */
1389     ret = xsltSaveResultToFilename((const char *) filename,
1390                                    res, style, 0);
1391     if (ret < 0) {
1392         xsltGenericError(xsltGenericErrorContext,
1393                          "xsltDocumentElem: unable to save to %s\n",
1394                          filename);
1395 #ifdef WITH_XSLT_DEBUG_EXTRA
1396     } else {
1397         xsltGenericDebug(xsltGenericDebugContext,
1398                          "Wrote %d bytes to %s\n", ret,, filename);
1399 #endif
1400     }
1401
1402   error:
1403     ctxt->output = oldOutput;
1404     ctxt->insert = oldInsert;
1405     ctxt->type = oldType;
1406     ctxt->outputFile = oldOutputFile;
1407     if (URL != NULL)
1408         xmlFree(URL);
1409     if (filename != NULL)
1410         xmlFree(filename);
1411     if (style != NULL)
1412         xsltFreeStylesheet(style);
1413     if (res != NULL)
1414         xmlFreeDoc(res);
1415 }
1416
1417 /************************************************************************
1418  *                                                                      *
1419  *              Most of the XSLT-1.0 transformations                    *
1420  *                                                                      *
1421  ************************************************************************/
1422
1423 void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node);
1424
1425 /**
1426  * xsltSort:
1427  * @ctxt:  a XSLT process context
1428  * @node:  the node in the source tree.
1429  * @inst:  the xslt sort node
1430  * @comp:  precomputed informations
1431  *
1432  * function attached to xsl:sort nodes, but this should not be
1433  * called directly
1434  */
1435 void
1436 xsltSort(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
1437         xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst ATTRIBUTE_UNUSED,
1438         xsltStylePreCompPtr comp) {
1439     if (comp == NULL) {
1440         xsltGenericError(xsltGenericErrorContext,
1441              "xsl:sort : compilation failed\n");
1442         return;
1443     }
1444     xsltGenericError(xsltGenericErrorContext,
1445          "xsl:sort : improper use this should not be reached\n");
1446 }
1447
1448 /**
1449  * xsltCopy:
1450  * @ctxt:  a XSLT process context
1451  * @node:  the node in the source tree.
1452  * @inst:  the xslt copy node
1453  * @comp:  precomputed informations
1454  *
1455  * Process the xslt copy node on the source node
1456  */
1457 void
1458 xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
1459                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
1460     xmlNodePtr copy, oldInsert;
1461
1462     oldInsert = ctxt->insert;
1463     if (ctxt->insert != NULL) {
1464         switch (node->type) {
1465             case XML_TEXT_NODE:
1466             case XML_CDATA_SECTION_NODE:
1467                 /*
1468                  * This text comes from the stylesheet
1469                  * For stylesheets, the set of whitespace-preserving
1470                  * element names consists of just xsl:text.
1471                  */
1472 #ifdef WITH_XSLT_DEBUG_PROCESS
1473                 if (node->type == XML_CDATA_SECTION_NODE)
1474                     xsltGenericDebug(xsltGenericDebugContext,
1475                          "xsl:copy: CDATA text %s\n", node->content);
1476                 else
1477                     xsltGenericDebug(xsltGenericDebugContext,
1478                          "xsl:copy: text %s\n", node->content);
1479 #endif
1480                 copy = xmlNewText(node->content);
1481                 if (copy != NULL) {
1482                     if ((node->name == xmlStringTextNoenc) ||
1483                         (node->type == XML_CDATA_SECTION_NODE))
1484                         copy->name = xmlStringTextNoenc;
1485                     xmlAddChild(ctxt->insert, copy);
1486                 } else {
1487                     xsltGenericError(xsltGenericErrorContext,
1488                             "xsl:copy: text copy failed\n");
1489                 }
1490                 break;
1491             case XML_DOCUMENT_NODE:
1492             case XML_HTML_DOCUMENT_NODE:
1493                 break;
1494             case XML_ELEMENT_NODE:
1495 #ifdef WITH_XSLT_DEBUG_PROCESS
1496                 xsltGenericDebug(xsltGenericDebugContext,
1497                                  "xsl:copy: node %s\n", node->name);
1498 #endif
1499                 copy = xsltCopyNode(ctxt, node, ctxt->insert);
1500                 ctxt->insert = copy;
1501                 if (comp->use != NULL) {
1502                     xsltApplyAttributeSet(ctxt, node, inst, comp->use);
1503                 }
1504                 break;
1505             case XML_ATTRIBUTE_NODE: {
1506 #ifdef WITH_XSLT_DEBUG_PROCESS
1507                 xsltGenericDebug(xsltGenericDebugContext,
1508                                  "xsl:copy: attribute %s\n", node->name);
1509 #endif
1510                 if (ctxt->insert->type == XML_ELEMENT_NODE) {
1511                     xmlAttrPtr attr = (xmlAttrPtr) node, ret = NULL, cur;
1512                     if (attr->ns != NULL) {
1513                         if ((!xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) &&
1514                             (xmlStrncasecmp(attr->ns->prefix,
1515                                             (xmlChar *)"xml", 3))) {
1516                             ret = xmlCopyProp(ctxt->insert, attr);
1517                             ret->ns = xsltGetNamespace(ctxt, node, attr->ns,
1518                                                        ctxt->insert);
1519                         } 
1520                     } else
1521                         ret = xmlCopyProp(ctxt->insert, attr);
1522
1523                     cur = ctxt->insert->properties;
1524                     if (cur != NULL) {
1525                         while (cur->next != NULL)
1526                             cur = cur->next;
1527                         cur->next = ret;
1528                         ret->prev = cur;
1529                     }else
1530                         ctxt->insert->properties = ret;
1531                 }
1532                 break;
1533             }
1534             case XML_PI_NODE:
1535 #ifdef WITH_XSLT_DEBUG_PROCESS
1536                 xsltGenericDebug(xsltGenericDebugContext,
1537                                  "xsl:copy: PI %s\n", node->name);
1538 #endif
1539                 copy = xmlNewPI(node->name, node->content);
1540                 xmlAddChild(ctxt->insert, copy);
1541                 break;
1542             case XML_COMMENT_NODE:
1543 #ifdef WITH_XSLT_DEBUG_PROCESS
1544                 xsltGenericDebug(xsltGenericDebugContext,
1545                                  "xsl:copy: comment\n");
1546 #endif
1547                 copy = xmlNewComment(node->content);
1548                 xmlAddChild(ctxt->insert, copy);
1549                 break;
1550             default:
1551                 break;
1552
1553         }
1554     }
1555
1556     switch (node->type) {
1557         case XML_DOCUMENT_NODE:
1558         case XML_HTML_DOCUMENT_NODE:
1559         case XML_ELEMENT_NODE:
1560             varsPush(ctxt, NULL);
1561             xsltApplyOneTemplate(ctxt, ctxt->node, inst->children, 0);
1562             xsltFreeStackElemList(varsPop(ctxt));
1563             break;
1564         default:
1565             break;
1566     }
1567     ctxt->insert = oldInsert;
1568 }
1569
1570 /**
1571  * xsltText:
1572  * @ctxt:  a XSLT process context
1573  * @node:  the node in the source tree.
1574  * @inst:  the xslt text node
1575  * @comp:  precomputed informations
1576  *
1577  * Process the xslt text node on the source node
1578  */
1579 void
1580 xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
1581             xmlNodePtr inst, xsltStylePreCompPtr comp) {
1582     if ((inst->children != NULL) && (comp != NULL)) {
1583         xmlNodePtr text = inst->children;
1584         xmlNodePtr copy;
1585
1586         while (text != NULL) {
1587             if (((text->type != XML_TEXT_NODE) &&
1588                  (text->type != XML_CDATA_SECTION_NODE)) ||
1589                 (text->next != NULL)) {
1590                 xsltGenericError(xsltGenericErrorContext,
1591                                  "xsl:text content problem\n");
1592                 break;
1593             }
1594             copy = xmlNewDocText(ctxt->output, text->content);
1595             if ((comp->noescape) || (text->type != XML_CDATA_SECTION_NODE)) {
1596 #ifdef WITH_XSLT_DEBUG_PARSING
1597                 xsltGenericDebug(xsltGenericDebugContext,
1598                      "Disable escaping: %s\n", text->content);
1599 #endif
1600                 copy->name = xmlStringTextNoenc;
1601             }
1602             xmlAddChild(ctxt->insert, copy);
1603             text = text->next;
1604         }
1605     }
1606 }
1607
1608 /**
1609  * xsltElement:
1610  * @ctxt:  a XSLT process context
1611  * @node:  the node in the source tree.
1612  * @inst:  the xslt element node
1613  * @comp:  precomputed informations
1614  *
1615  * Process the xslt element node on the source node
1616  */
1617 void
1618 xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
1619             xmlNodePtr inst, xsltStylePreCompPtr comp) {
1620     xmlChar *prop = NULL, *attributes = NULL;
1621     xmlChar *ncname = NULL, *name, *namespace;
1622     xmlChar *prefix = NULL;
1623     xmlChar *value = NULL;
1624     xmlNsPtr ns = NULL, oldns = NULL;
1625     xmlNodePtr copy;
1626     xmlNodePtr oldInsert;
1627
1628
1629     if (ctxt->insert == NULL)
1630         return;
1631     if (!comp->has_name) {
1632         return;
1633     }
1634
1635     /*
1636      * stack and saves
1637      */
1638     oldInsert = ctxt->insert;
1639
1640     if (comp->name == NULL) {
1641         prop = xsltEvalAttrValueTemplate(ctxt, inst,
1642                       (const xmlChar *)"name", XSLT_NAMESPACE);
1643         if (prop == NULL) {
1644             xsltGenericError(xsltGenericErrorContext,
1645                  "xsl:element : name is missing\n");
1646             goto error;
1647         }
1648         name = prop;
1649     } else {
1650         name = comp->name;
1651     }
1652
1653     ncname = xmlSplitQName2(name, &prefix);
1654     if (ncname == NULL) {
1655         prefix = NULL;
1656     } else {
1657         name = ncname;
1658     }
1659
1660     if ((comp->ns == NULL) && (comp->has_ns)) {
1661         namespace = xsltEvalAttrValueTemplate(ctxt, inst,
1662                 (const xmlChar *)"namespace", XSLT_NAMESPACE);
1663         if (namespace != NULL) {
1664             ns = xsltGetSpecialNamespace(ctxt, inst, namespace, prefix,
1665                                          ctxt->insert);
1666             xmlFree(namespace);
1667         }
1668     } else if (comp->ns != NULL) {
1669         ns = xsltGetSpecialNamespace(ctxt, inst, comp->ns, prefix,
1670                                      ctxt->insert);
1671     }
1672     if ((ns == NULL) && (prefix != NULL)) {
1673         if (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)) {
1674 #ifdef WITH_XSLT_DEBUG_PARSING
1675             xsltGenericDebug(xsltGenericDebugContext,
1676                  "xsl:element : xml prefix forbidden\n");
1677 #endif
1678             goto error;
1679         }
1680         oldns = xmlSearchNs(inst->doc, inst, prefix);
1681         if (oldns == NULL) {
1682             xsltGenericError(xsltGenericErrorContext,
1683                 "xsl:element : no namespace bound to prefix %s\n", prefix);
1684         } else {
1685             ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
1686         }
1687     }
1688
1689     copy = xmlNewDocNode(ctxt->output, ns, name, NULL);
1690     if (copy == NULL) {
1691         xsltGenericError(xsltGenericErrorContext,
1692             "xsl:element : creation of %s failed\n", name);
1693         goto error;
1694     }
1695     if ((ns == NULL) && (oldns != NULL)) {
1696         /* very specific case xsltGetNamespace failed */
1697         ns = xmlNewNs(copy, oldns->href, oldns->prefix);
1698         copy->ns = ns;
1699     }
1700     xmlAddChild(ctxt->insert, copy);
1701     ctxt->insert = copy;
1702     if (comp->has_use) {
1703         if (comp->use != NULL) {
1704             xsltApplyAttributeSet(ctxt, node, inst, comp->use);
1705         } else {
1706             attributes = xsltEvalAttrValueTemplate(ctxt, inst,
1707                        (const xmlChar *)"use-attribute-sets", XSLT_NAMESPACE);
1708             if (attributes != NULL) {
1709                 xsltApplyAttributeSet(ctxt, node, inst, attributes);
1710                 xmlFree(attributes);
1711             }
1712         }
1713     }
1714     
1715     varsPush(ctxt, NULL);
1716     xsltApplyOneTemplate(ctxt, ctxt->node, inst->children, 0);
1717     xsltFreeStackElemList(varsPop(ctxt));
1718
1719     ctxt->insert = oldInsert;
1720
1721 error:
1722     if (prop != NULL)
1723         xmlFree(prop);
1724     if (ncname != NULL)
1725         xmlFree(ncname);
1726     if (prefix != NULL)
1727         xmlFree(prefix);
1728     if (value != NULL)
1729         xmlFree(value);
1730 }
1731
1732 /**
1733  * xsltAttribute:
1734  * @ctxt:  a XSLT process context
1735  * @node:  the node in the source tree.
1736  * @inst:  the xslt attribute node
1737  * @comp:  precomputed informations
1738  *
1739  * Process the xslt attribute node on the source node
1740  */
1741 void
1742 xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
1743                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
1744     xmlChar *prop = NULL;
1745     xmlChar *ncname = NULL, *name, *namespace;
1746     xmlChar *prefix = NULL;
1747     xmlChar *value = NULL;
1748     xmlNsPtr ns = NULL;
1749     xmlAttrPtr attr;
1750
1751
1752     if (ctxt->insert == NULL)
1753         return;
1754     if (comp == NULL) {
1755         xsltGenericError(xsltGenericErrorContext,
1756              "xsl:attribute : compilation failed\n");
1757         return;
1758     }
1759
1760     if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
1761         return;
1762     if (!comp->has_name) {
1763         return;
1764     }
1765     if (ctxt->insert->children != NULL) {
1766         xsltGenericError(xsltGenericErrorContext,
1767              "xsl:attribute : node has already children\n");
1768         return;
1769     }
1770     if (comp->name == NULL) {
1771         prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name",
1772                                          XSLT_NAMESPACE);
1773         if (prop == NULL) {
1774             xsltGenericError(xsltGenericErrorContext,
1775                  "xsl:attribute : name is missing\n");
1776             goto error;
1777         }
1778         name = prop;
1779     } else {
1780         name = comp->name;
1781     }
1782
1783     ncname = xmlSplitQName2(name, &prefix);
1784     if (ncname == NULL) {
1785         prefix = NULL;
1786     } else {
1787         name = ncname;
1788     }
1789     if (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)) {
1790 #ifdef WITH_XSLT_DEBUG_PARSING
1791         xsltGenericDebug(xsltGenericDebugContext,
1792              "xsl:attribute : xml prefix forbidden\n");
1793 #endif
1794         goto error;
1795     }
1796     if ((comp->ns == NULL) && (comp->has_ns)) {
1797         namespace = xsltEvalAttrValueTemplate(ctxt, inst,
1798                 (const xmlChar *)"namespace", XSLT_NAMESPACE);
1799         if (namespace != NULL) {
1800             ns = xsltGetSpecialNamespace(ctxt, inst, namespace, prefix,
1801                                          ctxt->insert);
1802             xmlFree(namespace);
1803         } else {
1804             if (prefix != NULL) {
1805                 ns = xmlSearchNs(inst->doc, inst, prefix);
1806                 if (ns == NULL) {
1807                     xsltGenericError(xsltGenericErrorContext,
1808                         "xsl:attribute : no namespace bound to prefix %s\n", prefix);
1809                 } else {
1810                     ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
1811                 }
1812             }
1813         }
1814     } else if (comp->ns != NULL) {
1815         ns = xsltGetSpecialNamespace(ctxt, inst, comp->ns, prefix,
1816                                      ctxt->insert);
1817     }
1818
1819     value = xsltEvalTemplateString(ctxt, node, inst);
1820     if (value == NULL) {
1821         if (ns) {
1822             attr = xmlSetNsProp(ctxt->insert, ns, name, 
1823                                 (const xmlChar *)"");
1824         } else
1825             attr = xmlSetProp(ctxt->insert, name, (const xmlChar *)"");
1826     } else {
1827         if (ns) {
1828             attr = xmlSetNsProp(ctxt->insert, ns, name, value);
1829         } else
1830             attr = xmlSetProp(ctxt->insert, name, value);
1831         
1832     }
1833
1834 error:
1835     if (prop != NULL)
1836         xmlFree(prop);
1837     if (ncname != NULL)
1838         xmlFree(ncname);
1839     if (prefix != NULL)
1840         xmlFree(prefix);
1841     if (value != NULL)
1842         xmlFree(value);
1843 }
1844
1845
1846 /**
1847  * xsltComment:
1848  * @ctxt:  a XSLT process context
1849  * @node:  the node in the source tree.
1850  * @inst:  the xslt comment node
1851  * @comp:  precomputed informations
1852  *
1853  * Process the xslt comment node on the source node
1854  */
1855 void
1856 xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
1857                    xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
1858     xmlChar *value = NULL;
1859     xmlNodePtr comment;
1860
1861     value = xsltEvalTemplateString(ctxt, node, inst);
1862     /* TODO: use or generate the compiled form */
1863     /* TODO: check that there is no -- sequence and doesn't end up with - */
1864 #ifdef WITH_XSLT_DEBUG_PROCESS
1865     if (value == NULL)
1866         xsltGenericDebug(xsltGenericDebugContext,
1867              "xsl:comment: empty\n");
1868     else
1869         xsltGenericDebug(xsltGenericDebugContext,
1870              "xsl:comment: content %s\n", value);
1871 #endif
1872
1873     comment = xmlNewComment(value);
1874     xmlAddChild(ctxt->insert, comment);
1875
1876     if (value != NULL)
1877         xmlFree(value);
1878 }
1879
1880 /**
1881  * xsltProcessingInstruction:
1882  * @ctxt:  a XSLT process context
1883  * @node:  the node in the source tree.
1884  * @inst:  the xslt processing-instruction node
1885  * @comp:  precomputed informations
1886  *
1887  * Process the xslt processing-instruction node on the source node
1888  */
1889 void
1890 xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
1891                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
1892     xmlChar *ncname = NULL, *name;
1893     xmlChar *value = NULL;
1894     xmlNodePtr pi;
1895
1896
1897     if (ctxt->insert == NULL)
1898         return;
1899     if (comp->has_name == 0)
1900         return;
1901     if (comp->name == NULL) {
1902         ncname = xsltEvalAttrValueTemplate(ctxt, inst,
1903                             (const xmlChar *)"name", XSLT_NAMESPACE);
1904         if (ncname == NULL) {
1905             xsltGenericError(xsltGenericErrorContext,
1906                  "xsl:processing-instruction : name is missing\n");
1907             goto error;
1908         }
1909         name = ncname;
1910     } else {
1911         name = comp->name;
1912     }
1913     /* TODO: check that it's both an an NCName and a PITarget. */
1914
1915
1916     value = xsltEvalTemplateString(ctxt, node, inst);
1917     /* TODO: check that there is no ?> sequence */
1918 #ifdef WITH_XSLT_DEBUG_PROCESS
1919     if (value == NULL)
1920         xsltGenericDebug(xsltGenericDebugContext,
1921              "xsl:processing-instruction: %s empty\n", ncname);
1922     else
1923         xsltGenericDebug(xsltGenericDebugContext,
1924              "xsl:processing-instruction: %s content %s\n", ncname, value);
1925 #endif
1926
1927     pi = xmlNewPI(name, value);
1928     xmlAddChild(ctxt->insert, pi);
1929
1930 error:
1931     if (ncname != NULL)
1932         xmlFree(ncname);
1933     if (value != NULL)
1934         xmlFree(value);
1935 }
1936
1937 /**
1938  * xsltCopyOf:
1939  * @ctxt:  a XSLT process context
1940  * @node:  the node in the source tree.
1941  * @inst:  the xslt copy-of node
1942  * @comp:  precomputed informations
1943  *
1944  * Process the xslt copy-of node on the source node
1945  */
1946 void
1947 xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
1948                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
1949     xmlXPathObjectPtr res = NULL;
1950     xmlNodePtr copy = NULL;
1951     xmlNodeSetPtr list = NULL;
1952     int i;
1953     int oldProximityPosition, oldContextSize;
1954     int oldNsNr;
1955     xmlNsPtr *oldNamespaces;
1956
1957     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
1958         return;
1959     if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
1960         xsltGenericError(xsltGenericErrorContext,
1961              "xsl:copy-of : compilation failed\n");
1962         return;
1963     }
1964
1965 #ifdef WITH_XSLT_DEBUG_PROCESS
1966     xsltGenericDebug(xsltGenericDebugContext,
1967          "xsltCopyOf: select %s\n", comp->select);
1968 #endif
1969
1970     oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
1971     oldContextSize = ctxt->xpathCtxt->contextSize;
1972     oldNsNr = ctxt->xpathCtxt->nsNr;
1973     oldNamespaces = ctxt->xpathCtxt->namespaces;
1974     ctxt->xpathCtxt->node = node;
1975     ctxt->xpathCtxt->namespaces = comp->nsList;
1976     ctxt->xpathCtxt->nsNr = comp->nsNr;
1977     res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1978     ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
1979     ctxt->xpathCtxt->contextSize = oldContextSize;
1980     ctxt->xpathCtxt->nsNr = oldNsNr;
1981     ctxt->xpathCtxt->namespaces = oldNamespaces;
1982     if (res != NULL) {
1983         if (res->type == XPATH_NODESET) {
1984 #ifdef WITH_XSLT_DEBUG_PROCESS
1985             xsltGenericDebug(xsltGenericDebugContext,
1986                  "xsltCopyOf: result is a node set\n");
1987 #endif
1988             list = res->nodesetval;
1989             if (list != NULL) {
1990                 /* sort the list in document order */
1991                 xsltDocumentSortFunction(list);
1992                 /* append everything in this order under ctxt->insert */
1993                 for (i = 0;i < list->nodeNr;i++) {
1994                     if (list->nodeTab[i] == NULL)
1995                         continue;
1996                     if ((list->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1997                         (list->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) {
1998                         xsltCopyTreeList(ctxt, list->nodeTab[i]->children,
1999                                          ctxt->insert);
2000                     } else if (list->nodeTab[i]->type == XML_ATTRIBUTE_NODE) {
2001                         xsltCopyProp(ctxt, ctxt->insert, 
2002                                      (xmlAttrPtr) list->nodeTab[i]);
2003                     } else {
2004                         xsltCopyTree(ctxt, list->nodeTab[i], ctxt->insert);
2005                     }
2006                 }
2007             }
2008         } else if (res->type == XPATH_XSLT_TREE) {
2009 #ifdef WITH_XSLT_DEBUG_PROCESS
2010             xsltGenericDebug(xsltGenericDebugContext,
2011                  "xsltCopyOf: result is a result tree fragment\n");
2012 #endif
2013             list = res->nodesetval;
2014             if ((list != NULL) && (list->nodeTab != NULL) &&
2015                 (list->nodeTab[0] != NULL)) {
2016                 xsltCopyTreeList(ctxt, list->nodeTab[0]->children,
2017                                  ctxt->insert);
2018             }
2019         } else {
2020             /* convert to a string */
2021             res = xmlXPathConvertString(res);
2022             if ((res != NULL) && (res->type == XPATH_STRING)) {
2023                 /* append content as text node */
2024                 copy = xmlNewText(res->stringval);
2025                 if (copy != NULL) {
2026                     xmlAddChild(ctxt->insert, copy);
2027                 }
2028             }
2029             if (copy == NULL) {
2030                 xsltGenericError(xsltGenericErrorContext,
2031                     "xsltCopyOf: text copy failed\n");
2032             }
2033 #ifdef WITH_XSLT_DEBUG_PROCESS
2034             else
2035                 xsltGenericDebug(xsltGenericDebugContext,
2036                      "xsltCopyOf: result %s\n", res->stringval);
2037 #endif
2038         }
2039     }
2040
2041     if (res != NULL)
2042         xmlXPathFreeObject(res);
2043 }
2044
2045 /**
2046  * xsltValueOf:
2047  * @ctxt:  a XSLT process context
2048  * @node:  the node in the source tree.
2049  * @inst:  the xslt value-of node
2050  * @comp:  precomputed informations
2051  *
2052  * Process the xslt value-of node on the source node
2053  */
2054 void
2055 xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
2056                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
2057     xmlXPathObjectPtr res = NULL;
2058     xmlNodePtr copy = NULL;
2059     int oldProximityPosition, oldContextSize;
2060     int oldNsNr;
2061     xmlNsPtr *oldNamespaces;
2062
2063     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
2064         return;
2065     if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
2066         xsltGenericError(xsltGenericErrorContext,
2067              "xsl:value-of : compilation failed\n");
2068         return;
2069     }
2070
2071 #ifdef WITH_XSLT_DEBUG_PROCESS
2072     xsltGenericDebug(xsltGenericDebugContext,
2073          "xsltValueOf: select %s\n", comp->select);
2074 #endif
2075
2076     oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2077     oldContextSize = ctxt->xpathCtxt->contextSize;
2078     oldNsNr = ctxt->xpathCtxt->nsNr;
2079     oldNamespaces = ctxt->xpathCtxt->namespaces;
2080     ctxt->xpathCtxt->node = node;
2081     ctxt->xpathCtxt->namespaces = comp->nsList;
2082     ctxt->xpathCtxt->nsNr = comp->nsNr;
2083     res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
2084     ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2085     ctxt->xpathCtxt->contextSize = oldContextSize;
2086     ctxt->xpathCtxt->nsNr = oldNsNr;
2087     ctxt->xpathCtxt->namespaces = oldNamespaces;
2088     if (res != NULL) {
2089         if (res->type != XPATH_STRING)
2090             res = xmlXPathConvertString(res);
2091         if (res->type == XPATH_STRING) {
2092             copy = xmlNewText(res->stringval);
2093             if (copy != NULL) {
2094                 if (comp->noescape)
2095                     copy->name = xmlStringTextNoenc;
2096                 xmlAddChild(ctxt->insert, copy);
2097             }
2098         }
2099     }
2100     if (copy == NULL) {
2101         xsltGenericError(xsltGenericErrorContext,
2102             "xsltValueOf: text copy failed\n");
2103     }
2104 #ifdef WITH_XSLT_DEBUG_PROCESS
2105     else
2106         xsltGenericDebug(xsltGenericDebugContext,
2107              "xsltValueOf: result %s\n", res->stringval);
2108 #endif
2109     if (res != NULL)
2110         xmlXPathFreeObject(res);
2111 }
2112
2113 /**
2114  * xsltNumber:
2115  * @ctxt:  a XSLT process context
2116  * @node:  the node in the source tree.
2117  * @inst:  the xslt number node
2118  * @comp:  precomputed informations
2119  *
2120  * Process the xslt number node on the source node
2121  */
2122 void
2123 xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
2124            xmlNodePtr inst, xsltStylePreCompPtr comp)
2125 {
2126     if (comp == NULL) {
2127         xsltGenericError(xsltGenericErrorContext,
2128              "xsl:number : compilation failed\n");
2129         return;
2130     }
2131
2132     if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
2133         return;
2134
2135     comp->numdata.doc = inst->doc;
2136     comp->numdata.node = inst;
2137     
2138     xsltNumberFormat(ctxt, &comp->numdata, node);
2139 }
2140
2141 /**
2142  * xsltApplyImports:
2143  * @ctxt:  a XSLT process context
2144  * @node:  the node in the source tree.
2145  * @inst:  the xslt apply-imports node
2146  * @comp:  precomputed informations
2147  *
2148  * Process the xslt apply-imports node on the source node
2149  */
2150 void
2151 xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr node,
2152                  xmlNodePtr inst ATTRIBUTE_UNUSED, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
2153     xsltTemplatePtr template;
2154
2155     if ((ctxt->templ == NULL) || (ctxt->templ->style == NULL)) {
2156         xsltGenericError(xsltGenericErrorContext,
2157              "xsl:apply-imports : internal error no current template\n");
2158         return;
2159     }
2160     template = xsltGetTemplate(ctxt, node, ctxt->templ->style);
2161     if (template != NULL) {
2162         templPush(ctxt, template);
2163         varsPush(ctxt, NULL);
2164         xsltApplyOneTemplate(ctxt, node, template->content, 1);
2165         xsltFreeStackElemList(varsPop(ctxt));
2166         templPop(ctxt);
2167     }
2168 }
2169
2170 /**
2171  * xsltCallTemplate:
2172  * @ctxt:  a XSLT process context
2173  * @node:  the node in the source tree.
2174  * @inst:  the xslt call-template node
2175  * @comp:  precomputed informations
2176  *
2177  * Process the xslt call-template node on the source node
2178  */
2179 void
2180 xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
2181                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
2182     xmlNodePtr cur = NULL;
2183     xsltStackElemPtr params = NULL, param;
2184
2185
2186     if (ctxt->insert == NULL)
2187         return;
2188     if (comp == NULL) {
2189         xsltGenericError(xsltGenericErrorContext,
2190              "xsl:call-template : compilation failed\n");
2191         return;
2192     }
2193
2194     /*
2195      * The template must have been precomputed
2196      */
2197     if (comp->templ == NULL) {
2198         comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
2199         if (comp->templ == NULL) {
2200             xsltGenericError(xsltGenericErrorContext,
2201                  "xsl:call-template : template %s not found\n", comp->name);
2202             return;
2203         }
2204     }
2205
2206     /*
2207      * Create a new frame but block access to variables
2208      */
2209     templPush(ctxt, comp->templ);
2210     cur = inst->children;
2211     while (cur != NULL) {
2212         if (ctxt->state == XSLT_STATE_STOPPED) break;
2213         if (IS_XSLT_ELEM(cur)) {
2214             if (IS_XSLT_NAME(cur, "with-param")) {
2215                 param = xsltParseStylesheetCallerParam(ctxt, cur);
2216                 if (param != NULL) {
2217                     param->next = params;
2218                     params = param;
2219                 }
2220             } else {
2221                 xsltGenericError(xsltGenericDebugContext,
2222                      "xsl:call-template: misplaced xsl:%s\n", cur->name);
2223             }
2224         } else {
2225             xsltGenericError(xsltGenericDebugContext,
2226                  "xsl:call-template: misplaced %s element\n", cur->name);
2227         }
2228         cur = cur->next;
2229     }
2230     varsPush(ctxt, params);
2231     xsltApplyOneTemplate(ctxt, node, comp->templ->content, 1);
2232     xsltFreeStackElemList(varsPop(ctxt));
2233     templPop(ctxt);
2234 }
2235
2236 /**
2237  * xsltApplyTemplates:
2238  * @ctxt:  a XSLT process context
2239  * @node:  the node in the source tree.
2240  * @inst:  the apply-templates node
2241  * @comp:  precomputed informations
2242  *
2243  * Process the apply-templates node on the source node
2244  */
2245 void
2246 xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
2247                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
2248     xmlNodePtr cur, delete = NULL, oldNode;
2249     xmlXPathObjectPtr res = NULL;
2250     xmlNodeSetPtr list = NULL, oldList;
2251     int i, oldProximityPosition, oldContextSize;
2252     const xmlChar *oldMode, *oldModeURI;
2253     xsltStackElemPtr params = NULL, param, tmp, p;
2254     int nbsorts = 0;
2255     xmlNodePtr sorts[XSLT_MAX_SORT];
2256     xmlDocPtr oldXDocPtr;
2257     xsltDocumentPtr oldCDocPtr;
2258     int oldNsNr;
2259     xmlNsPtr *oldNamespaces;
2260
2261     if (comp == NULL) {
2262         xsltGenericError(xsltGenericErrorContext,
2263              "xsl:apply-templates : compilation failed\n");
2264         return;
2265     }
2266     if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
2267         return;
2268
2269 #ifdef WITH_XSLT_DEBUG_PROCESS
2270     if ((node != NULL) && (node->name != NULL))
2271         xsltGenericDebug(xsltGenericDebugContext,
2272              "xsltApplyTemplates: node: %s\n", node->name);
2273 #endif
2274
2275     /*
2276      * Get mode if any
2277      */
2278     oldNode = ctxt->node;
2279     oldMode = ctxt->mode;
2280     oldModeURI = ctxt->modeURI;
2281     ctxt->mode = comp->mode;
2282     ctxt->modeURI = comp->modeURI;
2283
2284     /*
2285      * The xpath context size and proximity position, as
2286      * well as the xpath and context documents, may be changed
2287      * so we save their initial state and will restore on exit
2288      */
2289     oldXDocPtr = ctxt->xpathCtxt->doc;
2290     oldCDocPtr = ctxt->document;
2291     oldContextSize = ctxt->xpathCtxt->contextSize;
2292     oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2293     oldNsNr = ctxt->xpathCtxt->nsNr;
2294     oldNamespaces = ctxt->xpathCtxt->namespaces;
2295     oldList = ctxt->nodeList;
2296
2297     if (comp->select != NULL) {
2298         if (comp->comp == NULL) {
2299             xsltGenericError(xsltGenericErrorContext,
2300                  "xsl:apply-templates : compilation failed\n");
2301             goto error;
2302         }
2303 #ifdef WITH_XSLT_DEBUG_PROCESS
2304         xsltGenericDebug(xsltGenericDebugContext,
2305              "xsltApplyTemplates: select %s\n", comp->select);
2306 #endif
2307
2308         ctxt->xpathCtxt->node = node;
2309         ctxt->xpathCtxt->namespaces = comp->nsList;
2310         ctxt->xpathCtxt->nsNr = comp->nsNr;
2311         res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
2312         ctxt->xpathCtxt->contextSize = oldContextSize;
2313         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2314         if (res != NULL) {
2315             if (res->type == XPATH_NODESET) {
2316                 list = res->nodesetval;
2317                 res->nodesetval = NULL;
2318              } else {
2319                 list = NULL;
2320              }
2321         }
2322         if (list == NULL) {
2323 #ifdef WITH_XSLT_DEBUG_PROCESS
2324             xsltGenericDebug(xsltGenericDebugContext,
2325                 "xsltApplyTemplates: select didn't evaluate to a node list\n");
2326 #endif
2327             goto error;
2328         }
2329     } else {
2330         /*
2331          * Build an XPath nodelist with the children
2332          */
2333         list = xmlXPathNodeSetCreate(NULL);
2334         cur = node->children;
2335         while (cur != NULL) {
2336             switch (cur->type) {
2337                 case XML_TEXT_NODE:
2338                     if ((IS_BLANK_NODE(cur)) &&
2339                         (cur->parent != NULL) &&
2340                         (ctxt->style->stripSpaces != NULL)) {
2341                         const xmlChar *val;
2342
2343                         val = (const xmlChar *)
2344                               xmlHashLookup(ctxt->style->stripSpaces,
2345                                             cur->parent->name);
2346                         if ((val != NULL) &&
2347                             (xmlStrEqual(val, (xmlChar *) "strip"))) {
2348                             delete = cur;
2349                             break;
2350                         }
2351                     }
2352                     /* no break on purpose */
2353                 case XML_DOCUMENT_NODE:
2354                 case XML_HTML_DOCUMENT_NODE:
2355                 case XML_ELEMENT_NODE:
2356                 case XML_CDATA_SECTION_NODE:
2357                 case XML_PI_NODE:
2358                 case XML_COMMENT_NODE:
2359                     xmlXPathNodeSetAdd(list, cur);
2360                     break;
2361                 default:
2362 #ifdef WITH_XSLT_DEBUG_PROCESS
2363                     xsltGenericDebug(xsltGenericDebugContext,
2364                      "xsltApplyTemplates: skipping cur type %d\n",
2365                                      cur->type);
2366 #endif
2367                     delete = cur;
2368             }
2369             cur = cur->next;
2370             if (delete != NULL) {
2371 #ifdef WITH_XSLT_DEBUG_PROCESS
2372                 xsltGenericDebug(xsltGenericDebugContext,
2373                      "xsltApplyTemplates: removing ignorable blank cur\n");
2374 #endif
2375                 xmlUnlinkNode(delete);
2376                 xmlFreeNode(delete);
2377                 delete = NULL;
2378             }
2379         }
2380     }
2381
2382 #ifdef WITH_XSLT_DEBUG_PROCESS
2383     if (list != NULL)
2384     xsltGenericDebug(xsltGenericDebugContext,
2385         "xsltApplyTemplates: list of %d nodes\n", list->nodeNr);
2386 #endif
2387
2388     ctxt->nodeList = list;
2389     ctxt->xpathCtxt->contextSize = list->nodeNr;
2390
2391     /* 
2392      * handle (or skip) the xsl:sort and xsl:with-param
2393      */
2394     cur = inst->children;
2395     while (cur!=NULL) {
2396         if (ctxt->state == XSLT_STATE_STOPPED) break;
2397         if (IS_XSLT_ELEM(cur)) {
2398             if (IS_XSLT_NAME(cur, "with-param")) {
2399                 param = xsltParseStylesheetCallerParam(ctxt, cur);
2400                 if (param != NULL) {
2401                     param->next = params;
2402                     params = param;
2403                 }
2404             } else if (IS_XSLT_NAME(cur, "sort")) {
2405                 if (nbsorts >= XSLT_MAX_SORT) {
2406                     xsltGenericError(xsltGenericDebugContext,
2407                         "xsl:call-template: %s too many sort\n", node->name);
2408                 } else {
2409                     sorts[nbsorts++] = cur;
2410                 }
2411             } else {
2412                 xsltGenericError(xsltGenericDebugContext,
2413                     "xsl:call-template: misplaced xsl:%s\n", cur->name);
2414             }
2415         } else {
2416             xsltGenericError(xsltGenericDebugContext,
2417                  "xsl:call-template: misplaced %s element\n", cur->name);
2418         }
2419         cur = cur->next;
2420     }
2421
2422     if (nbsorts > 0) {
2423         xsltDoSortFunction(ctxt, sorts, nbsorts);
2424     }
2425
2426     for (i = 0;i < list->nodeNr;i++) {
2427         ctxt->node = list->nodeTab[i];
2428         ctxt->xpathCtxt->proximityPosition = i + 1;
2429         /* For a 'select' nodeset, need to check if document has changed */
2430         if ( (list->nodeTab[i]->doc!=NULL) &&
2431              (list->nodeTab[i]->doc->doc!=NULL) &&
2432              (list->nodeTab[i]->doc->doc)!=ctxt->xpathCtxt->doc) {        
2433             /* The nodeset is from another document, so must change */
2434             ctxt->xpathCtxt->doc=list->nodeTab[i]->doc->doc;
2435             if ((ctxt->document =
2436                   xsltFindDocument(ctxt,list->nodeTab[i]->doc->doc))==NULL) { 
2437                 xsltGenericError(xsltGenericErrorContext,
2438                         "xsl:apply-templates : can't find doc\n");
2439                 goto error;
2440             }
2441             ctxt->xpathCtxt->node = list->nodeTab[i];
2442 #ifdef WITH_XSLT_DEBUG_PROCESS
2443         xsltGenericDebug(xsltGenericDebugContext,
2444              "xsltApplyTemplates: Changing document - context doc %s, xpathdoc %s\n",
2445              ctxt->document->doc->URL, ctxt->xpathCtxt->doc->URL);
2446 #endif
2447         }
2448         varsPush(ctxt, params);
2449         xsltProcessOneNode(ctxt, list->nodeTab[i]);
2450         tmp = varsPop(ctxt);
2451         /*
2452          * Free other parameter and variables which may have been
2453          * added to the set defined in the caller.
2454          */
2455         if (params == NULL) {
2456             xsltFreeStackElemList(tmp);
2457         } else if (tmp != params) {
2458             p = tmp;
2459             while ((p != NULL) && (p->next != params))
2460                 p = p->next;
2461             if (p == NULL) {
2462                 xsltFreeStackElemList(tmp);
2463             } else {
2464                 p->next = NULL;
2465                 xsltFreeStackElemList(tmp);
2466             }
2467         }
2468     }
2469     xsltFreeStackElemList(params);      /* free the parameter list */
2470 error:
2471
2472     ctxt->nodeList = oldList;
2473     ctxt->xpathCtxt->contextSize = oldContextSize;
2474     ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2475     ctxt->xpathCtxt->doc = oldXDocPtr;
2476     ctxt->document = oldCDocPtr;
2477     ctxt->xpathCtxt->nsNr = oldNsNr;
2478     ctxt->xpathCtxt->namespaces = oldNamespaces;
2479
2480     ctxt->node = oldNode;
2481     ctxt->mode = oldMode;
2482     ctxt->modeURI = oldModeURI;
2483     if (res != NULL)
2484         xmlXPathFreeObject(res);
2485     if (list != NULL)
2486         xmlXPathFreeNodeSet(list);
2487 }
2488
2489
2490 /**
2491  * xsltChoose:
2492  * @ctxt:  a XSLT process context
2493  * @node:  the node in the source tree.
2494  * @inst:  the xslt choose node
2495  * @comp:  precomputed informations
2496  *
2497  * Process the xslt choose node on the source node
2498  */
2499 void
2500 xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node,
2501            xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
2502     xmlChar *prop = NULL;
2503     xmlXPathObjectPtr res = NULL;
2504     xmlNodePtr replacement, when;
2505     int doit = 1;
2506     int oldProximityPosition, oldContextSize;
2507     int oldNsNr;
2508     xmlNsPtr *oldNamespaces;
2509
2510     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
2511         return;
2512
2513     /* 
2514      * Check the when's
2515      */
2516     replacement = inst->children;
2517     if (replacement == NULL) {
2518         xsltGenericError(xsltGenericErrorContext,
2519              "xsl:choose: empty content not allowed\n");
2520         goto error;
2521     }
2522     if ((!IS_XSLT_ELEM(replacement)) ||
2523         (!IS_XSLT_NAME(replacement, "when"))) {
2524         xsltGenericError(xsltGenericErrorContext,
2525              "xsl:choose: xsl:when expected first\n");
2526         goto error;
2527     }
2528     while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "when"))) {
2529         xsltStylePreCompPtr wcomp = replacement->_private;
2530
2531         if ((wcomp == NULL) || (wcomp->test == NULL) || (wcomp->comp == NULL)) {
2532             xsltGenericError(xsltGenericErrorContext,
2533                  "xsl:when: compilation failed !\n");
2534             goto error;
2535         }
2536         when = replacement;
2537 #ifdef WITH_XSLT_DEBUG_PROCESS
2538         xsltGenericDebug(xsltGenericDebugContext,
2539              "xsl:when: test %s\n", wcomp->test);
2540 #endif
2541
2542         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2543         oldContextSize = ctxt->xpathCtxt->contextSize;
2544         oldNsNr = ctxt->xpathCtxt->nsNr;
2545         oldNamespaces = ctxt->xpathCtxt->namespaces;
2546         ctxt->xpathCtxt->node = node;
2547         ctxt->xpathCtxt->namespaces = comp->nsList;
2548         ctxt->xpathCtxt->nsNr = comp->nsNr;
2549         res = xmlXPathCompiledEval(wcomp->comp, ctxt->xpathCtxt);
2550         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2551         ctxt->xpathCtxt->contextSize = oldContextSize;
2552         ctxt->xpathCtxt->nsNr = oldNsNr;
2553         ctxt->xpathCtxt->namespaces = oldNamespaces;
2554         if (res != NULL) {
2555             if (res->type != XPATH_BOOLEAN)
2556                 res = xmlXPathConvertBoolean(res);
2557             if (res->type == XPATH_BOOLEAN)
2558                 doit = res->boolval;
2559             else {
2560 #ifdef WITH_XSLT_DEBUG_PROCESS
2561                 xsltGenericDebug(xsltGenericDebugContext,
2562                     "xsl:when: test didn't evaluate to a boolean\n");
2563 #endif
2564                 goto error;
2565             }
2566         }
2567
2568 #ifdef WITH_XSLT_DEBUG_PROCESS
2569         xsltGenericDebug(xsltGenericDebugContext,
2570             "xsl:when: test evaluate to %d\n", doit);
2571 #endif
2572         if (doit) {
2573             varsPush(ctxt, NULL);
2574             xsltApplyOneTemplate(ctxt, ctxt->node, when->children, 0);
2575             xsltFreeStackElemList(varsPop(ctxt));
2576             goto done;
2577         }
2578         if (prop != NULL)
2579             xmlFree(prop);
2580         prop = NULL;
2581         if (res != NULL)
2582             xmlXPathFreeObject(res);
2583         res = NULL;
2584         replacement = replacement->next;
2585     }
2586     if (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "otherwise"))) {
2587         varsPush(ctxt, NULL);
2588         xsltApplyOneTemplate(ctxt, ctxt->node, replacement->children, 0);
2589         xsltFreeStackElemList(varsPop(ctxt));
2590         replacement = replacement->next;
2591     }
2592     if (replacement != NULL) {
2593         xsltGenericError(xsltGenericErrorContext,
2594              "xsl:choose: unexpected content %s\n", replacement->name);
2595         goto error;
2596     }
2597
2598 done:
2599 error:
2600     if (prop != NULL)
2601         xmlFree(prop);
2602     if (res != NULL)
2603         xmlXPathFreeObject(res);
2604 }
2605
2606 /**
2607  * xsltIf:
2608  * @ctxt:  a XSLT process context
2609  * @node:  the node in the source tree.
2610  * @inst:  the xslt if node
2611  * @comp:  precomputed informations
2612  *
2613  * Process the xslt if node on the source node
2614  */
2615 void
2616 xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
2617                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
2618     xmlXPathObjectPtr res = NULL;
2619     int doit = 1;
2620     int oldContextSize, oldProximityPosition;
2621     int oldNsNr;
2622     xmlNsPtr *oldNamespaces;
2623
2624     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
2625         return;
2626     if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
2627         xsltGenericError(xsltGenericErrorContext,
2628              "xsl:if : compilation failed\n");
2629         return;
2630     }
2631
2632 #ifdef WITH_XSLT_DEBUG_PROCESS
2633     xsltGenericDebug(xsltGenericDebugContext,
2634          "xsltIf: test %s\n", comp->test);
2635 #endif
2636
2637     oldContextSize = ctxt->xpathCtxt->contextSize;
2638     oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2639     oldNsNr = ctxt->xpathCtxt->nsNr;
2640     oldNamespaces = ctxt->xpathCtxt->namespaces;
2641     ctxt->xpathCtxt->node = node;
2642     ctxt->xpathCtxt->namespaces = comp->nsList;
2643     ctxt->xpathCtxt->nsNr = comp->nsNr;
2644     res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
2645     ctxt->xpathCtxt->contextSize = oldContextSize;
2646     ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2647     ctxt->xpathCtxt->nsNr = oldNsNr;
2648     ctxt->xpathCtxt->namespaces = oldNamespaces;
2649     if (res != NULL) {
2650         if (res->type != XPATH_BOOLEAN)
2651             res = xmlXPathConvertBoolean(res);
2652         if (res->type == XPATH_BOOLEAN)
2653             doit = res->boolval;
2654         else {
2655 #ifdef WITH_XSLT_DEBUG_PROCESS
2656             xsltGenericDebug(xsltGenericDebugContext,
2657                 "xsltIf: test didn't evaluate to a boolean\n");
2658 #endif
2659             goto error;
2660         }
2661     }
2662
2663 #ifdef WITH_XSLT_DEBUG_PROCESS
2664     xsltGenericDebug(xsltGenericDebugContext,
2665         "xsltIf: test evaluate to %d\n", doit);
2666 #endif
2667     if (doit) {
2668         varsPush(ctxt, NULL);
2669         xsltApplyOneTemplate(ctxt, node, inst->children, 0);
2670         xsltFreeStackElemList(varsPop(ctxt));
2671     }
2672
2673 error:
2674     if (res != NULL)
2675         xmlXPathFreeObject(res);
2676 }
2677
2678 /**
2679  * xsltForEach:
2680  * @ctxt:  a XSLT process context
2681  * @node:  the node in the source tree.
2682  * @inst:  the xslt for-each node
2683  * @comp:  precomputed informations
2684  *
2685  * Process the xslt for-each node on the source node
2686  */
2687 void
2688 xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
2689                    xmlNodePtr inst, xsltStylePreCompPtr comp) {
2690     xmlXPathObjectPtr res = NULL;
2691     xmlNodePtr replacement;
2692     xmlNodeSetPtr list = NULL, oldList;
2693     int i, oldProximityPosition, oldContextSize;
2694     xmlNodePtr oldNode = ctxt->node;
2695     int nbsorts = 0;
2696     xmlNodePtr sorts[XSLT_MAX_SORT];
2697     xmlDocPtr oldXDocPtr;
2698     xsltDocumentPtr oldCDocPtr;
2699     int oldNsNr;
2700     xmlNsPtr *oldNamespaces;
2701
2702     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
2703         return;
2704     if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
2705         xsltGenericError(xsltGenericErrorContext,
2706              "xsl:for-each : compilation failed\n");
2707         return;
2708     }
2709
2710 #ifdef WITH_XSLT_DEBUG_PROCESS
2711     xsltGenericDebug(xsltGenericDebugContext,
2712          "xsltForEach: select %s\n", comp->select);
2713 #endif
2714
2715     oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2716     oldContextSize = ctxt->xpathCtxt->contextSize;
2717     oldNsNr = ctxt->xpathCtxt->nsNr;
2718     oldNamespaces = ctxt->xpathCtxt->namespaces;
2719     ctxt->xpathCtxt->node = node;
2720     ctxt->xpathCtxt->namespaces = comp->nsList;
2721     ctxt->xpathCtxt->nsNr = comp->nsNr;
2722     oldCDocPtr = ctxt->document;
2723     oldXDocPtr = ctxt->xpathCtxt->doc;
2724     res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
2725     ctxt->xpathCtxt->contextSize = oldContextSize;
2726     ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2727     ctxt->xpathCtxt->nsNr = oldNsNr;
2728     ctxt->xpathCtxt->namespaces = oldNamespaces;
2729     if (res != NULL) {
2730         if (res->type == XPATH_NODESET)
2731             list = res->nodesetval;
2732     }
2733     if (list == NULL) {
2734 #ifdef WITH_XSLT_DEBUG_PROCESS
2735         xsltGenericDebug(xsltGenericDebugContext,
2736             "xsltForEach: select didn't evaluate to a node list\n");
2737 #endif
2738         goto error;
2739     }
2740
2741 #ifdef WITH_XSLT_DEBUG_PROCESS
2742     xsltGenericDebug(xsltGenericDebugContext,
2743         "xsltForEach: select evaluates to %d nodes\n", list->nodeNr);
2744 #endif
2745
2746     oldList = ctxt->nodeList;
2747     ctxt->nodeList = list;
2748     oldContextSize = ctxt->xpathCtxt->contextSize;
2749     oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2750     ctxt->xpathCtxt->contextSize = list->nodeNr;
2751
2752     /* 
2753      * handle and skip the xsl:sort
2754      */
2755     replacement = inst->children;
2756     while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "sort"))) {
2757         if (nbsorts >= XSLT_MAX_SORT) {
2758             xsltGenericError(xsltGenericDebugContext,
2759                 "xsl:for-each: too many sort\n");
2760         } else {
2761             sorts[nbsorts++] = replacement;
2762         }
2763         replacement = replacement->next;
2764     }
2765
2766     if (nbsorts > 0) {
2767         xsltDoSortFunction(ctxt, sorts, nbsorts);
2768     }
2769
2770
2771     for (i = 0;i < list->nodeNr;i++) {
2772         ctxt->node = list->nodeTab[i];
2773         ctxt->xpathCtxt->proximityPosition = i + 1;
2774         /* For a 'select' nodeset, need to check if document has changed */
2775         if ( (list->nodeTab[i]->doc!=NULL) &&
2776              (list->nodeTab[i]->doc->doc!=NULL) &&
2777              (list->nodeTab[i]->doc->doc)!=ctxt->xpathCtxt->doc) {        
2778             /* The nodeset is from another document, so must change */
2779             ctxt->xpathCtxt->doc=list->nodeTab[i]->doc->doc;
2780             if ((ctxt->document =
2781                   xsltFindDocument(ctxt,list->nodeTab[i]->doc->doc))==NULL) { 
2782                 xsltGenericError(xsltGenericErrorContext,
2783                         "xsl:apply-templates : can't find doc\n");
2784                 goto error;
2785             }
2786             ctxt->xpathCtxt->node = list->nodeTab[i];
2787 #ifdef WITH_XSLT_DEBUG_PROCESS
2788         xsltGenericDebug(xsltGenericDebugContext,
2789              "xsltApplyTemplates: Changing document - context doc %s, xpathdoc %s\n",
2790              ctxt->document->doc->URL, ctxt->xpathCtxt->doc->URL);
2791 #endif
2792         }
2793         /* ctxt->insert = oldInsert; */
2794         varsPush(ctxt, NULL);
2795         xsltApplyOneTemplate(ctxt, list->nodeTab[i], replacement, 0);
2796         xsltFreeStackElemList(varsPop(ctxt));
2797     }
2798     ctxt->document = oldCDocPtr;
2799     ctxt->nodeList = oldList;
2800     ctxt->node = oldNode;
2801     ctxt->xpathCtxt->doc = oldXDocPtr;
2802     ctxt->xpathCtxt->contextSize = oldContextSize;
2803     ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2804     ctxt->xpathCtxt->nsNr = oldNsNr;
2805     ctxt->xpathCtxt->namespaces = oldNamespaces;
2806
2807 error:
2808     if (res != NULL)
2809         xmlXPathFreeObject(res);
2810 }
2811
2812 /************************************************************************
2813  *                                                                      *
2814  *                      Generic interface                               *
2815  *                                                                      *
2816  ************************************************************************/
2817
2818 #ifdef XSLT_GENERATE_HTML_DOCTYPE
2819 typedef struct xsltHTMLVersion {
2820     const char *version;
2821     const char *public;
2822     const char *system;
2823 } xsltHTMLVersion;
2824
2825 static xsltHTMLVersion xsltHTMLVersions[] = {
2826     { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
2827       "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
2828     { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
2829       "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
2830     { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
2831       "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
2832     { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
2833       "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
2834     { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
2835       "http://www.w3.org/TR/html4/strict.dtd"},
2836     { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
2837       "http://www.w3.org/TR/html4/loose.dtd"},
2838     { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
2839       "http://www.w3.org/TR/html4/frameset.dtd"},
2840     { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
2841       "http://www.w3.org/TR/html4/loose.dtd"},
2842     { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
2843 };
2844
2845 /**
2846  * xsltGetHTMLIDs:
2847  * @version:  the version string
2848  * @public:  used to return the public ID
2849  * @system:  used to return the system ID
2850  *
2851  * Returns -1 if not found, 0 otherwise and the system and public
2852  *         Identifier for this given verion of HTML
2853  */
2854 static int
2855 xsltGetHTMLIDs(const xmlChar *version, const xmlChar **public,
2856                     const xmlChar **system) {
2857     unsigned int i;
2858     if (version == NULL)
2859         return(-1);
2860     for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
2861          i++) {
2862         if (!xmlStrcasecmp(version,
2863                            (const xmlChar *) xsltHTMLVersions[i].version)) {
2864             if (public != NULL)
2865                 *public = (const xmlChar *) xsltHTMLVersions[i].public;
2866             if (system != NULL)
2867                 *system = (const xmlChar *) xsltHTMLVersions[i].system;
2868             return(0);
2869         }
2870     }
2871     return(-1);
2872 }
2873 #endif
2874
2875 /**
2876  * xsltApplyStylesheetInternal:
2877  * @style:  a parsed XSLT stylesheet
2878  * @doc:  a parsed XML document
2879  * @params:  a NULL terminated arry of parameters names/values tuples
2880  * @output:  the targetted output
2881  *
2882  * Apply the stylesheet to the document
2883  * NOTE: This may lead to a non-wellformed output XML wise !
2884  *
2885  * Returns the result document or NULL in case of error
2886  */
2887 static xmlDocPtr
2888 xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
2889                     const char **params, const char *output) {
2890     xmlDocPtr res = NULL;
2891     xsltTransformContextPtr ctxt = NULL;
2892     xmlNodePtr root;
2893     const xmlChar *method;
2894     const xmlChar *doctypePublic;
2895     const xmlChar *doctypeSystem;
2896     const xmlChar *version;
2897     xsltStackElemPtr variables;
2898     xsltStackElemPtr vptr;
2899
2900
2901     if ((style == NULL) || (doc == NULL))
2902         return(NULL);
2903     ctxt = xsltNewTransformContext(style, doc);
2904     if (ctxt == NULL)
2905         return(NULL);
2906     xsltRegisterExtras(ctxt);
2907     if (output != NULL)
2908         ctxt->outputFile = output;
2909     else
2910         ctxt->outputFile = NULL;
2911
2912     XSLT_GET_IMPORT_PTR(method, style, method)
2913     XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
2914     XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
2915     XSLT_GET_IMPORT_PTR(version, style, version)
2916
2917     if ((method != NULL) &&
2918         (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
2919         if (xmlStrEqual(method, (const xmlChar *) "html")) {
2920             ctxt->type = XSLT_OUTPUT_HTML;
2921             if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
2922                 res = htmlNewDoc(doctypeSystem, doctypePublic);
2923             else {
2924                 if (version == NULL)
2925                     version = (const xmlChar *) "4.0";
2926 #ifdef XSLT_GENERATE_HTML_DOCTYPE
2927                 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
2928 #endif
2929                 res = htmlNewDoc(doctypeSystem, doctypePublic);
2930             }
2931             if (res == NULL)
2932                 goto error;
2933         } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
2934             xsltGenericError(xsltGenericErrorContext,
2935              "xsltApplyStylesheet: unsupported method xhtml, using html\n",
2936                              style->method);
2937             ctxt->type = XSLT_OUTPUT_HTML;
2938             res = htmlNewDoc(doctypeSystem, doctypePublic);
2939             if (res == NULL)
2940                 goto error;
2941         } else if (xmlStrEqual(style->method, (const xmlChar *) "text")) {
2942             ctxt->type = XSLT_OUTPUT_TEXT;
2943             res = xmlNewDoc(style->version);
2944             if (res == NULL)
2945                 goto error;
2946         } else {
2947             xsltGenericError(xsltGenericErrorContext,
2948                              "xsltApplyStylesheet: unsupported method %s\n",
2949                              style->method);
2950             goto error;
2951         }
2952     } else {
2953         ctxt->type = XSLT_OUTPUT_XML;
2954         res = xmlNewDoc(style->version);
2955         if (res == NULL)
2956             goto error;
2957     }
2958     res->charset = XML_CHAR_ENCODING_UTF8;
2959     if (style->encoding != NULL)
2960         res->encoding = xmlStrdup(style->encoding);
2961     variables = style->variables;
2962
2963     /*
2964      * Start the evaluation, evaluate the params, the stylesheets globals
2965      * and start by processing the top node.
2966      */
2967     ctxt->output = res;
2968     ctxt->insert = (xmlNodePtr) res;
2969     ctxt->globalVars = xmlHashCreate(20);
2970     if (params != NULL)
2971         xsltEvalUserParams(ctxt, params);
2972     xsltEvalGlobalVariables(ctxt);
2973     ctxt->node = (xmlNodePtr) doc;
2974     varsPush(ctxt, NULL);
2975     xsltProcessOneNode(ctxt, ctxt->node);
2976     xsltFreeStackElemList(varsPop(ctxt));
2977
2978     xsltCleanupTemplates(style); /* TODO: <- style should be read only */
2979
2980     /*
2981      * Now cleanup our variables so stylesheet can be re-used
2982      *
2983      * TODO: this is not needed anymore global variables are copied
2984      *       and not evaluated directly anymore, keep this as a check
2985      */
2986     if (style->variables != variables) {
2987         vptr = style->variables;
2988         while (vptr->next!=variables)
2989             vptr = vptr->next;
2990         vptr->next = NULL;
2991         xsltFreeStackElemList(style->variables);
2992         style->variables = variables;
2993     }
2994     vptr = style->variables;
2995     while(vptr!=NULL) {
2996         if (vptr->computed) {
2997             if (vptr->value != NULL) {
2998                 xmlXPathFreeObject(vptr->value);
2999                 vptr->value = NULL;
3000                 vptr->computed = 0;
3001             }
3002         }
3003         vptr = vptr->next;
3004     }
3005
3006
3007     /*
3008      * Do some post processing work depending on the generated output
3009      */
3010     root = xmlDocGetRootElement(res);
3011     if (root != NULL) {
3012         /*
3013          * Apply the default selection of the method
3014          */
3015         if ((method == NULL) &&
3016             (root->ns == NULL) &&
3017             (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3018             xmlNodePtr tmp;
3019             tmp = res->children;
3020             while ((tmp != NULL) && (tmp != root)) {
3021                 if (tmp->type == XML_ELEMENT_NODE)
3022                     break;
3023                 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3024                     break;
3025             }
3026             if (tmp == root) {
3027                 ctxt->type = XSLT_OUTPUT_HTML;
3028                 res->type = XML_HTML_DOCUMENT_NODE;
3029                 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3030                     res->intSubset = xmlCreateIntSubset(res, root->name,
3031                                  doctypePublic, doctypeSystem);
3032 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3033                 else {
3034                     if (version == NULL)
3035                         version = (const xmlChar *) "4.0";
3036                     xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3037                     if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3038                         res->intSubset = xmlCreateIntSubset(res, root->name,
3039                                      doctypePublic, doctypeSystem);
3040                 }
3041 #endif
3042             }
3043
3044         }
3045         if (ctxt->type == XSLT_OUTPUT_XML) {
3046             XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3047             XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3048             if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3049                 res->intSubset = xmlCreateIntSubset(res, root->name,
3050                              doctypePublic, doctypeSystem);
3051         }
3052     }
3053     xmlXPathFreeNodeSet(ctxt->nodeList);
3054     xsltFreeTransformContext(ctxt);
3055     return(res);
3056
3057 error:
3058     if (res != NULL)
3059         xmlFreeDoc(res);
3060     if (ctxt != NULL)
3061         xsltFreeTransformContext(ctxt);
3062     return(NULL);
3063 }
3064
3065 /**
3066  * xsltApplyStylesheet:
3067  * @style:  a parsed XSLT stylesheet
3068  * @doc:  a parsed XML document
3069  * @params:  a NULL terminated arry of parameters names/values tuples
3070  *
3071  * Apply the stylesheet to the document
3072  * NOTE: This may lead to a non-wellformed output XML wise !
3073  *
3074  * Returns the result document or NULL in case of error
3075  */
3076 xmlDocPtr
3077 xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
3078                     const char **params) {
3079     return(xsltApplyStylesheetInternal(style, doc, params, NULL));
3080 }
3081
3082 /**
3083  * xsltRunStylesheet:
3084  * @style:  a parsed XSLT stylesheet
3085  * @doc:  a parsed XML document
3086  * @params:  a NULL terminated arry of parameters names/values tuples
3087  * @output:  the URL/filename ot the generated resource if available
3088  * @SAX:  a SAX handler for progressive callback output (not implemented yet)
3089  * @IObuf:  an output buffer for progressive output (not implemented yet)
3090  *
3091  * Apply the stylesheet to the document and generate the output according
3092  * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
3093  *
3094  * NOTE: This may lead to a non-wellformed output XML wise !
3095  * NOTE: This may also result in multiple files being generated
3096  * NOTE: using IObuf, the result encoding used will be the one used for
3097  *       creating the output buffer, use the following macro to read it
3098  *       from the stylesheet
3099  *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
3100  * NOTE: using SAX, any encoding specified in the stylesheet will be lost
3101  *       since the interface uses only UTF8
3102  *
3103  * Returns the number of by written to the main resource or -1 in case of
3104  *         error.
3105  */
3106 int
3107 xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, const char **params,
3108                   const char *output, xmlSAXHandlerPtr SAX,
3109                   xmlOutputBufferPtr IObuf)
3110 {
3111     xmlDocPtr tmp;
3112     int ret;
3113
3114     if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
3115         return(-1);
3116     if ((SAX != NULL) && (IObuf != NULL))
3117         return(-1);
3118
3119     /* unsupported yet */
3120     if (SAX != NULL) {
3121         TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
3122         return(-1);
3123     }
3124
3125     tmp = xsltApplyStylesheetInternal(style, doc, params, output);
3126     if (tmp == NULL) {
3127         xsltGenericError(xsltGenericErrorContext,
3128              "xsltRunStylesheet : run failed\n");
3129         return(-1);
3130     }
3131     if (IObuf != NULL) {
3132         /* TODO: incomplete, IObuf output not progressive */
3133         ret = xsltSaveResultTo(IObuf, tmp, style);
3134     } else {
3135         ret = xsltSaveResultToFilename(output, tmp, style, 0);
3136     }
3137     xmlFreeDoc(tmp);
3138     return(ret);
3139 }