2 * transform.c: Implemetation of the XSL Transformation 1.0 engine
3 * transform part, i.e. applying a Stylesheet to a document
6 * http://www.w3.org/TR/1999/REC-xslt-19991116
8 * Michael Kay "XSLT Programmer's Reference" pp 637-643
9 * Writing Multiple Output Files
11 * XSLT-1.1 Working Draft
12 * http://www.w3.org/TR/xslt11#multiple-output
14 * See Copyright for the status of this software.
16 * Daniel.Veillard@imag.fr
19 #include "xsltconfig.h"
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>
36 #include "xsltInternals.h"
37 #include "xsltutils.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"
47 #include "documents.h"
48 #include "extensions.h"
52 #ifdef WITH_XSLT_DEBUG
53 #define WITH_XSLT_DEBUG_PROCESS
56 int xsltMaxDepth = 250;
63 # define FALSE (0 == 1)
64 # define TRUE (!FALSE)
67 #define IS_BLANK_NODE(n) \
68 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
71 * Generic function for accessing stacks in the transform Context
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"); \
86 ctxt->name##Tab[ctxt->name##Nr] = value; \
88 return(ctxt->name##Nr++); \
90 scope type name##Pop(xsltTransformContextPtr ctxt) { \
92 if (ctxt->name##Nr <= 0) return(0); \
94 if (ctxt->name##Nr > 0) \
95 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
98 ret = ctxt->name##Tab[ctxt->name##Nr]; \
99 ctxt->name##Tab[ctxt->name##Nr] = 0; \
104 * Those macros actually generate the functions
106 PUSH_AND_POP(static, xsltTemplatePtr, templ)
107 PUSH_AND_POP(static, xsltStackElemPtr, vars)
109 /************************************************************************
111 * XInclude default settings *
113 ************************************************************************/
115 static int xsltDoXIncludeDefault = 0;
118 * xsltSetXIncludeDefault:
119 * @xinclude: whether to do XInclude processing
121 * Set whether XInclude should be processed on document being loaded by default
124 xsltSetXIncludeDefault(int xinclude) {
125 xsltDoXIncludeDefault = (xinclude != 0);
129 * xsltGetXIncludeDefault:
131 * return the default state for XInclude processing
133 * Returns 0 if there is no processing 1 otherwise
136 xsltGetXIncludeDefault(void) {
137 return(xsltDoXIncludeDefault);
140 /************************************************************************
142 * handling of transformation contexts *
144 ************************************************************************/
147 * xsltNewTransformContext:
148 * @style: a parsed XSLT stylesheet
149 * @doc: the input document
151 * Create a new XSLT TransformContext
153 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
155 static xsltTransformContextPtr
156 xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
157 xsltTransformContextPtr cur;
158 xsltDocumentPtr docu;
160 cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
162 xsltGenericError(xsltGenericErrorContext,
163 "xsltNewTransformContext : malloc failed\n");
166 memset(cur, 0, sizeof(xsltTransformContext));
169 * initialize the template stack
171 cur->templTab = (xsltTemplatePtr *)
172 xmlMalloc(10 * sizeof(xsltTemplatePtr));
173 if (cur->templTab == NULL) {
174 xmlGenericError(xmlGenericErrorContext,
175 "xsltNewTransformContext: out of memory\n");
184 * initialize the variables stack
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);
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);
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);
216 xsltGenericError(xsltGenericErrorContext,
217 "xsltNewTransformContext : xsltNewDocument failed\n");
218 xmlFree(cur->templTab);
219 xmlFree(cur->varsTab);
224 cur->document = docu;
226 cur->xinclude = xsltDoXIncludeDefault;
231 * xsltFreeTransformContext:
232 * @ctxt: an XSLT parser context
234 * Free up the memory allocated by @ctxt
237 xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
240 if (ctxt->xpathCtxt != NULL) {
241 ctxt->xpathCtxt->nsHash = NULL;
242 xmlXPathFreeContext(ctxt->xpathCtxt);
244 if (ctxt->templTab != NULL)
245 xmlFree(ctxt->templTab);
246 if (ctxt->varsTab != NULL)
247 xmlFree(ctxt->varsTab);
248 xsltFreeDocuments(ctxt);
249 xsltFreeCtxtExts(ctxt);
250 xsltFreeGlobalVariables(ctxt);
251 memset(ctxt, -1, sizeof(xsltTransformContext));
255 /************************************************************************
257 * Copy of Nodes in an XSLT fashion *
259 ************************************************************************/
261 xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
266 * @ctxt: a XSLT process context
267 * @target: the element where the attribute will be grafted
268 * @attr: the attribute
270 * Do a copy of an attribute
272 * Returns: a new xmlAttrPtr, or NULL in case of error.
275 xsltCopyProp(xsltTransformContextPtr ctxt, xmlNodePtr target,
277 xmlAttrPtr ret = NULL;
284 if (attr->ns != NULL) {
285 ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
289 val = xmlNodeListGetString(attr->doc, attr->children, 1);
290 ret = xmlSetNsProp(target, ns, attr->name, val);
298 * @ctxt: a XSLT process context
299 * @target: the element where the attributes will be grafted
300 * @cur: the first attribute
302 * Do a copy of an attribute list.
304 * Returns: a new xmlAttrPtr, or NULL in case of error.
307 xsltCopyPropList(xsltTransformContextPtr ctxt, xmlNodePtr target,
309 xmlAttrPtr ret = NULL;
310 xmlAttrPtr p = NULL,q;
313 while (cur != NULL) {
314 if (cur->ns != NULL) {
315 ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target);
319 q = xmlCopyProp(target, cur);
337 * @ctxt: a XSLT process context
338 * @node: the element node in the source tree.
339 * @insert: the parent in the result tree.
341 * Make a copy of the element node @node
342 * and insert it as last child of @insert
344 * Returns a pointer to the new node, or NULL in case of error
347 xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
351 copy = xmlCopyNode(node, 0);
353 copy->doc = ctxt->output;
354 xmlAddChild(insert, copy);
355 if (node->type == XML_ELEMENT_NODE) {
357 * Add namespaces as they are needed
359 if (node->nsDef != NULL)
360 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
362 if (node->ns != NULL) {
363 copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
366 xsltGenericError(xsltGenericErrorContext,
367 "xsltCopyNode: copy %s failed\n", node->name);
374 * @ctxt: a XSLT process context
375 * @list: the list of element node in the source tree.
376 * @insert: the parent in the result tree.
378 * Make a copy of the full list of tree @list
379 * and insert them as last children of @insert
381 * Returns a pointer to the new list, or NULL in case of error
384 xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr list,
386 xmlNodePtr copy, ret = NULL;
388 while (list != NULL) {
389 copy = xsltCopyTree(ctxt, list, insert);
402 * @ctxt: a XSLT process context
403 * @node: the element node in the source tree.
404 * @insert: the parent in the result tree.
406 * Make a copy of the full tree under the element node @node
407 * and insert it as last child of @insert
409 * Returns a pointer to the new tree, or NULL in case of error
412 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
418 switch (node->type) {
419 case XML_ELEMENT_NODE:
421 case XML_CDATA_SECTION_NODE:
422 case XML_ENTITY_REF_NODE:
423 case XML_ENTITY_NODE:
425 case XML_COMMENT_NODE:
426 case XML_DOCUMENT_NODE:
427 case XML_HTML_DOCUMENT_NODE:
428 #ifdef LIBXML_DOCB_ENABLED
429 case XML_DOCB_DOCUMENT_NODE:
432 case XML_ATTRIBUTE_NODE:
434 xsltCopyProp(ctxt, insert, (xmlAttrPtr) node));
435 case XML_NAMESPACE_DECL:
437 xsltCopyNamespaceList(ctxt, insert, (xmlNsPtr) node));
439 case XML_DOCUMENT_TYPE_NODE:
440 case XML_DOCUMENT_FRAG_NODE:
441 case XML_NOTATION_NODE:
443 case XML_ELEMENT_DECL:
444 case XML_ATTRIBUTE_DECL:
445 case XML_ENTITY_DECL:
446 case XML_XINCLUDE_START:
447 case XML_XINCLUDE_END:
450 copy = xmlCopyNode(node, 0);
451 copy->doc = ctxt->output;
453 xmlAddChild(insert, copy);
456 * Add namespaces as they are needed
458 if (node->nsDef != NULL)
459 xsltCopyNamespaceList(ctxt, copy, node->nsDef);
460 if (node->ns != NULL) {
461 copy->ns = xsltGetNamespace(ctxt, node, node->ns, insert);
463 if (node->properties != NULL)
464 copy->properties = xsltCopyPropList(ctxt, copy,
466 if (node->children != NULL)
467 xsltCopyTreeList(ctxt, node->children, copy);
469 xsltGenericError(xsltGenericErrorContext,
470 "xsltCopyTree: copy %s failed\n", node->name);
475 /************************************************************************
477 * Default processing *
479 ************************************************************************/
481 void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node);
483 * xsltDefaultProcessOneNode:
484 * @ctxt: a XSLT process context
485 * @node: the node in the source tree.
487 * Process the source node with the default built-in template rule:
488 * <xsl:template match="*|/">
489 * <xsl:apply-templates/>
494 * <xsl:template match="text()|@*">
495 * <xsl:value-of select="."/>
498 * Note also that namespaces declarations are copied directly:
500 * the built-in template rule is the only template rule that is applied
501 * for namespace nodes.
504 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
507 xmlNodePtr delete = NULL, cur;
508 int strip_spaces = -1;
509 int nbchild = 0, oldSize;
510 int childno = 0, oldPos;
511 xsltTemplatePtr template;
517 switch (node->type) {
518 case XML_DOCUMENT_NODE:
519 case XML_HTML_DOCUMENT_NODE:
520 case XML_ELEMENT_NODE:
522 case XML_CDATA_SECTION_NODE:
523 template = xsltGetTemplate(ctxt, node, NULL);
527 #ifdef WITH_XSLT_DEBUG_PROCESS
528 xsltGenericDebug(xsltGenericDebugContext,
529 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
532 oldNode = ctxt->node;
534 templPush(ctxt, template);
535 xsltApplyOneTemplate(ctxt, node, template->content, 1);
537 ctxt->node = oldNode;
538 } else /* if (ctxt->mode == NULL) */ {
539 #ifdef WITH_XSLT_DEBUG_PROCESS
540 xsltGenericDebug(xsltGenericDebugContext,
541 "xsltDefaultProcessOneNode: copy CDATA %s\n",
544 copy = xmlNewDocText(ctxt->output, node->content);
546 xmlAddChild(ctxt->insert, copy);
548 xsltGenericError(xsltGenericErrorContext,
549 "xsltDefaultProcessOneNode: cdata copy failed\n");
554 template = xsltGetTemplate(ctxt, node, NULL);
558 #ifdef WITH_XSLT_DEBUG_PROCESS
559 xsltGenericDebug(xsltGenericDebugContext,
560 "xsltDefaultProcessOneNode: applying template for text %s\n",
563 oldNode = ctxt->node;
565 templPush(ctxt, template);
566 xsltApplyOneTemplate(ctxt, node, template->content, 1);
568 ctxt->node = oldNode;
569 } else /* if (ctxt->mode == NULL) */ {
570 #ifdef WITH_XSLT_DEBUG_PROCESS
571 if (node->content == NULL)
572 xsltGenericDebug(xsltGenericDebugContext,
573 "xsltDefaultProcessOneNode: copy empty text\n");
575 xsltGenericDebug(xsltGenericDebugContext,
576 "xsltDefaultProcessOneNode: copy text %s\n",
579 copy = xmlCopyNode(node, 0);
581 xmlAddChild(ctxt->insert, copy);
583 xsltGenericError(xsltGenericErrorContext,
584 "xsltDefaultProcessOneNode: text copy failed\n");
588 case XML_ATTRIBUTE_NODE:
589 if (ctxt->insert->type == XML_ELEMENT_NODE) {
590 xmlAttrPtr attr = (xmlAttrPtr) node, ret = NULL, current;
591 template = xsltGetTemplate(ctxt, node, NULL);
595 oldNode = ctxt->node;
597 templPush(ctxt, template);
598 xsltApplyOneTemplate(ctxt, node, template->content, 1);
600 ctxt->node = oldNode;
601 } else if (ctxt->mode == NULL) {
602 if (attr->ns != NULL) {
603 if ((!xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) &&
604 (xmlStrncasecmp(attr->ns->prefix,
605 (xmlChar *)"xml", 3))) {
606 ret = xmlCopyProp(ctxt->insert, attr);
607 ret->ns = xsltGetNamespace(ctxt, node, attr->ns,
611 ret = xmlCopyProp(ctxt->insert, attr);
613 current = ctxt->insert->properties;
614 if (current != NULL) {
615 if ((xmlStrEqual(current->name, ret->name)) &&
616 (current->ns == ret->ns)) {
618 tmp = current->children;
619 current->children = ret->children;
624 while (current->next != NULL) {
625 current = current->next;
626 if ((xmlStrEqual(current->name, ret->name)) &&
627 (current->ns == ret->ns)) {
629 tmp = current->children;
630 current->children = ret->children;
639 ctxt->insert->properties = ret;
647 * Handling of Elements: first pass, cleanup and counting
649 cur = node->children;
650 while (cur != NULL) {
653 if ((IS_BLANK_NODE(cur)) &&
654 (cur->parent != NULL) &&
655 (ctxt->style->stripSpaces != NULL)) {
656 if (strip_spaces == -1)
658 xsltFindElemSpaceHandling(ctxt, cur->parent);
659 if (strip_spaces == 1) {
664 /* no break on purpose */
665 case XML_CDATA_SECTION_NODE:
666 case XML_DOCUMENT_NODE:
667 case XML_HTML_DOCUMENT_NODE:
668 case XML_ELEMENT_NODE:
670 case XML_COMMENT_NODE:
674 #ifdef WITH_XSLT_DEBUG_PROCESS
675 xsltGenericDebug(xsltGenericDebugContext,
676 "xsltDefaultProcessOneNode: skipping node type %d\n",
682 if (delete != NULL) {
683 #ifdef WITH_XSLT_DEBUG_PROCESS
684 xsltGenericDebug(xsltGenericDebugContext,
685 "xsltDefaultProcessOneNode: removing ignorable blank node\n");
687 xmlUnlinkNode(delete);
693 * Handling of Elements: second pass, actual processing
695 attrs = node->properties;
696 while (attrs != NULL) {
697 template = xsltGetTemplate(ctxt, (xmlNodePtr) attrs, NULL);
701 oldNode = ctxt->node;
703 templPush(ctxt, template);
704 xsltApplyOneTemplate(ctxt, node, template->content, 1);
706 ctxt->node = oldNode;
710 oldSize = ctxt->xpathCtxt->contextSize;
711 oldPos = ctxt->xpathCtxt->proximityPosition;
712 cur = node->children;
713 while (cur != NULL) {
716 case XML_DOCUMENT_NODE:
717 case XML_HTML_DOCUMENT_NODE:
718 case XML_ELEMENT_NODE:
719 ctxt->xpathCtxt->contextSize = nbchild;
720 ctxt->xpathCtxt->proximityPosition = childno;
721 varsPush( ctxt, NULL );
722 xsltProcessOneNode(ctxt, cur);
723 xsltFreeStackElemList( varsPop(ctxt) );
725 case XML_CDATA_SECTION_NODE:
726 template = xsltGetTemplate(ctxt, node, NULL);
730 #ifdef WITH_XSLT_DEBUG_PROCESS
731 xsltGenericDebug(xsltGenericDebugContext,
732 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
735 oldNode = ctxt->node;
737 templPush(ctxt, template);
738 xsltApplyOneTemplate(ctxt, node, template->content, 1);
740 ctxt->node = oldNode;
741 } else /* if (ctxt->mode == NULL) */ {
742 #ifdef WITH_XSLT_DEBUG_PROCESS
743 xsltGenericDebug(xsltGenericDebugContext,
744 "xsltDefaultProcessOneNode: copy CDATA %s\n",
747 copy = xmlNewDocText(ctxt->output, node->content);
749 xmlAddChild(ctxt->insert, copy);
751 xsltGenericError(xsltGenericErrorContext,
752 "xsltDefaultProcessOneNode: cdata copy failed\n");
757 template = xsltGetTemplate(ctxt, cur, NULL);
761 #ifdef WITH_XSLT_DEBUG_PROCESS
762 xsltGenericDebug(xsltGenericDebugContext,
763 "xsltDefaultProcessOneNode: applying template for text %s\n",
766 oldNode = ctxt->node;
768 ctxt->xpathCtxt->contextSize = nbchild;
769 ctxt->xpathCtxt->proximityPosition = childno;
770 templPush(ctxt, template);
771 xsltApplyOneTemplate(ctxt, cur, template->content, 1);
773 ctxt->node = oldNode;
774 } else /* if (ctxt->mode == NULL) */ {
775 #ifdef WITH_XSLT_DEBUG_PROCESS
776 if (cur->content == NULL)
777 xsltGenericDebug(xsltGenericDebugContext,
778 "xsltDefaultProcessOneNode: copy empty text\n");
780 xsltGenericDebug(xsltGenericDebugContext,
781 "xsltDefaultProcessOneNode: copy text %s\n",
784 copy = xmlCopyNode(cur, 0);
786 xmlAddChild(ctxt->insert, copy);
788 xsltGenericError(xsltGenericErrorContext,
789 "xsltDefaultProcessOneNode: text copy failed\n");
794 case XML_COMMENT_NODE:
795 template = xsltGetTemplate(ctxt, cur, NULL);
799 #ifdef WITH_XSLT_DEBUG_PROCESS
800 if (cur->type == XML_PI_NODE)
801 xsltGenericDebug(xsltGenericDebugContext,
802 "xsltDefaultProcessOneNode: template found for PI %s\n",
804 else if (cur->type == XML_COMMENT_NODE)
805 xsltGenericDebug(xsltGenericDebugContext,
806 "xsltDefaultProcessOneNode: template found for comment\n");
808 oldNode = ctxt->node;
810 ctxt->xpathCtxt->contextSize = nbchild;
811 ctxt->xpathCtxt->proximityPosition = childno;
812 templPush(ctxt, template);
813 xsltApplyOneTemplate(ctxt, cur, template->content, 1);
815 ctxt->node = oldNode;
823 ctxt->xpathCtxt->contextSize = oldSize;
824 ctxt->xpathCtxt->proximityPosition = oldPos;
828 * xsltProcessOneNode:
829 * @ctxt: a XSLT process context
830 * @node: the node in the source tree.
832 * Process the source node.
835 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
836 xsltTemplatePtr template;
840 * Cleanup children empty nodes if asked for
842 if ((node->children != NULL) &&
843 (xsltFindElemSpaceHandling(ctxt, node))) {
844 xmlNodePtr delete = NULL, cur = node->children;
846 while (cur != NULL) {
847 if (IS_BLANK_NODE(cur))
851 if (delete != NULL) {
852 #ifdef WITH_XSLT_DEBUG_PROCESS
853 xsltGenericDebug(xsltGenericDebugContext,
854 "xsltProcessOneNode: removing ignorable blank node\n");
856 xmlUnlinkNode(delete);
863 template = xsltGetTemplate(ctxt, node, NULL);
865 * If no template is found, apply the default rule.
867 if (template == NULL) {
868 #ifdef WITH_XSLT_DEBUG_PROCESS
869 if (node->type == XML_DOCUMENT_NODE)
870 xsltGenericDebug(xsltGenericDebugContext,
871 "xsltProcessOneNode: no template found for /\n");
872 else if (node->type == XML_CDATA_SECTION_NODE)
873 xsltGenericDebug(xsltGenericDebugContext,
874 "xsltProcessOneNode: no template found for CDATA\n");
875 else if (node->type == XML_ATTRIBUTE_NODE)
876 xsltGenericDebug(xsltGenericDebugContext,
877 "xsltProcessOneNode: no template found for attribute %s\n",
878 ((xmlAttrPtr) node)->name);
880 xsltGenericDebug(xsltGenericDebugContext,
881 "xsltProcessOneNode: no template found for %s\n", node->name);
883 oldNode = ctxt->node;
885 xsltDefaultProcessOneNode(ctxt, node);
886 ctxt->node = oldNode;
890 if (node->type == XML_ATTRIBUTE_NODE) {
891 #ifdef WITH_XSLT_DEBUG_PROCESS
892 xsltGenericDebug(xsltGenericDebugContext,
893 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
894 template->match, node->name);
896 templPush(ctxt, template);
897 xsltApplyOneTemplate(ctxt, node, template->content, 1);
900 #ifdef WITH_XSLT_DEBUG_PROCESS
901 if (node->type == XML_DOCUMENT_NODE)
902 xsltGenericDebug(xsltGenericDebugContext,
903 "xsltProcessOneNode: applying template '%s' for /\n",
906 xsltGenericDebug(xsltGenericDebugContext,
907 "xsltProcessOneNode: applying template '%s' for %s\n",
908 template->match, node->name);
910 oldNode = ctxt->node;
912 templPush(ctxt, template);
913 xsltApplyOneTemplate(ctxt, node, template->content, 1);
915 ctxt->node = oldNode;
920 * xsltApplyOneTemplate:
921 * @ctxt: a XSLT process context
922 * @node: the node in the source tree.
923 * @list: the template replacement nodelist
924 * @real: is this a real template processing
926 * Process the apply-templates node on the source node
929 xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
930 xmlNodePtr list, int real) {
931 xmlNodePtr cur = NULL, insert, copy = NULL;
932 xmlNodePtr oldInsert;
933 xmlNodePtr oldCurrent = NULL;
934 xmlNodePtr oldInst = NULL;
941 if (ctxt->templNr >= xsltMaxDepth) {
942 xsltGenericError(xsltGenericErrorContext,
943 "xsltApplyOneTemplate: loop found ???\n");
944 xsltGenericError(xsltGenericErrorContext,
945 "try increasing xsltMaxDepth (--maxdepth)\n");
946 xsltDebug(ctxt, node, list, NULL);
953 oldInsert = insert = ctxt->insert;
954 oldInst = ctxt->inst;
956 oldCurrent = ctxt->node;
961 * Insert all non-XSLT nodes found in the template
964 while (cur != NULL) {
967 * test, we must have a valid insertion point
969 if (insert == NULL) {
970 #ifdef WITH_XSLT_DEBUG_PROCESS
971 xsltGenericDebug(xsltGenericDebugContext,
972 "xsltApplyOneTemplate: insert == NULL !\n");
975 ctxt->node = oldCurrent;
976 ctxt->inst = oldInst;
980 if (IS_XSLT_ELEM(cur)) {
982 * This is an XSLT node
984 xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->_private;
986 if (IS_XSLT_NAME(cur, "message")) {
987 xsltMessage(ctxt, node, cur);
989 xsltGenericError(xsltGenericDebugContext,
990 "xsltApplyOneTemplate: %s was not compiled\n",
996 if (info->func != NULL) {
997 ctxt->insert = insert;
998 info->func(ctxt, node, cur, info);
999 ctxt->insert = oldInsert;
1003 if (IS_XSLT_NAME(cur, "variable")) {
1004 xsltParseStylesheetVariable(ctxt, cur);
1005 } else if (IS_XSLT_NAME(cur, "param")) {
1006 xsltParseStylesheetParam(ctxt, cur);
1007 } else if (IS_XSLT_NAME(cur, "message")) {
1008 xsltMessage(ctxt, node, cur);
1010 xsltGenericError(xsltGenericDebugContext,
1011 "xsltApplyOneTemplate: problem with xsl:%s\n",
1016 } else if ((cur->type == XML_TEXT_NODE) ||
1017 (cur->type == XML_CDATA_SECTION_NODE)) {
1019 * This text comes from the stylesheet
1020 * For stylesheets, the set of whitespace-preserving
1021 * element names consists of just xsl:text.
1023 #ifdef WITH_XSLT_DEBUG_PROCESS
1024 if (cur->type == XML_CDATA_SECTION_NODE)
1025 xsltGenericDebug(xsltGenericDebugContext,
1026 "xsltApplyOneTemplate: copy CDATA text %s\n",
1028 else if (cur->name == xmlStringTextNoenc)
1029 xsltGenericDebug(xsltGenericDebugContext,
1030 "xsltApplyOneTemplate: copy unescaped text %s\n",
1033 xsltGenericDebug(xsltGenericDebugContext,
1034 "xsltApplyOneTemplate: copy text %s\n", cur->content);
1036 copy = xmlNewText(cur->content);
1038 if ((cur->name == xmlStringTextNoenc) ||
1039 (cur->type == XML_CDATA_SECTION_NODE))
1040 copy->name = xmlStringTextNoenc;
1041 xmlAddChild(insert, copy);
1043 xsltGenericError(xsltGenericErrorContext,
1044 "xsltApplyOneTemplate: text copy failed\n");
1046 } else if ((cur->type == XML_ELEMENT_NODE) &&
1047 (cur->ns != NULL) && (cur->_private != NULL)) {
1048 xsltTransformFunction function;
1050 * Flagged as an extension element
1052 function = (xsltTransformFunction)
1053 xmlHashLookup2(ctxt->extElements, cur->name, cur->ns->href);
1054 if (function == NULL) {
1055 xsltGenericError(xsltGenericErrorContext,
1056 "xsltApplyOneTemplate: failed to find extension %s\n",
1059 #ifdef WITH_XSLT_DEBUG_PROCESS
1060 xsltGenericDebug(xsltGenericDebugContext,
1061 "xsltApplyOneTemplate: extension construct %s\n", cur->name);
1064 ctxt->insert = insert;
1065 function(ctxt, node, cur, cur->_private);
1066 ctxt->insert = oldInsert;
1069 } else if (cur->type == XML_ELEMENT_NODE) {
1070 #ifdef WITH_XSLT_DEBUG_PROCESS
1071 xsltGenericDebug(xsltGenericDebugContext,
1072 "xsltApplyOneTemplate: copy node %s\n", cur->name);
1074 copy = xsltCopyNode(ctxt, cur, insert);
1076 * all the attributes are directly inherited
1078 if (cur->properties != NULL) {
1079 attrs = xsltAttrListTemplateProcess(ctxt, copy,
1085 * Skip to next node, in document order.
1087 if (cur->children != NULL) {
1088 if (cur->children->type != XML_ENTITY_DECL) {
1089 cur = cur->children;
1096 if (cur->next != NULL) {
1103 insert = insert->parent;
1106 if (cur == list->parent) {
1110 if (cur->next != NULL) {
1114 } while (cur != NULL);
1117 ctxt->node = oldCurrent;
1118 ctxt->inst = oldInst;
1122 /************************************************************************
1124 * XSLT-1.1 extensions *
1126 ************************************************************************/
1130 * @ctxt: an XSLT processing context
1131 * @node: The current node
1132 * @inst: the instruction in the stylesheet
1133 * @comp: precomputed informations
1135 * Process an XSLT-1.1 document element
1138 xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
1139 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1140 xsltStylesheetPtr style = NULL;
1142 xmlChar *filename = NULL;
1143 xmlDocPtr result = NULL;
1144 xmlDocPtr oldOutput;
1145 xmlNodePtr oldInsert;
1147 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
1150 if (comp->filename == NULL) {
1151 xmlChar *base = NULL;
1152 xmlChar *URL = NULL;
1153 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
1154 #ifdef WITH_XSLT_DEBUG_EXTRA
1155 xsltGenericDebug(xsltGenericDebugContext,
1156 "Found saxon:output extension\n");
1158 filename = xsltEvalAttrValueTemplate(ctxt, inst,
1159 (const xmlChar *)"file",
1160 XSLT_SAXON_NAMESPACE);
1161 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
1162 #ifdef WITH_XSLT_DEBUG_EXTRA
1163 xsltGenericDebug(xsltGenericDebugContext,
1164 "Found xalan:write extension\n");
1166 filename = xsltEvalAttrValueTemplate(ctxt, inst,
1167 (const xmlChar *)"select",
1168 XSLT_XALAN_NAMESPACE);
1169 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
1170 filename = xsltEvalAttrValueTemplate(ctxt, inst,
1171 (const xmlChar *)"href",
1173 if (filename == NULL) {
1174 #ifdef WITH_XSLT_DEBUG_EXTRA
1175 xsltGenericDebug(xsltGenericDebugContext,
1176 "Found xslt11:document construct\n");
1178 filename = xsltEvalAttrValueTemplate(ctxt, inst,
1179 (const xmlChar *)"href",
1183 #ifdef WITH_XSLT_DEBUG_EXTRA
1184 xsltGenericDebug(xsltGenericDebugContext,
1185 "Found xt:document extension\n");
1190 if (filename == NULL)
1194 * Compute output URL
1196 base = xmlNodeGetBase(inst->doc, inst);
1197 URL = xmlBuildURI(filename, base);
1199 xsltGenericError(xsltGenericErrorContext,
1200 "xsltDocumentElem: URL computation failed %s\n", filename);
1208 filename = xmlStrdup(comp->filename);
1211 oldOutput = ctxt->output;
1212 oldInsert = ctxt->insert;
1214 style = xsltNewStylesheet();
1215 if (style == NULL) {
1216 xsltGenericError(xsltGenericErrorContext,
1217 "xsltDocumentElem: out of memory\n");
1222 * Version described in 1.1 draft allows full parametrization
1225 xsltParseStylesheetOutput(style, inst);
1228 * Create a new document tree and process the element template
1230 result = xmlNewDoc(style->version);
1231 if (result == NULL) {
1232 xsltGenericError(xsltGenericErrorContext,
1233 "xsltDocumentElem: out of memory\n");
1236 ctxt->output = result;
1237 ctxt->insert = (xmlNodePtr) result;
1238 varsPush(ctxt, NULL);
1239 xsltApplyOneTemplate(ctxt, node, inst->children, 0);
1240 xsltFreeStackElemList(varsPop(ctxt));
1245 ret = xsltSaveResultToFilename((const char *) filename,
1248 xsltGenericError(xsltGenericErrorContext,
1249 "xsltDocumentElem: unable to save to %s\n", filename);
1250 #ifdef WITH_XSLT_DEBUG_EXTRA
1252 xsltGenericDebug(xsltGenericDebugContext,
1253 "Wrote %d bytes to %s\n", ret, , filename);
1258 ctxt->output = oldOutput;
1259 ctxt->insert = oldInsert;
1260 if (filename != NULL)
1263 xsltFreeStylesheet(style);
1268 /************************************************************************
1270 * Most of the XSLT-1.0 transformations *
1272 ************************************************************************/
1274 void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node);
1278 * @ctxt: a XSLT process context
1279 * @node: the node in the source tree.
1280 * @inst: the xslt sort node
1281 * @comp: precomputed informations
1283 * function attached to xsl:sort nodes, but this should not be
1287 xsltSort(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
1288 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst ATTRIBUTE_UNUSED,
1289 xsltStylePreCompPtr comp) {
1291 xsltGenericError(xsltGenericErrorContext,
1292 "xsl:sort : compilation failed\n");
1295 xsltGenericError(xsltGenericErrorContext,
1296 "xsl:sort : improper use this should not be reached\n");
1301 * @ctxt: a XSLT process context
1302 * @node: the node in the source tree.
1303 * @inst: the xslt copy node
1304 * @comp: precomputed informations
1306 * Process the xslt copy node on the source node
1309 xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
1310 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1311 xmlNodePtr copy, oldInsert;
1313 oldInsert = ctxt->insert;
1314 if (ctxt->insert != NULL) {
1315 switch (node->type) {
1317 case XML_CDATA_SECTION_NODE:
1319 * This text comes from the stylesheet
1320 * For stylesheets, the set of whitespace-preserving
1321 * element names consists of just xsl:text.
1323 #ifdef WITH_XSLT_DEBUG_PROCESS
1324 if (node->type == XML_CDATA_SECTION_NODE)
1325 xsltGenericDebug(xsltGenericDebugContext,
1326 "xsl:copy: CDATA text %s\n", node->content);
1328 xsltGenericDebug(xsltGenericDebugContext,
1329 "xsl:copy: text %s\n", node->content);
1331 copy = xmlNewText(node->content);
1333 if ((node->name == xmlStringTextNoenc) ||
1334 (node->type == XML_CDATA_SECTION_NODE))
1335 copy->name = xmlStringTextNoenc;
1336 xmlAddChild(ctxt->insert, copy);
1338 xsltGenericError(xsltGenericErrorContext,
1339 "xsl:copy: text copy failed\n");
1342 case XML_DOCUMENT_NODE:
1343 case XML_HTML_DOCUMENT_NODE:
1345 case XML_ELEMENT_NODE:
1346 #ifdef WITH_XSLT_DEBUG_PROCESS
1347 xsltGenericDebug(xsltGenericDebugContext,
1348 "xsl:copy: node %s\n", node->name);
1350 copy = xsltCopyNode(ctxt, node, ctxt->insert);
1351 ctxt->insert = copy;
1352 if (comp->use != NULL) {
1353 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
1356 case XML_ATTRIBUTE_NODE: {
1357 #ifdef WITH_XSLT_DEBUG_PROCESS
1358 xsltGenericDebug(xsltGenericDebugContext,
1359 "xsl:copy: attribute %s\n", node->name);
1361 if (ctxt->insert->type == XML_ELEMENT_NODE) {
1362 xmlAttrPtr attr = (xmlAttrPtr) node, ret = NULL, cur;
1363 if (attr->ns != NULL) {
1364 if ((!xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) &&
1365 (xmlStrncasecmp(attr->ns->prefix,
1366 (xmlChar *)"xml", 3))) {
1367 ret = xmlCopyProp(ctxt->insert, attr);
1368 ret->ns = xsltGetNamespace(ctxt, node, attr->ns,
1372 ret = xmlCopyProp(ctxt->insert, attr);
1374 cur = ctxt->insert->properties;
1376 while (cur->next != NULL)
1381 ctxt->insert->properties = ret;
1386 #ifdef WITH_XSLT_DEBUG_PROCESS
1387 xsltGenericDebug(xsltGenericDebugContext,
1388 "xsl:copy: PI %s\n", node->name);
1390 copy = xmlNewPI(node->name, node->content);
1391 xmlAddChild(ctxt->insert, copy);
1393 case XML_COMMENT_NODE:
1394 #ifdef WITH_XSLT_DEBUG_PROCESS
1395 xsltGenericDebug(xsltGenericDebugContext,
1396 "xsl:copy: comment\n");
1398 copy = xmlNewComment(node->content);
1399 xmlAddChild(ctxt->insert, copy);
1407 switch (node->type) {
1408 case XML_DOCUMENT_NODE:
1409 case XML_HTML_DOCUMENT_NODE:
1410 case XML_ELEMENT_NODE:
1411 varsPush(ctxt, NULL);
1412 xsltApplyOneTemplate(ctxt, ctxt->node, inst->children, 0);
1413 xsltFreeStackElemList(varsPop(ctxt));
1418 ctxt->insert = oldInsert;
1423 * @ctxt: a XSLT process context
1424 * @node: the node in the source tree.
1425 * @inst: the xslt text node
1426 * @comp: precomputed informations
1428 * Process the xslt text node on the source node
1431 xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
1432 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1433 if ((inst->children != NULL) && (comp != NULL)) {
1434 xmlNodePtr text = inst->children;
1437 while (text != NULL) {
1438 if (((text->type != XML_TEXT_NODE) &&
1439 (text->type != XML_CDATA_SECTION_NODE)) ||
1440 (text->next != NULL)) {
1441 xsltGenericError(xsltGenericErrorContext,
1442 "xsl:text content problem\n");
1445 copy = xmlNewDocText(ctxt->output, text->content);
1446 if ((comp->noescape) || (text->type != XML_CDATA_SECTION_NODE)) {
1447 #ifdef WITH_XSLT_DEBUG_PARSING
1448 xsltGenericDebug(xsltGenericDebugContext,
1449 "Disable escaping: %s\n", text->content);
1451 copy->name = xmlStringTextNoenc;
1453 xmlAddChild(ctxt->insert, copy);
1461 * @ctxt: a XSLT process context
1462 * @node: the node in the source tree.
1463 * @inst: the xslt element node
1464 * @comp: precomputed informations
1466 * Process the xslt element node on the source node
1469 xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
1470 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1471 xmlChar *prop = NULL, *attributes = NULL;
1472 xmlChar *ncname = NULL, *name, *namespace;
1473 xmlChar *prefix = NULL;
1474 xmlChar *value = NULL;
1475 xmlNsPtr ns = NULL, oldns = NULL;
1477 xmlNodePtr oldInsert;
1480 if (ctxt->insert == NULL)
1482 if (!comp->has_name) {
1489 oldInsert = ctxt->insert;
1491 if (comp->name == NULL) {
1492 prop = xsltEvalAttrValueTemplate(ctxt, inst,
1493 (const xmlChar *)"name", XSLT_NAMESPACE);
1495 xsltGenericError(xsltGenericErrorContext,
1496 "xsl:element : name is missing\n");
1504 ncname = xmlSplitQName2(name, &prefix);
1505 if (ncname == NULL) {
1511 if ((comp->ns == NULL) && (comp->has_ns)) {
1512 namespace = xsltEvalAttrValueTemplate(ctxt, inst,
1513 (const xmlChar *)"namespace", XSLT_NAMESPACE);
1514 if (namespace != NULL) {
1515 ns = xsltGetSpecialNamespace(ctxt, inst, namespace, prefix,
1519 } else if (comp->ns != NULL) {
1520 ns = xsltGetSpecialNamespace(ctxt, inst, comp->ns, prefix,
1523 if ((ns == NULL) && (prefix != NULL)) {
1524 if (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)) {
1525 #ifdef WITH_XSLT_DEBUG_PARSING
1526 xsltGenericDebug(xsltGenericDebugContext,
1527 "xsl:element : xml prefix forbidden\n");
1531 oldns = xmlSearchNs(inst->doc, inst, prefix);
1532 if (oldns == NULL) {
1533 xsltGenericError(xsltGenericErrorContext,
1534 "xsl:element : no namespace bound to prefix %s\n", prefix);
1536 ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
1540 copy = xmlNewDocNode(ctxt->output, ns, name, NULL);
1542 xsltGenericError(xsltGenericErrorContext,
1543 "xsl:element : creation of %s failed\n", name);
1546 if ((ns == NULL) && (oldns != NULL)) {
1547 /* very specific case xsltGetNamespace failed */
1548 ns = xmlNewNs(copy, oldns->href, oldns->prefix);
1551 xmlAddChild(ctxt->insert, copy);
1552 ctxt->insert = copy;
1553 if (comp->has_use) {
1554 if (comp->use != NULL) {
1555 xsltApplyAttributeSet(ctxt, node, inst, comp->use);
1557 attributes = xsltEvalAttrValueTemplate(ctxt, inst,
1558 (const xmlChar *)"use-attribute-sets", XSLT_NAMESPACE);
1559 if (attributes != NULL) {
1560 xsltApplyAttributeSet(ctxt, node, inst, attributes);
1561 xmlFree(attributes);
1566 varsPush(ctxt, NULL);
1567 xsltApplyOneTemplate(ctxt, ctxt->node, inst->children, 0);
1568 xsltFreeStackElemList(varsPop(ctxt));
1570 ctxt->insert = oldInsert;
1585 * @ctxt: a XSLT process context
1586 * @node: the node in the source tree.
1587 * @inst: the xslt attribute node
1588 * @comp: precomputed informations
1590 * Process the xslt attribute node on the source node
1593 xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
1594 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1595 xmlChar *prop = NULL;
1596 xmlChar *ncname = NULL, *name, *namespace;
1597 xmlChar *prefix = NULL;
1598 xmlChar *value = NULL;
1603 if (ctxt->insert == NULL)
1606 xsltGenericError(xsltGenericErrorContext,
1607 "xsl:attribute : compilation failed\n");
1611 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
1613 if (!comp->has_name) {
1616 if (ctxt->insert->children != NULL) {
1617 xsltGenericError(xsltGenericErrorContext,
1618 "xsl:attribute : node has already children\n");
1621 if (comp->name == NULL) {
1622 prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name",
1625 xsltGenericError(xsltGenericErrorContext,
1626 "xsl:attribute : name is missing\n");
1634 ncname = xmlSplitQName2(name, &prefix);
1635 if (ncname == NULL) {
1640 if (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)) {
1641 #ifdef WITH_XSLT_DEBUG_PARSING
1642 xsltGenericDebug(xsltGenericDebugContext,
1643 "xsl:attribute : xml prefix forbidden\n");
1647 if ((comp->ns == NULL) && (comp->has_ns)) {
1648 namespace = xsltEvalAttrValueTemplate(ctxt, inst,
1649 (const xmlChar *)"namespace", XSLT_NAMESPACE);
1650 if (namespace != NULL) {
1651 ns = xsltGetSpecialNamespace(ctxt, inst, namespace, prefix,
1655 if (prefix != NULL) {
1656 ns = xmlSearchNs(inst->doc, inst, prefix);
1658 xsltGenericError(xsltGenericErrorContext,
1659 "xsl:attribute : no namespace bound to prefix %s\n", prefix);
1661 ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
1665 } else if (comp->ns != NULL) {
1666 ns = xsltGetSpecialNamespace(ctxt, inst, comp->ns, prefix,
1670 value = xsltEvalTemplateString(ctxt, node, inst);
1671 if (value == NULL) {
1673 attr = xmlSetNsProp(ctxt->insert, ns, name,
1674 (const xmlChar *)"");
1676 attr = xmlSetProp(ctxt->insert, name, (const xmlChar *)"");
1679 attr = xmlSetNsProp(ctxt->insert, ns, name, value);
1681 attr = xmlSetProp(ctxt->insert, name, value);
1699 * @ctxt: a XSLT process context
1700 * @node: the node in the source tree.
1701 * @inst: the xslt comment node
1702 * @comp: precomputed informations
1704 * Process the xslt comment node on the source node
1707 xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
1708 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
1709 xmlChar *value = NULL;
1712 value = xsltEvalTemplateString(ctxt, node, inst);
1713 /* TODO: use or generate the compiled form */
1714 /* TODO: check that there is no -- sequence and doesn't end up with - */
1715 #ifdef WITH_XSLT_DEBUG_PROCESS
1717 xsltGenericDebug(xsltGenericDebugContext,
1718 "xsl:comment: empty\n");
1720 xsltGenericDebug(xsltGenericDebugContext,
1721 "xsl:comment: content %s\n", value);
1724 comment = xmlNewComment(value);
1725 xmlAddChild(ctxt->insert, comment);
1732 * xsltProcessingInstruction:
1733 * @ctxt: a XSLT process context
1734 * @node: the node in the source tree.
1735 * @inst: the xslt processing-instruction node
1736 * @comp: precomputed informations
1738 * Process the xslt processing-instruction node on the source node
1741 xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
1742 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1743 xmlChar *ncname = NULL, *name;
1744 xmlChar *value = NULL;
1748 if (ctxt->insert == NULL)
1750 if (comp->has_name == 0)
1752 if (comp->name == NULL) {
1753 ncname = xsltEvalAttrValueTemplate(ctxt, inst,
1754 (const xmlChar *)"name", XSLT_NAMESPACE);
1755 if (ncname == NULL) {
1756 xsltGenericError(xsltGenericErrorContext,
1757 "xsl:processing-instruction : name is missing\n");
1764 /* TODO: check that it's both an an NCName and a PITarget. */
1767 value = xsltEvalTemplateString(ctxt, node, inst);
1768 /* TODO: check that there is no ?> sequence */
1769 #ifdef WITH_XSLT_DEBUG_PROCESS
1771 xsltGenericDebug(xsltGenericDebugContext,
1772 "xsl:processing-instruction: %s empty\n", ncname);
1774 xsltGenericDebug(xsltGenericDebugContext,
1775 "xsl:processing-instruction: %s content %s\n", ncname, value);
1778 pi = xmlNewPI(name, value);
1779 xmlAddChild(ctxt->insert, pi);
1790 * @ctxt: a XSLT process context
1791 * @node: the node in the source tree.
1792 * @inst: the xslt copy-of node
1793 * @comp: precomputed informations
1795 * Process the xslt copy-of node on the source node
1798 xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
1799 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1800 xmlXPathObjectPtr res = NULL;
1801 xmlNodePtr copy = NULL;
1802 xmlNodeSetPtr list = NULL;
1804 int oldProximityPosition, oldContextSize;
1806 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
1808 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
1809 xsltGenericError(xsltGenericErrorContext,
1810 "xsl:copy-of : compilation failed\n");
1814 #ifdef WITH_XSLT_DEBUG_PROCESS
1815 xsltGenericDebug(xsltGenericDebugContext,
1816 "xsltCopyOf: select %s\n", comp->select);
1819 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
1820 oldContextSize = ctxt->xpathCtxt->contextSize;
1821 ctxt->xpathCtxt->node = node;
1822 ctxt->xpathCtxt->namespaces = comp->nsList;
1823 ctxt->xpathCtxt->nsNr = comp->nsNr;
1824 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1825 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
1826 ctxt->xpathCtxt->contextSize = oldContextSize;
1828 if (res->type == XPATH_NODESET) {
1829 #ifdef WITH_XSLT_DEBUG_PROCESS
1830 xsltGenericDebug(xsltGenericDebugContext,
1831 "xsltCopyOf: result is a node set\n");
1833 list = res->nodesetval;
1835 /* sort the list in document order */
1836 xsltDocumentSortFunction(list);
1837 /* append everything in this order under ctxt->insert */
1838 for (i = 0;i < list->nodeNr;i++) {
1839 if (list->nodeTab[i] == NULL)
1841 if ((list->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1842 (list->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) {
1843 xsltCopyTreeList(ctxt, list->nodeTab[i]->children,
1845 } else if (list->nodeTab[i]->type == XML_ATTRIBUTE_NODE) {
1846 xsltCopyProp(ctxt, ctxt->insert,
1847 (xmlAttrPtr) list->nodeTab[i]);
1849 xsltCopyTree(ctxt, list->nodeTab[i], ctxt->insert);
1853 } else if (res->type == XPATH_XSLT_TREE) {
1854 #ifdef WITH_XSLT_DEBUG_PROCESS
1855 xsltGenericDebug(xsltGenericDebugContext,
1856 "xsltCopyOf: result is a result tree fragment\n");
1858 list = res->nodesetval;
1859 if ((list != NULL) && (list->nodeTab != NULL) &&
1860 (list->nodeTab[0] != NULL)) {
1861 xsltCopyTreeList(ctxt, list->nodeTab[0]->children,
1865 /* convert to a string */
1866 res = xmlXPathConvertString(res);
1867 if ((res != NULL) && (res->type == XPATH_STRING)) {
1868 /* append content as text node */
1869 copy = xmlNewText(res->stringval);
1871 xmlAddChild(ctxt->insert, copy);
1875 xsltGenericError(xsltGenericErrorContext,
1876 "xsltCopyOf: text copy failed\n");
1878 #ifdef WITH_XSLT_DEBUG_PROCESS
1880 xsltGenericDebug(xsltGenericDebugContext,
1881 "xsltCopyOf: result %s\n", res->stringval);
1887 xmlXPathFreeObject(res);
1892 * @ctxt: a XSLT process context
1893 * @node: the node in the source tree.
1894 * @inst: the xslt value-of node
1895 * @comp: precomputed informations
1897 * Process the xslt value-of node on the source node
1900 xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
1901 xmlNodePtr inst, xsltStylePreCompPtr comp) {
1902 xmlXPathObjectPtr res = NULL;
1903 xmlNodePtr copy = NULL;
1904 int oldProximityPosition, oldContextSize;
1906 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
1908 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
1909 xsltGenericError(xsltGenericErrorContext,
1910 "xsl:value-of : compilation failed\n");
1914 #ifdef WITH_XSLT_DEBUG_PROCESS
1915 xsltGenericDebug(xsltGenericDebugContext,
1916 "xsltValueOf: select %s\n", comp->select);
1919 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
1920 oldContextSize = ctxt->xpathCtxt->contextSize;
1921 ctxt->xpathCtxt->node = node;
1922 ctxt->xpathCtxt->namespaces = comp->nsList;
1923 ctxt->xpathCtxt->nsNr = comp->nsNr;
1924 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
1925 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
1926 ctxt->xpathCtxt->contextSize = oldContextSize;
1928 if (res->type != XPATH_STRING)
1929 res = xmlXPathConvertString(res);
1930 if (res->type == XPATH_STRING) {
1931 copy = xmlNewText(res->stringval);
1934 copy->name = xmlStringTextNoenc;
1935 xmlAddChild(ctxt->insert, copy);
1940 xsltGenericError(xsltGenericErrorContext,
1941 "xsltValueOf: text copy failed\n");
1943 #ifdef WITH_XSLT_DEBUG_PROCESS
1945 xsltGenericDebug(xsltGenericDebugContext,
1946 "xsltValueOf: result %s\n", res->stringval);
1949 xmlXPathFreeObject(res);
1954 * @ctxt: a XSLT process context
1955 * @node: the node in the source tree.
1956 * @inst: the xslt number node
1957 * @comp: precomputed informations
1959 * Process the xslt number node on the source node
1962 xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
1963 xmlNodePtr inst, xsltStylePreCompPtr comp)
1966 xsltGenericError(xsltGenericErrorContext,
1967 "xsl:number : compilation failed\n");
1971 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
1974 comp->numdata.doc = inst->doc;
1975 comp->numdata.node = inst;
1977 xsltNumberFormat(ctxt, &comp->numdata, node);
1982 * @ctxt: a XSLT process context
1983 * @node: the node in the source tree.
1984 * @inst: the xslt apply-imports node
1985 * @comp: precomputed informations
1987 * Process the xslt apply-imports node on the source node
1990 xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr node,
1991 xmlNodePtr inst ATTRIBUTE_UNUSED, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
1992 xsltTemplatePtr template;
1994 if ((ctxt->templ == NULL) || (ctxt->templ->style == NULL)) {
1995 xsltGenericError(xsltGenericErrorContext,
1996 "xsl:apply-imports : internal error no current template\n");
1999 template = xsltGetTemplate(ctxt, node, ctxt->templ->style);
2000 if (template != NULL) {
2001 templPush(ctxt, template);
2002 varsPush(ctxt, NULL);
2003 xsltApplyOneTemplate(ctxt, node, template->content, 1);
2004 xsltFreeStackElemList(varsPop(ctxt));
2011 * @ctxt: a XSLT process context
2012 * @node: the node in the source tree.
2013 * @inst: the xslt call-template node
2014 * @comp: precomputed informations
2016 * Process the xslt call-template node on the source node
2019 xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
2020 xmlNodePtr inst, xsltStylePreCompPtr comp) {
2021 xmlNodePtr cur = NULL;
2022 xsltStackElemPtr params = NULL, param;
2025 if (ctxt->insert == NULL)
2028 xsltGenericError(xsltGenericErrorContext,
2029 "xsl:call-template : compilation failed\n");
2034 * The template must have been precomputed
2036 if (comp->templ == NULL) {
2037 comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
2038 if (comp->templ == NULL) {
2039 xsltGenericError(xsltGenericErrorContext,
2040 "xsl:call-template : template %s not found\n", comp->name);
2046 * Create a new frame but block access to variables
2048 templPush(ctxt, comp->templ);
2049 cur = inst->children;
2050 while (cur != NULL) {
2051 if (ctxt->state == XSLT_STATE_STOPPED) break;
2052 if (IS_XSLT_ELEM(cur)) {
2053 if (IS_XSLT_NAME(cur, "with-param")) {
2054 param = xsltParseStylesheetCallerParam(ctxt, cur);
2055 if (param != NULL) {
2056 param->next = params;
2060 xsltGenericError(xsltGenericDebugContext,
2061 "xsl:call-template: misplaced xsl:%s\n", cur->name);
2064 xsltGenericError(xsltGenericDebugContext,
2065 "xsl:call-template: misplaced %s element\n", cur->name);
2069 varsPush(ctxt, params);
2070 xsltApplyOneTemplate(ctxt, node, comp->templ->content, 1);
2071 xsltFreeStackElemList(varsPop(ctxt));
2076 * xsltApplyTemplates:
2077 * @ctxt: a XSLT process context
2078 * @node: the node in the source tree.
2079 * @inst: the apply-templates node
2080 * @comp: precomputed informations
2082 * Process the apply-templates node on the source node
2085 xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
2086 xmlNodePtr inst, xsltStylePreCompPtr comp) {
2087 xmlNodePtr cur, delete = NULL, oldNode;
2088 xmlXPathObjectPtr res = NULL;
2089 xmlNodeSetPtr list = NULL, oldList;
2090 int i, oldProximityPosition, oldContextSize;
2091 const xmlChar *oldMode, *oldModeURI;
2092 xsltStackElemPtr params = NULL, param, tmp, p;
2095 xmlNodePtr sorts[XSLT_MAX_SORT];
2096 xmlDocPtr oldXDocPtr, newXDocPtr;
2097 xsltDocumentPtr oldCDocPtr, newCDocPtr;
2100 xsltGenericError(xsltGenericErrorContext,
2101 "xsl:apply-templates : compilation failed\n");
2104 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
2107 #ifdef WITH_XSLT_DEBUG_PROCESS
2108 if ((node != NULL) && (node->name != NULL))
2109 xsltGenericDebug(xsltGenericDebugContext,
2110 "xsltApplyTemplates: node: %s\n", node->name);
2116 oldNode = ctxt->node;
2117 oldMode = ctxt->mode;
2118 oldModeURI = ctxt->modeURI;
2119 ctxt->mode = comp->mode;
2120 ctxt->modeURI = comp->modeURI;
2123 * The xpath context size and proximity position, as
2124 * well as the xpath and context documents, may be changed
2125 * so we save their initial state and will restore on exit
2127 newXDocPtr = oldXDocPtr = ctxt->xpathCtxt->doc;
2128 newCDocPtr = oldCDocPtr = ctxt->document;
2129 oldContextSize = ctxt->xpathCtxt->contextSize;
2130 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2132 if (comp->select != NULL) {
2133 if (comp->comp == NULL) {
2134 xsltGenericError(xsltGenericErrorContext,
2135 "xsl:apply-templates : compilation failed\n");
2138 #ifdef WITH_XSLT_DEBUG_PROCESS
2139 xsltGenericDebug(xsltGenericDebugContext,
2140 "xsltApplyTemplates: select %s\n", comp->select);
2143 ctxt->xpathCtxt->node = node;
2144 ctxt->xpathCtxt->namespaces = comp->nsList;
2145 ctxt->xpathCtxt->nsNr = comp->nsNr;
2146 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
2147 ctxt->xpathCtxt->contextSize = oldContextSize;
2148 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2150 if (res->type == XPATH_NODESET) {
2151 list = res->nodesetval;
2152 /* For a 'select' nodeset, need to check if document has changed */
2153 if ( (res->nodesetval!=NULL) &&
2154 (res->nodesetval->nodeTab!=NULL) &&
2155 (res->nodesetval->nodeTab[0]->doc!=NULL) &&
2156 (res->nodesetval->nodeTab[0]->doc->doc!=NULL) &&
2157 (res->nodesetval->nodeTab[0]->doc->doc)!=ctxt->xpathCtxt->doc) {
2158 newXDocPtr=res->nodesetval->nodeTab[0]->doc->doc;
2159 /* The nodeset is from another document, so must change */
2160 if ((newCDocPtr = xsltFindDocument(ctxt,newXDocPtr))==NULL) {
2161 xsltGenericError(xsltGenericErrorContext,
2162 "xsl:apply-templates : can't find doc\n");
2165 /* Can't actually do the change yet, so set flag for later */
2168 res->nodesetval = NULL;
2174 #ifdef WITH_XSLT_DEBUG_PROCESS
2175 xsltGenericDebug(xsltGenericDebugContext,
2176 "xsltApplyTemplates: select didn't evaluate to a node list\n");
2182 * Build an XPath nodelist with the children
2184 list = xmlXPathNodeSetCreate(NULL);
2185 cur = node->children;
2186 while (cur != NULL) {
2187 switch (cur->type) {
2189 if ((IS_BLANK_NODE(cur)) &&
2190 (cur->parent != NULL) &&
2191 (ctxt->style->stripSpaces != NULL)) {
2194 val = (const xmlChar *)
2195 xmlHashLookup(ctxt->style->stripSpaces,
2197 if ((val != NULL) &&
2198 (xmlStrEqual(val, (xmlChar *) "strip"))) {
2203 /* no break on purpose */
2204 case XML_DOCUMENT_NODE:
2205 case XML_HTML_DOCUMENT_NODE:
2206 case XML_ELEMENT_NODE:
2207 case XML_CDATA_SECTION_NODE:
2209 case XML_COMMENT_NODE:
2210 xmlXPathNodeSetAdd(list, cur);
2213 #ifdef WITH_XSLT_DEBUG_PROCESS
2214 xsltGenericDebug(xsltGenericDebugContext,
2215 "xsltApplyTemplates: skipping cur type %d\n",
2221 if (delete != NULL) {
2222 #ifdef WITH_XSLT_DEBUG_PROCESS
2223 xsltGenericDebug(xsltGenericDebugContext,
2224 "xsltApplyTemplates: removing ignorable blank cur\n");
2226 xmlUnlinkNode(delete);
2227 xmlFreeNode(delete);
2233 #ifdef WITH_XSLT_DEBUG_PROCESS
2235 xsltGenericDebug(xsltGenericDebugContext,
2236 "xsltApplyTemplates: list of %d nodes\n", list->nodeNr);
2239 oldList = ctxt->nodeList;
2240 ctxt->nodeList = list;
2241 ctxt->xpathCtxt->contextSize = list->nodeNr;
2244 * handle (or skip) the xsl:sort and xsl:with-param
2246 cur = inst->children;
2248 if (ctxt->state == XSLT_STATE_STOPPED) break;
2249 if (IS_XSLT_ELEM(cur)) {
2250 if (IS_XSLT_NAME(cur, "with-param")) {
2251 param = xsltParseStylesheetCallerParam(ctxt, cur);
2252 if (param != NULL) {
2253 param->next = params;
2256 } else if (IS_XSLT_NAME(cur, "sort")) {
2257 if (nbsorts >= XSLT_MAX_SORT) {
2258 xsltGenericError(xsltGenericDebugContext,
2259 "xsl:call-template: %s too many sort\n", node->name);
2261 sorts[nbsorts++] = cur;
2264 xsltGenericError(xsltGenericDebugContext,
2265 "xsl:call-template: misplaced xsl:%s\n", cur->name);
2268 xsltGenericError(xsltGenericDebugContext,
2269 "xsl:call-template: misplaced %s element\n", cur->name);
2275 xsltDoSortFunction(ctxt, sorts, nbsorts);
2279 /* The original 'select' may have required a change of document*/
2281 #ifdef WITH_XSLT_DEBUG_PROCESS
2282 xsltGenericDebug(xsltGenericDebugContext,
2283 "xsltApplyTemplates: Changing document - context doc %s, xpathdoc %s\n",
2284 newCDocPtr->doc->URL, newXDocPtr->URL);
2287 ctxt->document = newCDocPtr;
2288 ctxt->xpathCtxt->doc = newXDocPtr;
2289 ctxt->xpathCtxt->node = list->nodeTab[0];
2292 for (i = 0;i < list->nodeNr;i++) {
2293 ctxt->node = list->nodeTab[i];
2294 ctxt->xpathCtxt->proximityPosition = i + 1;
2295 varsPush(ctxt, params);
2296 xsltProcessOneNode(ctxt, list->nodeTab[i]);
2297 tmp = varsPop(ctxt);
2299 * Free other parameter and variables which may have been
2300 * added to the set defined in the caller.
2302 if (params == NULL) {
2303 xsltFreeStackElemList(tmp);
2304 } else if (tmp != params) {
2306 while ((p != NULL) && (p->next != params))
2309 xsltFreeStackElemList(tmp);
2312 xsltFreeStackElemList(tmp);
2316 xsltFreeStackElemList(params); /* free the parameter list */
2317 ctxt->nodeList = oldList;
2318 ctxt->xpathCtxt->contextSize = oldContextSize;
2319 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2320 ctxt->xpathCtxt->doc = oldXDocPtr;
2321 ctxt->document = oldCDocPtr;
2324 ctxt->node = oldNode;
2325 ctxt->mode = oldMode;
2326 ctxt->modeURI = oldModeURI;
2328 xmlXPathFreeObject(res);
2330 xmlXPathFreeNodeSet(list);
2336 * @ctxt: a XSLT process context
2337 * @node: the node in the source tree.
2338 * @inst: the xslt choose node
2339 * @comp: precomputed informations
2341 * Process the xslt choose node on the source node
2344 xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node,
2345 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
2346 xmlChar *prop = NULL;
2347 xmlXPathObjectPtr res = NULL;
2348 xmlNodePtr replacement, when;
2350 int oldProximityPosition, oldContextSize;
2352 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
2358 replacement = inst->children;
2359 if (replacement == NULL) {
2360 xsltGenericError(xsltGenericErrorContext,
2361 "xsl:choose: empty content not allowed\n");
2364 if ((!IS_XSLT_ELEM(replacement)) ||
2365 (!IS_XSLT_NAME(replacement, "when"))) {
2366 xsltGenericError(xsltGenericErrorContext,
2367 "xsl:choose: xsl:when expected first\n");
2370 while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "when"))) {
2371 xsltStylePreCompPtr wcomp = replacement->_private;
2373 if ((wcomp == NULL) || (wcomp->test == NULL) || (wcomp->comp == NULL)) {
2374 xsltGenericError(xsltGenericErrorContext,
2375 "xsl:when: compilation failed !\n");
2379 #ifdef WITH_XSLT_DEBUG_PROCESS
2380 xsltGenericDebug(xsltGenericDebugContext,
2381 "xsl:when: test %s\n", wcomp->test);
2384 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2385 oldContextSize = ctxt->xpathCtxt->contextSize;
2386 ctxt->xpathCtxt->node = node;
2387 ctxt->xpathCtxt->namespaces = comp->nsList;
2388 ctxt->xpathCtxt->nsNr = comp->nsNr;
2389 res = xmlXPathCompiledEval(wcomp->comp, ctxt->xpathCtxt);
2390 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2391 ctxt->xpathCtxt->contextSize = oldContextSize;
2393 if (res->type != XPATH_BOOLEAN)
2394 res = xmlXPathConvertBoolean(res);
2395 if (res->type == XPATH_BOOLEAN)
2396 doit = res->boolval;
2398 #ifdef WITH_XSLT_DEBUG_PROCESS
2399 xsltGenericDebug(xsltGenericDebugContext,
2400 "xsl:when: test didn't evaluate to a boolean\n");
2406 #ifdef WITH_XSLT_DEBUG_PROCESS
2407 xsltGenericDebug(xsltGenericDebugContext,
2408 "xsl:when: test evaluate to %d\n", doit);
2411 varsPush(ctxt, NULL);
2412 xsltApplyOneTemplate(ctxt, ctxt->node, when->children, 0);
2413 xsltFreeStackElemList(varsPop(ctxt));
2420 xmlXPathFreeObject(res);
2422 replacement = replacement->next;
2424 if (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "otherwise"))) {
2425 varsPush(ctxt, NULL);
2426 xsltApplyOneTemplate(ctxt, ctxt->node, replacement->children, 0);
2427 xsltFreeStackElemList(varsPop(ctxt));
2428 replacement = replacement->next;
2430 if (replacement != NULL) {
2431 xsltGenericError(xsltGenericErrorContext,
2432 "xsl:choose: unexpected content %s\n", replacement->name);
2441 xmlXPathFreeObject(res);
2446 * @ctxt: a XSLT process context
2447 * @node: the node in the source tree.
2448 * @inst: the xslt if node
2449 * @comp: precomputed informations
2451 * Process the xslt if node on the source node
2454 xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
2455 xmlNodePtr inst, xsltStylePreCompPtr comp) {
2456 xmlXPathObjectPtr res = NULL;
2458 int oldContextSize, oldProximityPosition;
2460 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
2462 if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
2463 xsltGenericError(xsltGenericErrorContext,
2464 "xsl:if : compilation failed\n");
2468 #ifdef WITH_XSLT_DEBUG_PROCESS
2469 xsltGenericDebug(xsltGenericDebugContext,
2470 "xsltIf: test %s\n", comp->test);
2473 oldContextSize = ctxt->xpathCtxt->contextSize;
2474 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2475 ctxt->xpathCtxt->node = node;
2476 ctxt->xpathCtxt->namespaces = comp->nsList;
2477 ctxt->xpathCtxt->nsNr = comp->nsNr;
2478 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
2479 ctxt->xpathCtxt->contextSize = oldContextSize;
2480 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2482 if (res->type != XPATH_BOOLEAN)
2483 res = xmlXPathConvertBoolean(res);
2484 if (res->type == XPATH_BOOLEAN)
2485 doit = res->boolval;
2487 #ifdef WITH_XSLT_DEBUG_PROCESS
2488 xsltGenericDebug(xsltGenericDebugContext,
2489 "xsltIf: test didn't evaluate to a boolean\n");
2495 #ifdef WITH_XSLT_DEBUG_PROCESS
2496 xsltGenericDebug(xsltGenericDebugContext,
2497 "xsltIf: test evaluate to %d\n", doit);
2500 varsPush(ctxt, NULL);
2501 xsltApplyOneTemplate(ctxt, node, inst->children, 0);
2502 xsltFreeStackElemList(varsPop(ctxt));
2507 xmlXPathFreeObject(res);
2512 * @ctxt: a XSLT process context
2513 * @node: the node in the source tree.
2514 * @inst: the xslt for-each node
2515 * @comp: precomputed informations
2517 * Process the xslt for-each node on the source node
2520 xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
2521 xmlNodePtr inst, xsltStylePreCompPtr comp) {
2522 xmlXPathObjectPtr res = NULL;
2523 xmlNodePtr replacement;
2524 xmlNodeSetPtr list = NULL, oldList;
2525 int i, oldProximityPosition, oldContextSize;
2526 xmlNodePtr oldNode = ctxt->node;
2528 xmlNodePtr sorts[XSLT_MAX_SORT];
2529 xmlDocPtr oldXDocPtr, newXDocPtr;
2530 xsltDocumentPtr oldCDocPtr, newCDocPtr;
2532 if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
2534 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
2535 xsltGenericError(xsltGenericErrorContext,
2536 "xsl:for-each : compilation failed\n");
2540 #ifdef WITH_XSLT_DEBUG_PROCESS
2541 xsltGenericDebug(xsltGenericDebugContext,
2542 "xsltForEach: select %s\n", comp->select);
2545 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2546 oldContextSize = ctxt->xpathCtxt->contextSize;
2547 ctxt->xpathCtxt->node = node;
2548 ctxt->xpathCtxt->namespaces = comp->nsList;
2549 ctxt->xpathCtxt->nsNr = comp->nsNr;
2550 oldCDocPtr = ctxt->document;
2551 oldXDocPtr = ctxt->xpathCtxt->doc;
2552 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
2553 ctxt->xpathCtxt->contextSize = oldContextSize;
2554 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2556 if (res->type == XPATH_NODESET)
2557 list = res->nodesetval;
2560 #ifdef WITH_XSLT_DEBUG_PROCESS
2561 xsltGenericDebug(xsltGenericDebugContext,
2562 "xsltForEach: select didn't evaluate to a node list\n");
2567 #ifdef WITH_XSLT_DEBUG_PROCESS
2568 xsltGenericDebug(xsltGenericDebugContext,
2569 "xsltForEach: select evaluates to %d nodes\n", list->nodeNr);
2572 oldList = ctxt->nodeList;
2573 ctxt->nodeList = list;
2574 oldContextSize = ctxt->xpathCtxt->contextSize;
2575 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
2576 ctxt->xpathCtxt->contextSize = list->nodeNr;
2578 /* For a 'select' nodeset, need to check if document has changed */
2579 if (list->nodeTab!=NULL) {
2580 if ( (res->nodesetval!=NULL) &&
2581 (res->nodesetval->nodeTab!=NULL) &&
2582 (res->nodesetval->nodeTab[0]->doc!=NULL) &&
2583 (res->nodesetval->nodeTab[0]->doc->doc!=NULL) &&
2584 (res->nodesetval->nodeTab[0]->doc->doc)!=ctxt->xpathCtxt->doc) {
2585 newXDocPtr=res->nodesetval->nodeTab[0]->doc->doc;
2586 /* The nodeset is from another document, so must change */
2587 if ((newCDocPtr = xsltFindDocument(ctxt,newXDocPtr))==NULL) {
2588 xsltGenericError(xsltGenericErrorContext,
2589 "xsl:for-each : can't find document\n");
2592 ctxt->document = newCDocPtr;
2593 ctxt->xpathCtxt->doc = newXDocPtr;
2594 ctxt->xpathCtxt->node = list->nodeTab[0];
2595 ctxt->xpathCtxt->contextSize = list->nodeNr;
2596 ctxt->xpathCtxt->proximityPosition = 0;
2601 * handle and skip the xsl:sort
2603 replacement = inst->children;
2604 while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "sort"))) {
2605 if (nbsorts >= XSLT_MAX_SORT) {
2606 xsltGenericError(xsltGenericDebugContext,
2607 "xsl:for-each: too many sort\n");
2609 sorts[nbsorts++] = replacement;
2611 replacement = replacement->next;
2615 xsltDoSortFunction(ctxt, sorts, nbsorts);
2619 for (i = 0;i < list->nodeNr;i++) {
2620 ctxt->node = list->nodeTab[i];
2621 ctxt->xpathCtxt->proximityPosition = i + 1;
2622 /* ctxt->insert = oldInsert; */
2623 varsPush(ctxt, NULL);
2624 xsltApplyOneTemplate(ctxt, list->nodeTab[i], replacement, 0);
2625 xsltFreeStackElemList(varsPop(ctxt));
2627 ctxt->document = oldCDocPtr;
2628 ctxt->nodeList = oldList;
2629 ctxt->node = oldNode;
2630 ctxt->xpathCtxt->doc = oldXDocPtr;
2631 ctxt->xpathCtxt->contextSize = oldContextSize;
2632 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
2636 xmlXPathFreeObject(res);
2639 /************************************************************************
2641 * Generic interface *
2643 ************************************************************************/
2645 #ifdef XSLT_GENERATE_HTML_DOCTYPE
2646 typedef struct xsltHTMLVersion {
2647 const char *version;
2652 static xsltHTMLVersion xsltHTMLVersions[] = {
2653 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
2654 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
2655 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
2656 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
2657 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
2658 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
2659 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
2660 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
2661 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
2662 "http://www.w3.org/TR/html4/strict.dtd"},
2663 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
2664 "http://www.w3.org/TR/html4/loose.dtd"},
2665 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
2666 "http://www.w3.org/TR/html4/frameset.dtd"},
2667 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
2668 "http://www.w3.org/TR/html4/loose.dtd"},
2669 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
2674 * @version: the version string
2675 * @public: used to return the public ID
2676 * @system: used to return the system ID
2678 * Returns -1 if not found, 0 otherwise and the system and public
2679 * Identifier for this given verion of HTML
2682 xsltGetHTMLIDs(const xmlChar *version, const xmlChar **public,
2683 const xmlChar **system) {
2685 if (version == NULL)
2687 for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
2689 if (!xmlStrcasecmp(version,
2690 (const xmlChar *) xsltHTMLVersions[i].version)) {
2692 *public = (const xmlChar *) xsltHTMLVersions[i].public;
2694 *system = (const xmlChar *) xsltHTMLVersions[i].system;
2703 * xsltApplyStylesheet:
2704 * @style: a parsed XSLT stylesheet
2705 * @doc: a parsed XML document
2706 * @params: a NULL terminated arry of parameters names/values tuples
2708 * Apply the stylesheet to the document
2709 * NOTE: This may lead to a non-wellformed output XML wise !
2711 * Returns the result document or NULL in case of error
2714 xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
2715 const char **params) {
2716 xmlDocPtr res = NULL;
2717 xsltTransformContextPtr ctxt = NULL;
2719 const xmlChar *method;
2720 const xmlChar *doctypePublic;
2721 const xmlChar *doctypeSystem;
2722 const xmlChar *version;
2723 xsltStackElemPtr variables;
2724 xsltStackElemPtr vptr;
2727 if ((style == NULL) || (doc == NULL))
2729 ctxt = xsltNewTransformContext(style, doc);
2730 xsltRegisterExtras(ctxt);
2734 XSLT_GET_IMPORT_PTR(method, style, method)
2735 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
2736 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
2737 XSLT_GET_IMPORT_PTR(version, style, version)
2739 if ((method != NULL) &&
2740 (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
2741 if (xmlStrEqual(method, (const xmlChar *) "html")) {
2742 ctxt->type = XSLT_OUTPUT_HTML;
2743 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
2744 res = htmlNewDoc(doctypeSystem, doctypePublic);
2746 if (version == NULL)
2747 version = (const xmlChar *) "4.0";
2748 #ifdef XSLT_GENERATE_HTML_DOCTYPE
2749 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
2751 res = htmlNewDoc(doctypeSystem, doctypePublic);
2755 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
2756 xsltGenericError(xsltGenericErrorContext,
2757 "xsltApplyStylesheet: unsupported method xhtml, using html\n",
2759 ctxt->type = XSLT_OUTPUT_HTML;
2760 res = htmlNewDoc(doctypeSystem, doctypePublic);
2763 } else if (xmlStrEqual(style->method, (const xmlChar *) "text")) {
2764 ctxt->type = XSLT_OUTPUT_TEXT;
2765 res = xmlNewDoc(style->version);
2769 xsltGenericError(xsltGenericErrorContext,
2770 "xsltApplyStylesheet: unsupported method %s\n",
2775 ctxt->type = XSLT_OUTPUT_XML;
2776 res = xmlNewDoc(style->version);
2780 res->charset = XML_CHAR_ENCODING_UTF8;
2781 if (style->encoding != NULL)
2782 res->encoding = xmlStrdup(style->encoding);
2783 variables = style->variables;
2786 * Start the evaluation, evaluate the params, the stylesheets globals
2787 * and start by processing the top node.
2790 ctxt->insert = (xmlNodePtr) res;
2791 ctxt->globalVars = xmlHashCreate(20);
2793 xsltEvalUserParams(ctxt, params);
2794 xsltEvalGlobalVariables(ctxt);
2795 ctxt->node = (xmlNodePtr) doc;
2796 varsPush(ctxt, NULL);
2797 xsltProcessOneNode(ctxt, ctxt->node);
2798 xsltFreeStackElemList(varsPop(ctxt));
2800 xsltCleanupTemplates(style); /* TODO: <- style should be read only */
2803 * Now cleanup our variables so stylesheet can be re-used
2805 * TODO: this is not needed anymore global variables are copied
2806 * and not evaluated directly anymore, keep this as a check
2808 if (style->variables != variables) {
2809 vptr = style->variables;
2810 while (vptr->next!=variables)
2813 xsltFreeStackElemList(style->variables);
2814 style->variables = variables;
2816 vptr = style->variables;
2818 if (vptr->computed) {
2819 if (vptr->value != NULL) {
2820 xmlXPathFreeObject(vptr->value);
2830 * Do some post processing work depending on the generated output
2832 root = xmlDocGetRootElement(res);
2835 * Apply the default selection of the method
2837 if ((method == NULL) &&
2838 (root->ns == NULL) &&
2839 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
2841 tmp = res->children;
2842 while ((tmp != NULL) && (tmp != root)) {
2843 if (tmp->type == XML_ELEMENT_NODE)
2845 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
2849 ctxt->type = XSLT_OUTPUT_HTML;
2850 res->type = XML_HTML_DOCUMENT_NODE;
2851 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
2852 res->intSubset = xmlCreateIntSubset(res, root->name,
2853 doctypePublic, doctypeSystem);
2854 #ifdef XSLT_GENERATE_HTML_DOCTYPE
2856 if (version == NULL)
2857 version = (const xmlChar *) "4.0";
2858 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
2859 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
2860 res->intSubset = xmlCreateIntSubset(res, root->name,
2861 doctypePublic, doctypeSystem);
2867 if (ctxt->type == XSLT_OUTPUT_XML) {
2868 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
2869 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
2870 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
2871 res->intSubset = xmlCreateIntSubset(res, root->name,
2872 doctypePublic, doctypeSystem);
2875 xmlXPathFreeNodeSet(ctxt->nodeList);
2876 xsltFreeTransformContext(ctxt);
2883 xsltFreeTransformContext(ctxt);